]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMapper.cpp
c2691aea70d927921a8cce28fe4e3116ff7e9911
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
1 /*
2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 #include <IOKit/IOLib.h>
31 #include <IOKit/IOMapper.h>
32 #include <libkern/c++/OSData.h>
33
34 #include "IOCopyMapper.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 OSMetaClassDefineReservedUsed(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() { fWaitLock = IOLockAlloc(); };
66 ~IOMapperLock() { IOLockFree(fWaitLock); };
67
68 void lock() { IOLockLock(fWaitLock); };
69 void unlock() { IOLockUnlock(fWaitLock); };
70 void sleep(void *event) { IOLockSleep(fWaitLock, event, THREAD_UNINT); };
71 void wakeup(void *event) { IOLockWakeup(fWaitLock, event, false); };
72 };
73
74 static IOMapperLock sMapperLock;
75
76 bool IOMapper::start(IOService *provider)
77 {
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 return true;
92 }
93
94 bool IOMapper::allocTable(IOByteCount size)
95 {
96 assert(!fTable);
97
98 fTableSize = size;
99 fTableHandle = NewARTTable(size, &fTable, &fTablePhys);
100 return fTableHandle != 0;
101 }
102
103 void IOMapper::free()
104 {
105 if (fTableHandle) {
106 FreeARTTable(fTableHandle, fTableSize);
107 fTableHandle = 0;
108 }
109
110 super::free();
111 }
112
113 void IOMapper::setMapperRequired(bool hasMapper)
114 {
115 if (hasMapper)
116 IOMapper::gSystem = (IOMapper *) kHasMapper;
117 else {
118 sMapperLock.lock();
119 IOMapper::gSystem = (IOMapper *) kNoMapper;
120 sMapperLock.unlock();
121 sMapperLock.wakeup(&IOMapper::gSystem);
122 }
123 }
124
125 void IOMapper::waitForSystemMapper()
126 {
127 sMapperLock.lock();
128 while ((vm_address_t) IOMapper::gSystem & kWaitMask)
129 sMapperLock.sleep(&IOMapper::gSystem);
130 sMapperLock.unlock();
131 }
132
133 void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
134 ppnum_t *pageList, IOItemCount pageCount)
135 {
136 while (pageCount--)
137 iovmInsert(addr, offset++, *pageList++);
138 }
139
140 void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
141 upl_page_info_t *pageList, IOItemCount pageCount)
142 {
143 for (IOItemCount i = 0; i < pageCount; i++)
144 iovmInsert(addr, offset + i, pageList[i].phys_addr);
145 }
146
147 OSData * IOMapper::
148 NewARTTable(IOByteCount size, void ** virtAddrP, ppnum_t *physAddrP)
149 {
150 if (!virtAddrP || !physAddrP)
151 return 0;
152
153 kern_return_t kr;
154 vm_address_t address;
155
156 size = round_page_32(size);
157 kr = kmem_alloc_contig(kernel_map, &address, size, PAGE_MASK, 0);
158 if (kr)
159 return 0;
160
161 ppnum_t pagenum = pmap_find_phys(kernel_pmap, (addr64_t) address);
162 if (pagenum)
163 *physAddrP = pagenum;
164 else {
165 FreeARTTable((OSData *) address, size);
166 address = 0;
167 }
168
169 *virtAddrP = (void *) address;
170
171 return (OSData *) address;
172 }
173
174 void IOMapper::FreeARTTable(OSData *artHandle, IOByteCount size)
175 {
176 vm_address_t address = (vm_address_t) artHandle;
177
178 size = round_page_32(size);
179 kmem_free(kernel_map, address, size); // Just panic if address is 0
180 }
181
182 bool IOMapper::getBypassMask(addr64_t *maskP) const
183 {
184 return false;
185 }
186
187 __BEGIN_DECLS
188
189 // These are C accessors to the system mapper for non-IOKit clients
190 ppnum_t IOMapperIOVMAlloc(unsigned pages)
191 {
192 IOMapper::checkForSystemMapper();
193
194 if (IOMapper::gSystem)
195 return IOMapper::gSystem->iovmAlloc((IOItemCount) pages);
196 else
197 return 0;
198 }
199
200 void IOMapperIOVMFree(ppnum_t addr, unsigned pages)
201 {
202 if (IOMapper::gSystem)
203 IOMapper::gSystem->iovmFree(addr, (IOItemCount) pages);
204 }
205
206 ppnum_t IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page)
207 {
208 if (IOMapper::gSystem) {
209 IOMapper::gSystem->iovmInsert(addr, (IOItemCount) offset, page);
210 return addr + offset;
211 }
212 else
213 return page;
214 }
215
216 void IOMapperInsertPPNPages(ppnum_t addr, unsigned offset,
217 ppnum_t *pageList, unsigned pageCount)
218 {
219 if (!IOMapper::gSystem)
220 panic("IOMapperInsertPPNPages no system mapper");
221 else
222 assert(!((vm_address_t) IOMapper::gSystem & 3));
223
224 IOMapper::gSystem->
225 iovmInsert(addr, (IOItemCount) offset, pageList, pageCount);
226 }
227
228 void IOMapperInsertUPLPages(ppnum_t addr, unsigned offset,
229 upl_page_info_t *pageList, unsigned pageCount)
230 {
231 if (!IOMapper::gSystem)
232 panic("IOMapperInsertUPLPages no system mapper");
233 else
234 assert(!((vm_address_t) IOMapper::gSystem & 3));
235
236 IOMapper::gSystem->iovmInsert(addr,
237 (IOItemCount) offset,
238 pageList,
239 (IOItemCount) pageCount);
240 }
241
242 /////////////////////////////////////////////////////////////////////////////
243 //
244 //
245 // IOLib.h APIs
246 //
247 //
248 /////////////////////////////////////////////////////////////////////////////
249
250 #include <machine/machine_routines.h>
251
252 UInt8 IOMappedRead8(IOPhysicalAddress address)
253 {
254 IOMapper::checkForSystemMapper();
255
256 if (IOMapper::gSystem) {
257 addr64_t addr = IOMapper::gSystem->mapAddr(address);
258 return (UInt8) ml_phys_read_byte_64(addr);
259 }
260 else
261 return (UInt8) ml_phys_read_byte((vm_offset_t) address);
262 }
263
264 UInt16 IOMappedRead16(IOPhysicalAddress address)
265 {
266 IOMapper::checkForSystemMapper();
267
268 if (IOMapper::gSystem) {
269 addr64_t addr = IOMapper::gSystem->mapAddr(address);
270 return (UInt16) ml_phys_read_half_64(addr);
271 }
272 else
273 return (UInt16) ml_phys_read_half((vm_offset_t) address);
274 }
275
276 UInt32 IOMappedRead32(IOPhysicalAddress address)
277 {
278 IOMapper::checkForSystemMapper();
279
280 if (IOMapper::gSystem) {
281 addr64_t addr = IOMapper::gSystem->mapAddr(address);
282 return (UInt32) ml_phys_read_word_64(addr);
283 }
284 else
285 return (UInt32) ml_phys_read_word((vm_offset_t) address);
286 }
287
288 UInt64 IOMappedRead64(IOPhysicalAddress address)
289 {
290 IOMapper::checkForSystemMapper();
291
292 if (IOMapper::gSystem) {
293 addr64_t addr = IOMapper::gSystem->mapAddr(address);
294 return (UInt64) ml_phys_read_double_64(addr);
295 }
296 else
297 return (UInt64) ml_phys_read_double((vm_offset_t) address);
298 }
299
300 void IOMappedWrite8(IOPhysicalAddress address, UInt8 value)
301 {
302 IOMapper::checkForSystemMapper();
303
304 if (IOMapper::gSystem) {
305 addr64_t addr = IOMapper::gSystem->mapAddr(address);
306 ml_phys_write_byte_64(addr, value);
307 }
308 else
309 ml_phys_write_byte((vm_offset_t) address, value);
310 }
311
312 void IOMappedWrite16(IOPhysicalAddress address, UInt16 value)
313 {
314 IOMapper::checkForSystemMapper();
315
316 if (IOMapper::gSystem) {
317 addr64_t addr = IOMapper::gSystem->mapAddr(address);
318 ml_phys_write_half_64(addr, value);
319 }
320 else
321 ml_phys_write_half((vm_offset_t) address, value);
322 }
323
324 void IOMappedWrite32(IOPhysicalAddress address, UInt32 value)
325 {
326 IOMapper::checkForSystemMapper();
327
328 if (IOMapper::gSystem) {
329 addr64_t addr = IOMapper::gSystem->mapAddr(address);
330 ml_phys_write_word_64(addr, value);
331 }
332 else
333 ml_phys_write_word((vm_offset_t) address, value);
334 }
335
336 void IOMappedWrite64(IOPhysicalAddress address, UInt64 value)
337 {
338 IOMapper::checkForSystemMapper();
339
340 if (IOMapper::gSystem) {
341 addr64_t addr = IOMapper::gSystem->mapAddr(address);
342 ml_phys_write_double_64(addr, value);
343 }
344 else
345 ml_phys_write_double((vm_offset_t) address, value);
346 }
347
348 mach_vm_address_t IOMallocPhysical(mach_vm_size_t size, mach_vm_address_t mask)
349 {
350 mach_vm_address_t address = 0;
351 if (gIOCopyMapper)
352 {
353 address = ptoa_64(gIOCopyMapper->iovmAlloc(atop_64(round_page(size))));
354 }
355
356 return (address);
357 }
358
359 void IOFreePhysical(mach_vm_address_t address, mach_vm_size_t size)
360 {
361 if (gIOCopyMapper)
362 {
363 gIOCopyMapper->iovmFree(atop_64(address), atop_64(round_page(size)));
364 }
365 }
366
367
368 __END_DECLS