]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/Kernel/IOMapper.cpp
xnu-6153.61.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMapper.cpp
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
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"
35
36__BEGIN_DECLS
37extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
38__END_DECLS
39
40#define super IOService
41OSDefineMetaClassAndAbstractStructors(IOMapper, IOService);
42
43OSMetaClassDefineReservedUnused(IOMapper, 0);
44OSMetaClassDefineReservedUnused(IOMapper, 1);
45OSMetaClassDefineReservedUnused(IOMapper, 2);
46OSMetaClassDefineReservedUnused(IOMapper, 3);
47OSMetaClassDefineReservedUnused(IOMapper, 4);
48OSMetaClassDefineReservedUnused(IOMapper, 5);
49OSMetaClassDefineReservedUnused(IOMapper, 6);
50OSMetaClassDefineReservedUnused(IOMapper, 7);
51OSMetaClassDefineReservedUnused(IOMapper, 8);
52OSMetaClassDefineReservedUnused(IOMapper, 9);
53OSMetaClassDefineReservedUnused(IOMapper, 10);
54OSMetaClassDefineReservedUnused(IOMapper, 11);
55OSMetaClassDefineReservedUnused(IOMapper, 12);
56OSMetaClassDefineReservedUnused(IOMapper, 13);
57OSMetaClassDefineReservedUnused(IOMapper, 14);
58OSMetaClassDefineReservedUnused(IOMapper, 15);
59
60IOMapper * IOMapper::gSystem = (IOMapper *) IOMapper::kUnknown;
61
62class IOMapperLock {
63 IOLock *fWaitLock;
64public:
65 IOMapperLock()
66 {
67 fWaitLock = IOLockAlloc();
68 }
69 ~IOMapperLock()
70 {
71 IOLockFree(fWaitLock);
72 }
73
74 void
75 lock()
76 {
77 IOLockLock(fWaitLock);
78 }
79 void
80 unlock()
81 {
82 IOLockUnlock(fWaitLock);
83 }
84 void
85 sleep(void *event)
86 {
87 IOLockSleep(fWaitLock, event, THREAD_UNINT);
88 }
89 void
90 wakeup(void *event)
91 {
92 IOLockWakeup(fWaitLock, event, false);
93 }
94};
95
96static IOMapperLock sMapperLock;
97
98bool
99IOMapper::start(IOService *provider)
100{
101 OSObject * obj;
102 if (!super::start(provider)) {
103 return false;
104 }
105
106 if (!initHardware(provider)) {
107 return false;
108 }
109
110 fPageSize = getPageSize();
111
112 if (fIsSystem) {
113 sMapperLock.lock();
114 IOMapper::gSystem = this;
115 sMapperLock.wakeup(&IOMapper::gSystem);
116 sMapperLock.unlock();
117 }
118
119 if (provider) {
120 obj = provider->getProperty("iommu-id");
121 if (!obj) {
122 obj = provider->getProperty("AAPL,phandle");
123 }
124 if (obj) {
125 setProperty(gIOMapperIDKey, obj);
126 }
127 }
128 return true;
129}
130
131void
132IOMapper::free()
133{
134 super::free();
135}
136
137void
138IOMapper::setMapperRequired(bool hasMapper)
139{
140 if (hasMapper) {
141 IOMapper::gSystem = (IOMapper *) kHasMapper;
142 } else {
143 sMapperLock.lock();
144 IOMapper::gSystem = (IOMapper *) kNoMapper;
145 sMapperLock.unlock();
146 sMapperLock.wakeup(&IOMapper::gSystem);
147 }
148}
149
150void
151IOMapper::waitForSystemMapper()
152{
153 sMapperLock.lock();
154 while ((uintptr_t) IOMapper::gSystem & kWaitMask) {
155 OSReportWithBacktrace("waitForSystemMapper");
156 sMapperLock.sleep(&IOMapper::gSystem);
157 }
158 sMapperLock.unlock();
159}
160
161IOMapper *
162IOMapper::copyMapperForDevice(IOService * device)
163{
164 return copyMapperForDeviceWithIndex(device, 0);
165}
166
167IOMapper *
168IOMapper::copyMapperForDeviceWithIndex(IOService * device, unsigned int index)
169{
170 OSData *data;
171 OSObject * obj;
172 IOMapper * mapper = NULL;
173 OSDictionary * matching;
174
175 obj = device->copyProperty("iommu-parent");
176 if (!obj) {
177 return NULL;
178 }
179
180 if ((mapper = OSDynamicCast(IOMapper, obj))) {
181 goto found;
182 }
183
184 if ((data = OSDynamicCast(OSData, obj))) {
185 if (index >= data->getLength() / sizeof(UInt32)) {
186 goto done;
187 }
188
189 data = OSData::withBytesNoCopy((UInt32 *)data->getBytesNoCopy() + index, sizeof(UInt32));
190 if (!data) {
191 goto done;
192 }
193
194 matching = IOService::propertyMatching(gIOMapperIDKey, data);
195 data->release();
196 } else {
197 matching = IOService::propertyMatching(gIOMapperIDKey, obj);
198 }
199
200 if (matching) {
201 mapper = OSDynamicCast(IOMapper, IOService::waitForMatchingService(matching));
202 matching->release();
203 }
204
205done:
206 if (obj) {
207 obj->release();
208 }
209found:
210 if (mapper) {
211 if (!mapper->fAllocName) {
212 char name[MACH_ZONE_NAME_MAX_LEN];
213 char kmodname[KMOD_MAX_NAME];
214 vm_tag_t tag;
215 uint32_t kmodid;
216
217 tag = IOMemoryTag(kernel_map);
218 if (!(kmodid = vm_tag_get_kext(tag, &kmodname[0], KMOD_MAX_NAME))) {
219 snprintf(kmodname, sizeof(kmodname), "%d", tag);
220 }
221 snprintf(name, sizeof(name), "%s.DMA.%s", kmodname, device->getName());
222 mapper->fAllocName = kern_allocation_name_allocate(name, 16);
223 }
224 }
225
226 return mapper;
227}
228
229__BEGIN_DECLS
230
231// These are C accessors to the system mapper for non-IOKit clients
232ppnum_t
233IOMapperIOVMAlloc(unsigned pages)
234{
235 IOReturn ret;
236 uint64_t dmaAddress, dmaLength;
237
238 IOMapper::checkForSystemMapper();
239
240 ret = kIOReturnUnsupported;
241 if (IOMapper::gSystem) {
242 ret = IOMapper::gSystem->iovmMapMemory(
243 NULL, 0, ptoa_64(pages),
244 (kIODMAMapReadAccess | kIODMAMapWriteAccess),
245 NULL, NULL, NULL,
246 &dmaAddress, &dmaLength);
247 }
248
249 if (kIOReturnSuccess == ret) {
250 return atop_64(dmaAddress);
251 }
252 return 0;
253}
254
255void
256IOMapperIOVMFree(ppnum_t addr, unsigned pages)
257{
258 if (IOMapper::gSystem) {
259 IOMapper::gSystem->iovmUnmapMemory(NULL, NULL, ptoa_64(addr), ptoa_64(pages));
260 }
261}
262
263ppnum_t
264IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page)
265{
266 if (!IOMapper::gSystem) {
267 return page;
268 }
269 if (!addr) {
270 panic("!addr");
271 }
272 IOMapper::gSystem->iovmInsert((kIODMAMapReadAccess | kIODMAMapWriteAccess),
273 ptoa_64(addr), ptoa_64(offset), ptoa_64(page), ptoa_64(1));
274 return addr + offset;
275}
276
277/////////////////////////////////////////////////////////////////////////////
278//
279//
280// IOLib.h APIs
281//
282//
283/////////////////////////////////////////////////////////////////////////////
284
285#include <machine/machine_routines.h>
286
287UInt8
288IOMappedRead8(IOPhysicalAddress address)
289{
290 IOMapper::checkForSystemMapper();
291
292 if (IOMapper::gSystem) {
293 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
294 return (UInt8) ml_phys_read_byte_64(addr);
295 } else {
296 return (UInt8) ml_phys_read_byte((vm_offset_t) address);
297 }
298}
299
300UInt16
301IOMappedRead16(IOPhysicalAddress address)
302{
303 IOMapper::checkForSystemMapper();
304
305 if (IOMapper::gSystem) {
306 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
307 return (UInt16) ml_phys_read_half_64(addr);
308 } else {
309 return (UInt16) ml_phys_read_half((vm_offset_t) address);
310 }
311}
312
313UInt32
314IOMappedRead32(IOPhysicalAddress address)
315{
316 IOMapper::checkForSystemMapper();
317
318 if (IOMapper::gSystem) {
319 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
320 return (UInt32) ml_phys_read_word_64(addr);
321 } else {
322 return (UInt32) ml_phys_read_word((vm_offset_t) address);
323 }
324}
325
326UInt64
327IOMappedRead64(IOPhysicalAddress address)
328{
329 IOMapper::checkForSystemMapper();
330
331 if (IOMapper::gSystem) {
332 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
333 return (UInt64) ml_phys_read_double_64(addr);
334 } else {
335 return (UInt64) ml_phys_read_double((vm_offset_t) address);
336 }
337}
338
339void
340IOMappedWrite8(IOPhysicalAddress address, UInt8 value)
341{
342 IOMapper::checkForSystemMapper();
343
344 if (IOMapper::gSystem) {
345 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
346 ml_phys_write_byte_64(addr, value);
347 } else {
348 ml_phys_write_byte((vm_offset_t) address, value);
349 }
350}
351
352void
353IOMappedWrite16(IOPhysicalAddress address, UInt16 value)
354{
355 IOMapper::checkForSystemMapper();
356
357 if (IOMapper::gSystem) {
358 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
359 ml_phys_write_half_64(addr, value);
360 } else {
361 ml_phys_write_half((vm_offset_t) address, value);
362 }
363}
364
365void
366IOMappedWrite32(IOPhysicalAddress address, UInt32 value)
367{
368 IOMapper::checkForSystemMapper();
369
370 if (IOMapper::gSystem) {
371 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
372 ml_phys_write_word_64(addr, value);
373 } else {
374 ml_phys_write_word((vm_offset_t) address, value);
375 }
376}
377
378void
379IOMappedWrite64(IOPhysicalAddress address, UInt64 value)
380{
381 IOMapper::checkForSystemMapper();
382
383 if (IOMapper::gSystem) {
384 addr64_t addr = IOMapper::gSystem->mapToPhysicalAddress(address);
385 ml_phys_write_double_64(addr, value);
386 } else {
387 ml_phys_write_double((vm_offset_t) address, value);
388 }
389}
390
391__END_DECLS