]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMapper.cpp
xnu-1504.7.4.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
1 /*
2 * Copyright (c) 1998-2004 Apple Computer, 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
33 #include "IOCopyMapper.h"
34
35 __BEGIN_DECLS
36 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
37 __END_DECLS
38
39 #define super IOService
40 OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
41
42 OSMetaClassDefineReservedUsed(IOMapper, 0);
43 OSMetaClassDefineReservedUsed(IOMapper, 1);
44 OSMetaClassDefineReservedUsed(IOMapper, 2);
45 OSMetaClassDefineReservedUnused(IOMapper, 3);
46 OSMetaClassDefineReservedUnused(IOMapper, 4);
47 OSMetaClassDefineReservedUnused(IOMapper, 5);
48 OSMetaClassDefineReservedUnused(IOMapper, 6);
49 OSMetaClassDefineReservedUnused(IOMapper, 7);
50 OSMetaClassDefineReservedUnused(IOMapper, 8);
51 OSMetaClassDefineReservedUnused(IOMapper, 9);
52 OSMetaClassDefineReservedUnused(IOMapper, 10);
53 OSMetaClassDefineReservedUnused(IOMapper, 11);
54 OSMetaClassDefineReservedUnused(IOMapper, 12);
55 OSMetaClassDefineReservedUnused(IOMapper, 13);
56 OSMetaClassDefineReservedUnused(IOMapper, 14);
57 OSMetaClassDefineReservedUnused(IOMapper, 15);
58
59 IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
60
61 class IOMapperLock {
62 IOLock *fWaitLock;
63 public:
64 IOMapperLock() { fWaitLock = IOLockAlloc(); };
65 ~IOMapperLock() { IOLockFree(fWaitLock); };
66
67 void lock() { IOLockLock(fWaitLock); };
68 void unlock() { IOLockUnlock(fWaitLock); };
69 void sleep(void *event) { IOLockSleep(fWaitLock, event, THREAD_UNINT); };
70 void wakeup(void *event) { IOLockWakeup(fWaitLock, event, false); };
71 };
72
73 static IOMapperLock sMapperLock;
74
75 bool IOMapper::start(IOService *provider)
76 {
77 OSObject * obj;
78 if (!super::start(provider))
79 return false;
80
81 if (!initHardware(provider))
82 return false;
83
84 if (fIsSystem) {
85 sMapperLock.lock();
86 IOMapper::gSystem = this;
87 sMapperLock.wakeup(&IOMapper::gSystem);
88 sMapperLock.unlock();
89 }
90
91 if (provider)
92 {
93 obj = provider->getProperty("iommu-id");
94 if (!obj)
95 obj = provider->getProperty("AAPL,phandle");
96 if (obj)
97 setProperty(gIOMapperIDKey, obj);
98 }
99 return true;
100 }
101
102 bool IOMapper::allocTable(IOByteCount size)
103 {
104 assert(!fTable);
105
106 fTableSize = size;
107 fTableHandle = NewARTTable(size, &fTable, &fTablePhys);
108 return fTableHandle != 0;
109 }
110
111 void IOMapper::free()
112 {
113 if (fTableHandle) {
114 FreeARTTable(fTableHandle, fTableSize);
115 fTableHandle = 0;
116 }
117
118 super::free();
119 }
120
121 void IOMapper::setMapperRequired(bool hasMapper)
122 {
123 if (hasMapper)
124 IOMapper::gSystem = (IOMapper *) kHasMapper;
125 else {
126 sMapperLock.lock();
127 IOMapper::gSystem = (IOMapper *) kNoMapper;
128 sMapperLock.unlock();
129 sMapperLock.wakeup(&IOMapper::gSystem);
130 }
131 }
132
133 void IOMapper::waitForSystemMapper()
134 {
135 sMapperLock.lock();
136 while ((uintptr_t) IOMapper::gSystem & kWaitMask)
137 sMapperLock.sleep(&IOMapper::gSystem);
138 sMapperLock.unlock();
139 }
140
141 IOMapper * IOMapper::copyMapperForDevice(IOService * device)
142 {
143 OSObject * obj;
144 IOMapper * mapper;
145 OSDictionary * matching;
146
147 obj = device->copyProperty("iommu-parent");
148 if (!obj)
149 return (NULL);
150
151 if ((mapper = OSDynamicCast(IOMapper, obj)))
152 return (mapper);
153
154 matching = IOService::propertyMatching(gIOMapperIDKey, obj);
155 if (matching)
156 {
157 mapper = OSDynamicCast(IOMapper, IOService::waitForMatchingService(matching));
158 matching->release();
159 }
160 if (mapper)
161 device->setProperty("iommu-parent", mapper);
162 else
163 obj->release();
164
165 return (mapper);
166 }
167
168 ppnum_t IOMapper::iovmAllocDMACommand(IODMACommand * command, IOItemCount pageCount)
169 {
170 return (0);
171 }
172
173 void IOMapper::iovmFreeDMACommand(IODMACommand * command,
174 ppnum_t addr, IOItemCount pageCount)
175 {
176 }
177
178 void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
179 ppnum_t *pageList, IOItemCount pageCount)
180 {
181 while (pageCount--)
182 iovmInsert(addr, offset++, *pageList++);
183 }
184
185 void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
186 upl_page_info_t *pageList, IOItemCount pageCount)
187 {
188 for (IOItemCount i = 0; i < pageCount; i++)
189 iovmInsert(addr, offset + i, pageList[i].phys_addr);
190 }
191
192 OSData * IOMapper::
193 NewARTTable(IOByteCount size, void ** virtAddrP, ppnum_t *physAddrP)
194 {
195 if (!virtAddrP || !physAddrP)
196 return 0;
197
198 kern_return_t kr;
199 vm_address_t address;
200
201 size = round_page(size);
202 kr = kmem_alloc_contig(kernel_map, &address, size, PAGE_MASK, 0 /*max_pnum*/, 0 /*pnum_mask*/, false);
203 if (kr)
204 return 0;
205
206 ppnum_t pagenum = pmap_find_phys(kernel_pmap, (addr64_t) address);
207 if (pagenum)
208 *physAddrP = pagenum;
209 else {
210 FreeARTTable((OSData *) address, size);
211 address = 0;
212 }
213
214 *virtAddrP = (void *) address;
215
216 return (OSData *) address;
217 }
218
219 void IOMapper::FreeARTTable(OSData *artHandle, IOByteCount size)
220 {
221 vm_address_t address = (vm_address_t) artHandle;
222
223 size = round_page(size);
224 kmem_free(kernel_map, address, size); // Just panic if address is 0
225 }
226
227 bool IOMapper::getBypassMask(addr64_t *maskP) const
228 {
229 return false;
230 }
231
232 __BEGIN_DECLS
233
234 // These are C accessors to the system mapper for non-IOKit clients
235 ppnum_t IOMapperIOVMAlloc(unsigned pages)
236 {
237 IOMapper::checkForSystemMapper();
238
239 if (IOMapper::gSystem)
240 return IOMapper::gSystem->iovmAlloc((IOItemCount) pages);
241 else
242 return 0;
243 }
244
245 void IOMapperIOVMFree(ppnum_t addr, unsigned pages)
246 {
247 if (IOMapper::gSystem)
248 IOMapper::gSystem->iovmFree(addr, (IOItemCount) pages);
249 }
250
251 ppnum_t IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page)
252 {
253 if (IOMapper::gSystem) {
254 IOMapper::gSystem->iovmInsert(addr, (IOItemCount) offset, page);
255 return addr + offset;
256 }
257 else
258 return page;
259 }
260
261 void IOMapperInsertPPNPages(ppnum_t addr, unsigned offset,
262 ppnum_t *pageList, unsigned pageCount)
263 {
264 if (!IOMapper::gSystem)
265 panic("IOMapperInsertPPNPages no system mapper");
266 else
267 assert(!((vm_address_t) IOMapper::gSystem & 3));
268
269 IOMapper::gSystem->
270 iovmInsert(addr, (IOItemCount) offset, pageList, pageCount);
271 }
272
273 void IOMapperInsertUPLPages(ppnum_t addr, unsigned offset,
274 upl_page_info_t *pageList, unsigned pageCount)
275 {
276 if (!IOMapper::gSystem)
277 panic("IOMapperInsertUPLPages no system mapper");
278 else
279 assert(!((vm_address_t) IOMapper::gSystem & 3));
280
281 IOMapper::gSystem->iovmInsert(addr,
282 (IOItemCount) offset,
283 pageList,
284 (IOItemCount) pageCount);
285 }
286
287 /////////////////////////////////////////////////////////////////////////////
288 //
289 //
290 // IOLib.h APIs
291 //
292 //
293 /////////////////////////////////////////////////////////////////////////////
294
295 #include <machine/machine_routines.h>
296
297 UInt8 IOMappedRead8(IOPhysicalAddress address)
298 {
299 IOMapper::checkForSystemMapper();
300
301 if (IOMapper::gSystem) {
302 addr64_t addr = IOMapper::gSystem->mapAddr(address);
303 return (UInt8) ml_phys_read_byte_64(addr);
304 }
305 else
306 return (UInt8) ml_phys_read_byte((vm_offset_t) address);
307 }
308
309 UInt16 IOMappedRead16(IOPhysicalAddress address)
310 {
311 IOMapper::checkForSystemMapper();
312
313 if (IOMapper::gSystem) {
314 addr64_t addr = IOMapper::gSystem->mapAddr(address);
315 return (UInt16) ml_phys_read_half_64(addr);
316 }
317 else
318 return (UInt16) ml_phys_read_half((vm_offset_t) address);
319 }
320
321 UInt32 IOMappedRead32(IOPhysicalAddress address)
322 {
323 IOMapper::checkForSystemMapper();
324
325 if (IOMapper::gSystem) {
326 addr64_t addr = IOMapper::gSystem->mapAddr(address);
327 return (UInt32) ml_phys_read_word_64(addr);
328 }
329 else
330 return (UInt32) ml_phys_read_word((vm_offset_t) address);
331 }
332
333 UInt64 IOMappedRead64(IOPhysicalAddress address)
334 {
335 IOMapper::checkForSystemMapper();
336
337 if (IOMapper::gSystem) {
338 addr64_t addr = IOMapper::gSystem->mapAddr(address);
339 return (UInt64) ml_phys_read_double_64(addr);
340 }
341 else
342 return (UInt64) ml_phys_read_double((vm_offset_t) address);
343 }
344
345 void IOMappedWrite8(IOPhysicalAddress address, UInt8 value)
346 {
347 IOMapper::checkForSystemMapper();
348
349 if (IOMapper::gSystem) {
350 addr64_t addr = IOMapper::gSystem->mapAddr(address);
351 ml_phys_write_byte_64(addr, value);
352 }
353 else
354 ml_phys_write_byte((vm_offset_t) address, value);
355 }
356
357 void IOMappedWrite16(IOPhysicalAddress address, UInt16 value)
358 {
359 IOMapper::checkForSystemMapper();
360
361 if (IOMapper::gSystem) {
362 addr64_t addr = IOMapper::gSystem->mapAddr(address);
363 ml_phys_write_half_64(addr, value);
364 }
365 else
366 ml_phys_write_half((vm_offset_t) address, value);
367 }
368
369 void IOMappedWrite32(IOPhysicalAddress address, UInt32 value)
370 {
371 IOMapper::checkForSystemMapper();
372
373 if (IOMapper::gSystem) {
374 addr64_t addr = IOMapper::gSystem->mapAddr(address);
375 ml_phys_write_word_64(addr, value);
376 }
377 else
378 ml_phys_write_word((vm_offset_t) address, value);
379 }
380
381 void IOMappedWrite64(IOPhysicalAddress address, UInt64 value)
382 {
383 IOMapper::checkForSystemMapper();
384
385 if (IOMapper::gSystem) {
386 addr64_t addr = IOMapper::gSystem->mapAddr(address);
387 ml_phys_write_double_64(addr, value);
388 }
389 else
390 ml_phys_write_double((vm_offset_t) address, value);
391 }
392
393 mach_vm_address_t IOMallocPhysical(mach_vm_size_t size, mach_vm_address_t mask)
394 {
395 mach_vm_address_t address = 0;
396 if (gIOCopyMapper)
397 {
398 address = ptoa_64(gIOCopyMapper->iovmAlloc(atop_64(round_page(size))));
399 }
400 return (address);
401 }
402
403 void IOFreePhysical(mach_vm_address_t address, mach_vm_size_t size)
404 {
405 if (gIOCopyMapper)
406 {
407 gIOCopyMapper->iovmFree(atop_64(address), atop_64(round_page(size)));
408 }
409 }
410
411
412 __END_DECLS