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