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