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