2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <IOKit/IOLib.h>
29 #include <IOKit/IOMapper.h>
30 #include <IOKit/IODMACommand.h>
31 #include <libkern/c++/OSData.h>
32 #include <libkern/OSDebug.h>
33 #include <mach_debug/zone_info.h>
34 #include "IOKitKernelInternal.h"
37 extern ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
40 #define super IOService
41 OSDefineMetaClassAndAbstractStructors(IOMapper
, IOService
);
43 OSMetaClassDefineReservedUnused(IOMapper
, 0);
44 OSMetaClassDefineReservedUnused(IOMapper
, 1);
45 OSMetaClassDefineReservedUnused(IOMapper
, 2);
46 OSMetaClassDefineReservedUnused(IOMapper
, 3);
47 OSMetaClassDefineReservedUnused(IOMapper
, 4);
48 OSMetaClassDefineReservedUnused(IOMapper
, 5);
49 OSMetaClassDefineReservedUnused(IOMapper
, 6);
50 OSMetaClassDefineReservedUnused(IOMapper
, 7);
51 OSMetaClassDefineReservedUnused(IOMapper
, 8);
52 OSMetaClassDefineReservedUnused(IOMapper
, 9);
53 OSMetaClassDefineReservedUnused(IOMapper
, 10);
54 OSMetaClassDefineReservedUnused(IOMapper
, 11);
55 OSMetaClassDefineReservedUnused(IOMapper
, 12);
56 OSMetaClassDefineReservedUnused(IOMapper
, 13);
57 OSMetaClassDefineReservedUnused(IOMapper
, 14);
58 OSMetaClassDefineReservedUnused(IOMapper
, 15);
60 IOMapper
* IOMapper::gSystem
= (IOMapper
*) IOMapper::kUnknown
;
65 IOMapperLock() { fWaitLock
= IOLockAlloc(); }
66 ~IOMapperLock() { IOLockFree(fWaitLock
); }
68 void lock() { IOLockLock(fWaitLock
); }
69 void unlock() { IOLockUnlock(fWaitLock
); }
70 void sleep(void *event
) { IOLockSleep(fWaitLock
, event
, THREAD_UNINT
); }
71 void wakeup(void *event
) { IOLockWakeup(fWaitLock
, event
, false); }
74 static IOMapperLock sMapperLock
;
76 bool IOMapper::start(IOService
*provider
)
79 if (!super::start(provider
))
82 if (!initHardware(provider
))
85 fPageSize
= getPageSize();
89 IOMapper::gSystem
= this;
90 sMapperLock
.wakeup(&IOMapper::gSystem
);
96 obj
= provider
->getProperty("iommu-id");
98 obj
= provider
->getProperty("AAPL,phandle");
100 setProperty(gIOMapperIDKey
, obj
);
105 void IOMapper::free()
110 void IOMapper::setMapperRequired(bool hasMapper
)
113 IOMapper::gSystem
= (IOMapper
*) kHasMapper
;
116 IOMapper::gSystem
= (IOMapper
*) kNoMapper
;
117 sMapperLock
.unlock();
118 sMapperLock
.wakeup(&IOMapper::gSystem
);
122 void IOMapper::waitForSystemMapper()
125 while ((uintptr_t) IOMapper::gSystem
& kWaitMask
)
127 OSReportWithBacktrace("waitForSystemMapper");
128 sMapperLock
.sleep(&IOMapper::gSystem
);
130 sMapperLock
.unlock();
133 IOMapper
* IOMapper::copyMapperForDevice(IOService
* device
)
135 return copyMapperForDeviceWithIndex(device
, 0);
138 IOMapper
* IOMapper::copyMapperForDeviceWithIndex(IOService
* device
, unsigned int index
)
142 IOMapper
* mapper
= NULL
;
143 OSDictionary
* matching
;
145 obj
= device
->copyProperty("iommu-parent");
146 if (!obj
) return (NULL
);
148 if ((mapper
= OSDynamicCast(IOMapper
, obj
))) goto found
;
150 if ((data
= OSDynamicCast(OSData
, obj
)))
152 if (index
>= data
->getLength() / sizeof(UInt32
)) goto done
;
154 data
= OSData::withBytesNoCopy((UInt32
*)data
->getBytesNoCopy() + index
, sizeof(UInt32
));
155 if (!data
) goto done
;
157 matching
= IOService::propertyMatching(gIOMapperIDKey
, data
);
161 matching
= IOService::propertyMatching(gIOMapperIDKey
, obj
);
165 mapper
= OSDynamicCast(IOMapper
, IOService::waitForMatchingService(matching
));
170 if (obj
) obj
->release();
174 if (!mapper
->fAllocName
)
176 char name
[MACH_ZONE_NAME_MAX_LEN
];
177 char kmodname
[KMOD_MAX_NAME
];
181 tag
= IOMemoryTag(kernel_map
);
182 if (!(kmodid
= vm_tag_get_kext(tag
, &kmodname
[0], KMOD_MAX_NAME
)))
184 snprintf(kmodname
, sizeof(kmodname
), "%d", tag
);
186 snprintf(name
, sizeof(name
), "%s.DMA.%s", kmodname
, device
->getName());
187 mapper
->fAllocName
= kern_allocation_name_allocate(name
, 16);
196 // These are C accessors to the system mapper for non-IOKit clients
197 ppnum_t
IOMapperIOVMAlloc(unsigned pages
)
200 uint64_t dmaAddress
, dmaLength
;
202 IOMapper::checkForSystemMapper();
204 ret
= kIOReturnUnsupported
;
205 if (IOMapper::gSystem
)
207 ret
= IOMapper::gSystem
->iovmMapMemory(
208 NULL
, 0, ptoa_64(pages
),
209 (kIODMAMapReadAccess
| kIODMAMapWriteAccess
),
211 &dmaAddress
, &dmaLength
);
214 if (kIOReturnSuccess
== ret
) return (atop_64(dmaAddress
));
218 void IOMapperIOVMFree(ppnum_t addr
, unsigned pages
)
220 if (IOMapper::gSystem
)
222 IOMapper::gSystem
->iovmUnmapMemory(NULL
, NULL
, ptoa_64(addr
), ptoa_64(pages
));
226 ppnum_t
IOMapperInsertPage(ppnum_t addr
, unsigned offset
, ppnum_t page
)
228 if (!IOMapper::gSystem
) return (page
);
229 if (!addr
) panic("!addr");
230 IOMapper::gSystem
->iovmInsert((kIODMAMapReadAccess
| kIODMAMapWriteAccess
),
231 ptoa_64(addr
), ptoa_64(offset
), ptoa_64(page
), ptoa_64(1));
232 return (addr
+ offset
);
235 /////////////////////////////////////////////////////////////////////////////
241 /////////////////////////////////////////////////////////////////////////////
243 #include <machine/machine_routines.h>
245 UInt8
IOMappedRead8(IOPhysicalAddress address
)
247 IOMapper::checkForSystemMapper();
249 if (IOMapper::gSystem
) {
250 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
251 return (UInt8
) ml_phys_read_byte_64(addr
);
254 return (UInt8
) ml_phys_read_byte((vm_offset_t
) address
);
257 UInt16
IOMappedRead16(IOPhysicalAddress address
)
259 IOMapper::checkForSystemMapper();
261 if (IOMapper::gSystem
) {
262 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
263 return (UInt16
) ml_phys_read_half_64(addr
);
266 return (UInt16
) ml_phys_read_half((vm_offset_t
) address
);
269 UInt32
IOMappedRead32(IOPhysicalAddress address
)
271 IOMapper::checkForSystemMapper();
273 if (IOMapper::gSystem
) {
274 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
275 return (UInt32
) ml_phys_read_word_64(addr
);
278 return (UInt32
) ml_phys_read_word((vm_offset_t
) address
);
281 UInt64
IOMappedRead64(IOPhysicalAddress address
)
283 IOMapper::checkForSystemMapper();
285 if (IOMapper::gSystem
) {
286 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
287 return (UInt64
) ml_phys_read_double_64(addr
);
290 return (UInt64
) ml_phys_read_double((vm_offset_t
) address
);
293 void IOMappedWrite8(IOPhysicalAddress address
, UInt8 value
)
295 IOMapper::checkForSystemMapper();
297 if (IOMapper::gSystem
) {
298 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
299 ml_phys_write_byte_64(addr
, value
);
302 ml_phys_write_byte((vm_offset_t
) address
, value
);
305 void IOMappedWrite16(IOPhysicalAddress address
, UInt16 value
)
307 IOMapper::checkForSystemMapper();
309 if (IOMapper::gSystem
) {
310 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
311 ml_phys_write_half_64(addr
, value
);
314 ml_phys_write_half((vm_offset_t
) address
, value
);
317 void IOMappedWrite32(IOPhysicalAddress address
, UInt32 value
)
319 IOMapper::checkForSystemMapper();
321 if (IOMapper::gSystem
) {
322 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
323 ml_phys_write_word_64(addr
, value
);
326 ml_phys_write_word((vm_offset_t
) address
, value
);
329 void IOMappedWrite64(IOPhysicalAddress address
, UInt64 value
)
331 IOMapper::checkForSystemMapper();
333 if (IOMapper::gSystem
) {
334 addr64_t addr
= IOMapper::gSystem
->mapToPhysicalAddress(address
);
335 ml_phys_write_double_64(addr
, value
);
338 ml_phys_write_double((vm_offset_t
) address
, value
);