]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOMapper.cpp
xnu-2050.9.2.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
CommitLineData
55e303ae 1/*
91447636 2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
55e303ae 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
55e303ae 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.
8f6c56a5 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.
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
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.
8f6c56a5 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
A
31#include <libkern/c++/OSData.h>
32
0c530ab8
A
33__BEGIN_DECLS
34extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
35__END_DECLS
36
55e303ae
A
37#define super IOService
38OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
39
0c530ab8 40OSMetaClassDefineReservedUsed(IOMapper, 0);
b0d623f7
A
41OSMetaClassDefineReservedUsed(IOMapper, 1);
42OSMetaClassDefineReservedUsed(IOMapper, 2);
55e303ae
A
43OSMetaClassDefineReservedUnused(IOMapper, 3);
44OSMetaClassDefineReservedUnused(IOMapper, 4);
45OSMetaClassDefineReservedUnused(IOMapper, 5);
46OSMetaClassDefineReservedUnused(IOMapper, 6);
47OSMetaClassDefineReservedUnused(IOMapper, 7);
48OSMetaClassDefineReservedUnused(IOMapper, 8);
49OSMetaClassDefineReservedUnused(IOMapper, 9);
50OSMetaClassDefineReservedUnused(IOMapper, 10);
51OSMetaClassDefineReservedUnused(IOMapper, 11);
52OSMetaClassDefineReservedUnused(IOMapper, 12);
53OSMetaClassDefineReservedUnused(IOMapper, 13);
54OSMetaClassDefineReservedUnused(IOMapper, 14);
55OSMetaClassDefineReservedUnused(IOMapper, 15);
56
57IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
58
59class IOMapperLock {
60 IOLock *fWaitLock;
61public:
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
71static IOMapperLock sMapperLock;
72
73bool IOMapper::start(IOService *provider)
74{
b0d623f7 75 OSObject * obj;
55e303ae
A
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
b0d623f7
A
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 }
55e303ae
A
97 return true;
98}
99
100bool IOMapper::allocTable(IOByteCount size)
101{
102 assert(!fTable);
103
104 fTableSize = size;
105 fTableHandle = NewARTTable(size, &fTable, &fTablePhys);
106 return fTableHandle != 0;
107}
108
109void IOMapper::free()
110{
111 if (fTableHandle) {
112 FreeARTTable(fTableHandle, fTableSize);
113 fTableHandle = 0;
114 }
115
116 super::free();
117}
118
119void 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
131void IOMapper::waitForSystemMapper()
132{
133 sMapperLock.lock();
b0d623f7 134 while ((uintptr_t) IOMapper::gSystem & kWaitMask)
55e303ae
A
135 sMapperLock.sleep(&IOMapper::gSystem);
136 sMapperLock.unlock();
137}
138
b0d623f7
A
139IOMapper * 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
166ppnum_t IOMapper::iovmAllocDMACommand(IODMACommand * command, IOItemCount pageCount)
167{
168 return (0);
169}
170
171void IOMapper::iovmFreeDMACommand(IODMACommand * command,
172 ppnum_t addr, IOItemCount pageCount)
173{
174}
175
55e303ae
A
176void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
177 ppnum_t *pageList, IOItemCount pageCount)
178{
179 while (pageCount--)
180 iovmInsert(addr, offset++, *pageList++);
181}
182
183void 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
0c530ab8
A
190OSData * IOMapper::
191NewARTTable(IOByteCount size, void ** virtAddrP, ppnum_t *physAddrP)
6601e61a 192{
0c530ab8
A
193 if (!virtAddrP || !physAddrP)
194 return 0;
195
55e303ae 196 kern_return_t kr;
0c530ab8 197 vm_address_t address;
55e303ae 198
b0d623f7
A
199 size = round_page(size);
200 kr = kmem_alloc_contig(kernel_map, &address, size, PAGE_MASK, 0 /*max_pnum*/, 0 /*pnum_mask*/, false);
0c530ab8 201 if (kr)
55e303ae
A
202 return 0;
203
0c530ab8
A
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 }
55e303ae 211
0c530ab8 212 *virtAddrP = (void *) address;
55e303ae 213
0c530ab8 214 return (OSData *) address;
55e303ae
A
215}
216
217void IOMapper::FreeARTTable(OSData *artHandle, IOByteCount size)
218{
0c530ab8 219 vm_address_t address = (vm_address_t) artHandle;
21362eb3 220
b0d623f7 221 size = round_page(size);
0c530ab8
A
222 kmem_free(kernel_map, address, size); // Just panic if address is 0
223}
6601e61a 224
0c530ab8
A
225bool IOMapper::getBypassMask(addr64_t *maskP) const
226{
227 return false;
55e303ae
A
228}
229
230__BEGIN_DECLS
231
232// These are C accessors to the system mapper for non-IOKit clients
233ppnum_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
243void IOMapperIOVMFree(ppnum_t addr, unsigned pages)
244{
245 if (IOMapper::gSystem)
246 IOMapper::gSystem->iovmFree(addr, (IOItemCount) pages);
247}
248
249ppnum_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
259void 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
271void 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
295UInt8 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
307UInt16 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
319UInt32 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
331UInt64 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
343void 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
355void 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
367void 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
379void 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