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