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