]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMapper.cpp
xnu-4903.270.47.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
1 /*
2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <IOKit/IOLib.h>
29 #include <IOKit/IOMapper.h>
30 #include <IOKit/IODMACommand.h>
31 #include <libkern/c++/OSData.h>
32 #include <libkern/OSDebug.h>
33 #include <mach_debug/zone_info.h>
34 #include "IOKitKernelInternal.h"
35
36 __BEGIN_DECLS
37 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
38 __END_DECLS
39
40 #define super IOService
41 OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
42
43 OSMetaClassDefineReservedUnused(IOMapper, 0);
44 OSMetaClassDefineReservedUnused(IOMapper, 1);
45 OSMetaClassDefineReservedUnused(IOMapper, 2);
46 OSMetaClassDefineReservedUnused(IOMapper, 3);
47 OSMetaClassDefineReservedUnused(IOMapper, 4);
48 OSMetaClassDefineReservedUnused(IOMapper, 5);
49 OSMetaClassDefineReservedUnused(IOMapper, 6);
50 OSMetaClassDefineReservedUnused(IOMapper, 7);
51 OSMetaClassDefineReservedUnused(IOMapper, 8);
52 OSMetaClassDefineReservedUnused(IOMapper, 9);
53 OSMetaClassDefineReservedUnused(IOMapper, 10);
54 OSMetaClassDefineReservedUnused(IOMapper, 11);
55 OSMetaClassDefineReservedUnused(IOMapper, 12);
56 OSMetaClassDefineReservedUnused(IOMapper, 13);
57 OSMetaClassDefineReservedUnused(IOMapper, 14);
58 OSMetaClassDefineReservedUnused(IOMapper, 15);
59
60 IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
61
62 class IOMapperLock {
63 IOLock *fWaitLock;
64 public:
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 }
94 };
95
96 static IOMapperLock sMapperLock;
97
98 bool
99 IOMapper::start(IOService *provider)
100 {
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;
129 }
130
131 void
132 IOMapper::free()
133 {
134 super::free();
135 }
136
137 void
138 IOMapper::setMapperRequired(bool hasMapper)
139 {
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 }
148 }
149
150 void
151 IOMapper::waitForSystemMapper()
152 {
153 sMapperLock.lock();
154 while ((uintptr_t) IOMapper::gSystem & kWaitMask) {
155 OSReportWithBacktrace("waitForSystemMapper");
156 sMapperLock.sleep(&IOMapper::gSystem);
157 }
158 sMapperLock.unlock();
159 }
160
161 IOMapper *
162 IOMapper::copyMapperForDevice(IOService * device)
163 {
164 return copyMapperForDeviceWithIndex(device, 0);
165 }
166
167 IOMapper *
168 IOMapper::copyMapperForDeviceWithIndex(IOService * device, unsigned int index)
169 {
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 }
204
205 done:
206 if (obj) {
207 obj->release();
208 }
209 found:
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;
227 }
228
229 __BEGIN_DECLS
230
231 // These are C accessors to the system mapper for non-IOKit clients
232 ppnum_t
233 IOMapperIOVMAlloc(unsigned pages)
234 {
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;
253 }
254
255 void
256 IOMapperIOVMFree(ppnum_t addr, unsigned pages)
257 {
258 if (IOMapper::gSystem) {
259 IOMapper::gSystem->iovmUnmapMemory(NULL, NULL, ptoa_64(addr), ptoa_64(pages));
260 }
261 }
262
263 ppnum_t
264 IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page)
265 {
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;
275 }
276
277 /////////////////////////////////////////////////////////////////////////////
278 //
279 //
280 // IOLib.h APIs
281 //
282 //
283 /////////////////////////////////////////////////////////////////////////////
284
285 #include <machine/machine_routines.h>
286
287 UInt8
288 IOMappedRead8(IOPhysicalAddress address)
289 {
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 }
298 }
299
300 UInt16
301 IOMappedRead16(IOPhysicalAddress address)
302 {
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 }
311 }
312
313 UInt32
314 IOMappedRead32(IOPhysicalAddress address)
315 {
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 }
324 }
325
326 UInt64
327 IOMappedRead64(IOPhysicalAddress address)
328 {
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 }
337 }
338
339 void
340 IOMappedWrite8(IOPhysicalAddress address, UInt8 value)
341 {
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 }
350 }
351
352 void
353 IOMappedWrite16(IOPhysicalAddress address, UInt16 value)
354 {
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 }
363 }
364
365 void
366 IOMappedWrite32(IOPhysicalAddress address, UInt32 value)
367 {
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 }
376 }
377
378 void
379 IOMappedWrite64(IOPhysicalAddress address, UInt64 value)
380 {
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 }
389 }
390
391 __END_DECLS