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