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