2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
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.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 #include <IOKit/IOLib.h>
31 #include <IOKit/IOMapper.h>
32 #include <libkern/c++/OSData.h>
34 #define super IOService
35 OSDefineMetaClassAndAbstractStructors(IOMapper
, IOService
);
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);
54 IOMapper
* IOMapper::gSystem
= (IOMapper
*) IOMapper::kUnknown
;
59 IOMapperLock() { fWaitLock
= IOLockAlloc(); };
60 ~IOMapperLock() { IOLockFree(fWaitLock
); };
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); };
68 static IOMapperLock sMapperLock
;
70 bool IOMapper::start(IOService
*provider
)
72 if (!super::start(provider
))
75 if (!initHardware(provider
))
80 IOMapper::gSystem
= this;
81 sMapperLock
.wakeup(&IOMapper::gSystem
);
88 bool IOMapper::allocTable(IOByteCount size
)
93 fTableHandle
= NewARTTable(size
, &fTable
, &fTablePhys
);
94 return fTableHandle
!= 0;
100 FreeARTTable(fTableHandle
, fTableSize
);
107 void IOMapper::setMapperRequired(bool hasMapper
)
110 IOMapper::gSystem
= (IOMapper
*) kHasMapper
;
113 IOMapper::gSystem
= (IOMapper
*) kNoMapper
;
114 sMapperLock
.unlock();
115 sMapperLock
.wakeup(&IOMapper::gSystem
);
119 void IOMapper::waitForSystemMapper()
122 while ((vm_address_t
) IOMapper::gSystem
& kWaitMask
)
123 sMapperLock
.sleep(&IOMapper::gSystem
);
124 sMapperLock
.unlock();
127 void IOMapper::iovmInsert(ppnum_t addr
, IOItemCount offset
,
128 ppnum_t
*pageList
, IOItemCount pageCount
)
131 iovmInsert(addr
, offset
++, *pageList
++);
134 void IOMapper::iovmInsert(ppnum_t addr
, IOItemCount offset
,
135 upl_page_info_t
*pageList
, IOItemCount pageCount
)
137 for (IOItemCount i
= 0; i
< pageCount
; i
++)
138 iovmInsert(addr
, offset
+ i
, pageList
[i
].phys_addr
);
141 struct ARTTableData
{
145 #define getARTDataP(data) ((ARTTableData *) (data)->getBytesNoCopy())
148 IOMapper::NewARTTable(IOByteCount size
,
149 void ** virtAddrP
, ppnum_t
*physAddrP
)
153 vm_address_t startUpl
;
155 unsigned int dataSize
;
156 upl_page_info_t
*pl
= 0;
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
);
165 // Append 0's to the buffer, in-other-words reset to nulls.
166 ret
->appendBytes(NULL
, sizeof(ARTTableData
));
167 dataP
= getARTDataP(ret
);
169 kr
= kmem_alloc_contig(kernel_map
, &startUpl
, size
, PAGE_MASK
, 0);
173 dataP
->v
= (void *) startUpl
;
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
;
181 kr
= vm_map_get_upl(kernel_map
,
182 (vm_map_offset_t
)startUpl
,
190 panic("IOMapper:vm_map_get_upl returned 0x%x\n");
194 if (!ret
->appendBytes(&iopl
, sizeof(upl_t
)))
197 startUpl
+= iopl_size
;
201 // Need to re-establish the dataP as the OSData may have grown.
202 dataP
= getARTDataP(ret
);
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
;
212 FreeARTTable(ret
, size
);
216 void IOMapper::FreeARTTable(OSData
*artHandle
, IOByteCount size
)
220 ARTTableData
*dataP
= getARTDataP(artHandle
);
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
]);
229 size
= round_page_32(size
);
230 kmem_free(kernel_map
, (vm_address_t
) dataP
->v
, size
);
232 artHandle
->release();
237 // These are C accessors to the system mapper for non-IOKit clients
238 ppnum_t
IOMapperIOVMAlloc(unsigned pages
)
240 IOMapper::checkForSystemMapper();
242 if (IOMapper::gSystem
)
243 return IOMapper::gSystem
->iovmAlloc((IOItemCount
) pages
);
248 void IOMapperIOVMFree(ppnum_t addr
, unsigned pages
)
250 if (IOMapper::gSystem
)
251 IOMapper::gSystem
->iovmFree(addr
, (IOItemCount
) pages
);
254 ppnum_t
IOMapperInsertPage(ppnum_t addr
, unsigned offset
, ppnum_t page
)
256 if (IOMapper::gSystem
) {
257 IOMapper::gSystem
->iovmInsert(addr
, (IOItemCount
) offset
, page
);
258 return addr
+ offset
;
264 void IOMapperInsertPPNPages(ppnum_t addr
, unsigned offset
,
265 ppnum_t
*pageList
, unsigned pageCount
)
267 if (!IOMapper::gSystem
)
268 panic("IOMapperInsertPPNPages no system mapper");
270 assert(!((vm_address_t
) IOMapper::gSystem
& 3));
273 iovmInsert(addr
, (IOItemCount
) offset
, pageList
, pageCount
);
276 void IOMapperInsertUPLPages(ppnum_t addr
, unsigned offset
,
277 upl_page_info_t
*pageList
, unsigned pageCount
)
279 if (!IOMapper::gSystem
)
280 panic("IOMapperInsertUPLPages no system mapper");
282 assert(!((vm_address_t
) IOMapper::gSystem
& 3));
284 IOMapper::gSystem
->iovmInsert(addr
,
285 (IOItemCount
) offset
,
287 (IOItemCount
) pageCount
);
290 /////////////////////////////////////////////////////////////////////////////
296 /////////////////////////////////////////////////////////////////////////////
298 #include <machine/machine_routines.h>
300 UInt8
IOMappedRead8(IOPhysicalAddress address
)
302 IOMapper::checkForSystemMapper();
304 if (IOMapper::gSystem
) {
305 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
306 return (UInt8
) ml_phys_read_byte_64(addr
);
309 return (UInt8
) ml_phys_read_byte((vm_offset_t
) address
);
312 UInt16
IOMappedRead16(IOPhysicalAddress address
)
314 IOMapper::checkForSystemMapper();
316 if (IOMapper::gSystem
) {
317 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
318 return (UInt16
) ml_phys_read_half_64(addr
);
321 return (UInt16
) ml_phys_read_half((vm_offset_t
) address
);
324 UInt32
IOMappedRead32(IOPhysicalAddress address
)
326 IOMapper::checkForSystemMapper();
328 if (IOMapper::gSystem
) {
329 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
330 return (UInt32
) ml_phys_read_word_64(addr
);
333 return (UInt32
) ml_phys_read_word((vm_offset_t
) address
);
336 UInt64
IOMappedRead64(IOPhysicalAddress address
)
338 IOMapper::checkForSystemMapper();
340 if (IOMapper::gSystem
) {
341 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
342 return (UInt64
) ml_phys_read_double_64(addr
);
345 return (UInt64
) ml_phys_read_double((vm_offset_t
) address
);
348 void IOMappedWrite8(IOPhysicalAddress address
, UInt8 value
)
350 IOMapper::checkForSystemMapper();
352 if (IOMapper::gSystem
) {
353 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
354 ml_phys_write_byte_64(addr
, value
);
357 ml_phys_write_byte((vm_offset_t
) address
, value
);
360 void IOMappedWrite16(IOPhysicalAddress address
, UInt16 value
)
362 IOMapper::checkForSystemMapper();
364 if (IOMapper::gSystem
) {
365 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
366 ml_phys_write_half_64(addr
, value
);
369 ml_phys_write_half((vm_offset_t
) address
, value
);
372 void IOMappedWrite32(IOPhysicalAddress address
, UInt32 value
)
374 IOMapper::checkForSystemMapper();
376 if (IOMapper::gSystem
) {
377 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
378 ml_phys_write_word_64(addr
, value
);
381 ml_phys_write_word((vm_offset_t
) address
, value
);
384 void IOMappedWrite64(IOPhysicalAddress address
, UInt64 value
)
386 IOMapper::checkForSystemMapper();
388 if (IOMapper::gSystem
) {
389 addr64_t addr
= IOMapper::gSystem
->mapAddr(address
);
390 ml_phys_write_double_64(addr
, value
);
393 ml_phys_write_double((vm_offset_t
) address
, value
);