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