]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOMapper.cpp
xnu-344.21.74.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
CommitLineData
d7e50217
A
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
30OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
31
32OSMetaClassDefineReservedUnused(IOMapper, 0);
33OSMetaClassDefineReservedUnused(IOMapper, 1);
34OSMetaClassDefineReservedUnused(IOMapper, 2);
35OSMetaClassDefineReservedUnused(IOMapper, 3);
36OSMetaClassDefineReservedUnused(IOMapper, 4);
37OSMetaClassDefineReservedUnused(IOMapper, 5);
38OSMetaClassDefineReservedUnused(IOMapper, 6);
39OSMetaClassDefineReservedUnused(IOMapper, 7);
40OSMetaClassDefineReservedUnused(IOMapper, 8);
41OSMetaClassDefineReservedUnused(IOMapper, 9);
42OSMetaClassDefineReservedUnused(IOMapper, 10);
43OSMetaClassDefineReservedUnused(IOMapper, 11);
44OSMetaClassDefineReservedUnused(IOMapper, 12);
45OSMetaClassDefineReservedUnused(IOMapper, 13);
46OSMetaClassDefineReservedUnused(IOMapper, 14);
47OSMetaClassDefineReservedUnused(IOMapper, 15);
48
49IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
50
51class IOMapperLock {
52 IOLock *fWaitLock;
53public:
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
63static IOMapperLock sMapperLock;
64
65bool 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
83bool IOMapper::allocTable(IOByteCount size)
84{
85 assert(!fTable);
86
87 fTableSize = size;
88 fTableHandle = NewARTTable(size, &fTable, &fTablePhys);
89 return fTableHandle != 0;
90}
91
92void IOMapper::free()
93{
94 if (fTableHandle) {
95 FreeARTTable(fTableHandle, fTableSize);
96 fTableHandle = 0;
97 }
98
99 super::free();
100}
101
102void 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
114void IOMapper::waitForSystemMapper()
115{
116 sMapperLock.lock();
117 while ((vm_address_t) IOMapper::gSystem & kWaitMask)
118 sMapperLock.sleep(&IOMapper::gSystem);
119 sMapperLock.unlock();
120}
121
122void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset,
123 ppnum_t *pageList, IOItemCount pageCount)
124{
125 while (pageCount--)
126 iovmInsert(addr, offset++, *pageList++);
127}
128
129void 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
136struct ARTTableData {
137 void *v;
138 upl_t u[0];
139};
140#define getARTDataP(data) ((ARTTableData *) (data)->getBytesNoCopy())
141
142OSData *
143IOMapper::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
206bail:
207 FreeARTTable(ret, size);
208 return 0;
209}
210
211void 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
231ppnum_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
241void IOMapperIOVMFree(ppnum_t addr, unsigned pages)
242{
243 if (IOMapper::gSystem)
244 IOMapper::gSystem->iovmFree(addr, (IOItemCount) pages);
245}
246
247ppnum_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
257void 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
269void 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
293UInt8 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
305UInt16 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
317UInt32 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
329UInt64 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
341void 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
353void 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
365void 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
377void 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