]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOMapper.cpp
xnu-6153.61.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
CommitLineData
55e303ae 1/*
39037602 2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
55e303ae 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
55e303ae
A
27 */
28#include <IOKit/IOLib.h>
29#include <IOKit/IOMapper.h>
b0d623f7 30#include <IOKit/IODMACommand.h>
55e303ae 31#include <libkern/c++/OSData.h>
99c3a104 32#include <libkern/OSDebug.h>
5ba3f43e 33#include <mach_debug/zone_info.h>
3e170ce0 34#include "IOKitKernelInternal.h"
55e303ae 35
0c530ab8
A
36__BEGIN_DECLS
37extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
38__END_DECLS
39
55e303ae
A
40#define super IOService
41OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
42
3e170ce0
A
43OSMetaClassDefineReservedUnused(IOMapper, 0);
44OSMetaClassDefineReservedUnused(IOMapper, 1);
45OSMetaClassDefineReservedUnused(IOMapper, 2);
46OSMetaClassDefineReservedUnused(IOMapper, 3);
55e303ae
A
47OSMetaClassDefineReservedUnused(IOMapper, 4);
48OSMetaClassDefineReservedUnused(IOMapper, 5);
49OSMetaClassDefineReservedUnused(IOMapper, 6);
50OSMetaClassDefineReservedUnused(IOMapper, 7);
51OSMetaClassDefineReservedUnused(IOMapper, 8);
52OSMetaClassDefineReservedUnused(IOMapper, 9);
53OSMetaClassDefineReservedUnused(IOMapper, 10);
54OSMetaClassDefineReservedUnused(IOMapper, 11);
55OSMetaClassDefineReservedUnused(IOMapper, 12);
56OSMetaClassDefineReservedUnused(IOMapper, 13);
57OSMetaClassDefineReservedUnused(IOMapper, 14);
58OSMetaClassDefineReservedUnused(IOMapper, 15);
59
60IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
61
62class IOMapperLock {
0a7de745 63 IOLock *fWaitLock;
55e303ae 64public:
0a7de745
A
65 IOMapperLock()
66 {
67 fWaitLock = IOLockAlloc();
68 }
69 ~IOMapperLock()
70 {
71 IOLockFree(fWaitLock);
72 }
73
74 void
75 lock()
76 {
77 IOLockLock(fWaitLock);
78 }
79 void
80 unlock()
81 {
82 IOLockUnlock(fWaitLock);
83 }
84 void
85 sleep(void *event)
86 {
87 IOLockSleep(fWaitLock, event, THREAD_UNINT);
88 }
89 void
90 wakeup(void *event)
91 {
92 IOLockWakeup(fWaitLock, event, false);
93 }
55e303ae
A
94};
95
96static IOMapperLock sMapperLock;
97
0a7de745
A
98bool
99IOMapper::start(IOService *provider)
55e303ae 100{
0a7de745
A
101 OSObject * obj;
102 if (!super::start(provider)) {
103 return false;
104 }
105
106 if (!initHardware(provider)) {
107 return false;
108 }
109
110 fPageSize = getPageSize();
111
112 if (fIsSystem) {
113 sMapperLock.lock();
114 IOMapper::gSystem = this;
115 sMapperLock.wakeup(&IOMapper::gSystem);
116 sMapperLock.unlock();
117 }
118
119 if (provider) {
120 obj = provider->getProperty("iommu-id");
121 if (!obj) {
122 obj = provider->getProperty("AAPL,phandle");
123 }
124 if (obj) {
125 setProperty(gIOMapperIDKey, obj);
126 }
127 }
128 return true;
55e303ae
A
129}
130
0a7de745
A
131void
132IOMapper::free()
55e303ae 133{
0a7de745 134 super::free();
55e303ae
A
135}
136
0a7de745
A
137void
138IOMapper::setMapperRequired(bool hasMapper)
55e303ae 139{
0a7de745
A
140 if (hasMapper) {
141 IOMapper::gSystem = (IOMapper *) kHasMapper;
142 } else {
143 sMapperLock.lock();
144 IOMapper::gSystem = (IOMapper *) kNoMapper;
145 sMapperLock.unlock();
146 sMapperLock.wakeup(&IOMapper::gSystem);
147 }
55e303ae
A
148}
149
0a7de745
A
150void
151IOMapper::waitForSystemMapper()
55e303ae 152{
0a7de745
A
153 sMapperLock.lock();
154 while ((uintptr_t) IOMapper::gSystem & kWaitMask) {
99c3a104 155 OSReportWithBacktrace("waitForSystemMapper");
0a7de745
A
156 sMapperLock.sleep(&IOMapper::gSystem);
157 }
158 sMapperLock.unlock();
55e303ae
A
159}
160
0a7de745
A
161IOMapper *
162IOMapper::copyMapperForDevice(IOService * device)
b0d623f7 163{
0a7de745 164 return copyMapperForDeviceWithIndex(device, 0);
39236c6e
A
165}
166
0a7de745
A
167IOMapper *
168IOMapper::copyMapperForDeviceWithIndex(IOService * device, unsigned int index)
39236c6e 169{
0a7de745
A
170 OSData *data;
171 OSObject * obj;
172 IOMapper * mapper = NULL;
173 OSDictionary * matching;
174
175 obj = device->copyProperty("iommu-parent");
176 if (!obj) {
177 return NULL;
178 }
179
180 if ((mapper = OSDynamicCast(IOMapper, obj))) {
181 goto found;
182 }
183
184 if ((data = OSDynamicCast(OSData, obj))) {
185 if (index >= data->getLength() / sizeof(UInt32)) {
186 goto done;
187 }
188
189 data = OSData::withBytesNoCopy((UInt32 *)data->getBytesNoCopy() + index, sizeof(UInt32));
190 if (!data) {
191 goto done;
192 }
193
194 matching = IOService::propertyMatching(gIOMapperIDKey, data);
195 data->release();
196 } else {
197 matching = IOService::propertyMatching(gIOMapperIDKey, obj);
198 }
199
200 if (matching) {
201 mapper = OSDynamicCast(IOMapper, IOService::waitForMatchingService(matching));
202 matching->release();
203 }
39236c6e
A
204
205done:
0a7de745
A
206 if (obj) {
207 obj->release();
208 }
5ba3f43e 209found:
0a7de745
A
210 if (mapper) {
211 if (!mapper->fAllocName) {
212 char name[MACH_ZONE_NAME_MAX_LEN];
213 char kmodname[KMOD_MAX_NAME];
214 vm_tag_t tag;
215 uint32_t kmodid;
216
217 tag = IOMemoryTag(kernel_map);
218 if (!(kmodid = vm_tag_get_kext(tag, &kmodname[0], KMOD_MAX_NAME))) {
219 snprintf(kmodname, sizeof(kmodname), "%d", tag);
220 }
221 snprintf(name, sizeof(name), "%s.DMA.%s", kmodname, device->getName());
222 mapper->fAllocName = kern_allocation_name_allocate(name, 16);
223 }
224 }
225
226 return mapper;
b0d623f7
A
227}
228
55e303ae
A
229__BEGIN_DECLS
230
231// These are C accessors to the system mapper for non-IOKit clients
0a7de745
A
232ppnum_t
233IOMapperIOVMAlloc(unsigned pages)
55e303ae 234{
0a7de745
A
235 IOReturn ret;
236 uint64_t dmaAddress, dmaLength;
237
238 IOMapper::checkForSystemMapper();
239
240 ret = kIOReturnUnsupported;
241 if (IOMapper::gSystem) {
242 ret = IOMapper::gSystem->iovmMapMemory(
243 NULL, 0, ptoa_64(pages),
244 (kIODMAMapReadAccess | kIODMAMapWriteAccess),
245 NULL, NULL, NULL,
246 &dmaAddress, &dmaLength);
247 }
248
249 if (kIOReturnSuccess == ret) {
250 return atop_64(dmaAddress);
251 }
252 return 0;
55e303ae
A
253}
254
0a7de745
A
255void
256IOMapperIOVMFree(ppnum_t addr, unsigned pages)
55e303ae 257{
0a7de745
A
258 if (IOMapper::gSystem) {
259 IOMapper::gSystem->iovmUnmapMemory(NULL, NULL, ptoa_64(addr), ptoa_64(pages));
260 }
55e303ae
A
261}
262
0a7de745
A
263ppnum_t
264IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page)
55e303ae 265{
0a7de745
A
266 if (!IOMapper::gSystem) {
267 return page;
268 }
269 if (!addr) {
270 panic("!addr");
271 }
272 IOMapper::gSystem->iovmInsert((kIODMAMapReadAccess | kIODMAMapWriteAccess),
273 ptoa_64(addr), ptoa_64(offset), ptoa_64(page), ptoa_64(1));
274 return addr + offset;
55e303ae
A
275}
276
277/////////////////////////////////////////////////////////////////////////////
278//
279//
280// IOLib.h APIs
281//
282//
283/////////////////////////////////////////////////////////////////////////////
284
285#include <machine/machine_routines.h>
286
0a7de745
A
287UInt8
288IOMappedRead8(IOPhysicalAddress address)
55e303ae 289{
0a7de745
A
290 IOMapper::checkForSystemMapper();
291
292 if (IOMapper::gSystem) {
293 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
294 return (UInt8) ml_phys_read_byte_64(addr);
295 } else {
296 return (UInt8) ml_phys_read_byte((vm_offset_t) address);
297 }
55e303ae
A
298}
299
0a7de745
A
300UInt16
301IOMappedRead16(IOPhysicalAddress address)
55e303ae 302{
0a7de745
A
303 IOMapper::checkForSystemMapper();
304
305 if (IOMapper::gSystem) {
306 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
307 return (UInt16) ml_phys_read_half_64(addr);
308 } else {
309 return (UInt16) ml_phys_read_half((vm_offset_t) address);
310 }
55e303ae
A
311}
312
0a7de745
A
313UInt32
314IOMappedRead32(IOPhysicalAddress address)
55e303ae 315{
0a7de745
A
316 IOMapper::checkForSystemMapper();
317
318 if (IOMapper::gSystem) {
319 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
320 return (UInt32) ml_phys_read_word_64(addr);
321 } else {
322 return (UInt32) ml_phys_read_word((vm_offset_t) address);
323 }
55e303ae
A
324}
325
0a7de745
A
326UInt64
327IOMappedRead64(IOPhysicalAddress address)
55e303ae 328{
0a7de745
A
329 IOMapper::checkForSystemMapper();
330
331 if (IOMapper::gSystem) {
332 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
333 return (UInt64) ml_phys_read_double_64(addr);
334 } else {
335 return (UInt64) ml_phys_read_double((vm_offset_t) address);
336 }
55e303ae
A
337}
338
0a7de745
A
339void
340IOMappedWrite8(IOPhysicalAddress address, UInt8 value)
55e303ae 341{
0a7de745
A
342 IOMapper::checkForSystemMapper();
343
344 if (IOMapper::gSystem) {
345 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
346 ml_phys_write_byte_64(addr, value);
347 } else {
348 ml_phys_write_byte((vm_offset_t) address, value);
349 }
55e303ae
A
350}
351
0a7de745
A
352void
353IOMappedWrite16(IOPhysicalAddress address, UInt16 value)
55e303ae 354{
0a7de745
A
355 IOMapper::checkForSystemMapper();
356
357 if (IOMapper::gSystem) {
358 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
359 ml_phys_write_half_64(addr, value);
360 } else {
361 ml_phys_write_half((vm_offset_t) address, value);
362 }
55e303ae
A
363}
364
0a7de745
A
365void
366IOMappedWrite32(IOPhysicalAddress address, UInt32 value)
55e303ae 367{
0a7de745
A
368 IOMapper::checkForSystemMapper();
369
370 if (IOMapper::gSystem) {
371 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
372 ml_phys_write_word_64(addr, value);
373 } else {
374 ml_phys_write_word((vm_offset_t) address, value);
375 }
55e303ae
A
376}
377
0a7de745
A
378void
379IOMappedWrite64(IOPhysicalAddress address, UInt64 value)
55e303ae 380{
0a7de745
A
381 IOMapper::checkForSystemMapper();
382
383 if (IOMapper::gSystem) {
384 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
385 ml_phys_write_double_64(addr, value);
386 } else {
387 ml_phys_write_double((vm_offset_t) address, value);
388 }
55e303ae
A
389}
390
391__END_DECLS