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 return copyMapperForDeviceWithIndex(device, 0); 146} 147 148IOMapper * IOMapper::copyMapperForDeviceWithIndex(IOService * device, unsigned int index) 149{ 150 OSData *data; 151 OSObject * obj; 152 IOMapper * mapper = NULL; 153 OSDictionary * matching; 154 155 obj = device->copyProperty("iommu-parent"); 156 if (!obj) 157 return (NULL); 158 159 if ((mapper = OSDynamicCast(IOMapper, obj))) 160 return (mapper); 161 162 if ((data = OSDynamicCast(OSData, obj))) 163 { 164 if (index >= data->getLength() / sizeof(UInt32)) 165 goto done; 166 167 data = OSData::withBytesNoCopy((UInt32 *)data->getBytesNoCopy() + index, sizeof(UInt32)); 168 if (!data) 169 goto done; 170 171 matching = IOService::propertyMatching(gIOMapperIDKey, data); 172 data->release(); 173 } 174 else 175 matching = IOService::propertyMatching(gIOMapperIDKey, obj); 176 177 if (matching) 178 { 179 mapper = OSDynamicCast(IOMapper, IOService::waitForMatchingService(matching)); 180 matching->release(); 181 } 182 183done: 184 if (obj) 185 obj->release(); 186 return (mapper); 187} 188 189ppnum_t IOMapper::iovmAllocDMACommand(IODMACommand * command, IOItemCount pageCount) 190{ 191 return (0); 192} 193 194void IOMapper::iovmFreeDMACommand(IODMACommand * command, 195 ppnum_t addr, IOItemCount pageCount) 196{ 197} 198 199ppnum_t IOMapper::iovmMapMemory( 200 OSObject * memory, // dma command or iomd 201 ppnum_t offsetPage, 202 ppnum_t pageCount, 203 uint32_t options, 204 upl_page_info_t * pageList, 205 const IODMAMapSpecification * mapSpecification) 206{ 207 return (0); 208} 209 210void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset, 211 ppnum_t *pageList, IOItemCount pageCount) 212{ 213 while (pageCount--) 214 iovmInsert(addr, offset++, *pageList++); 215} 216 217void IOMapper::iovmInsert(ppnum_t addr, IOItemCount offset, 218 upl_page_info_t *pageList, IOItemCount pageCount) 219{ 220 for (IOItemCount i = 0; i < pageCount; i++) 221 iovmInsert(addr, offset + i, pageList[i].phys_addr); 222} 223 224OSData * IOMapper:: 225NewARTTable(IOByteCount size, void ** virtAddrP, ppnum_t *physAddrP) 226{ 227 if (!virtAddrP || !physAddrP) 228 return 0; 229 230 kern_return_t kr; 231 vm_address_t address; 232 233 size = round_page(size); 234 kr = kmem_alloc_contig(kernel_map, &address, size, PAGE_MASK, 0 /*max_pnum*/, 0 /*pnum_mask*/, false); 235 if (kr) 236 return 0; 237 238 ppnum_t pagenum = pmap_find_phys(kernel_pmap, (addr64_t) address); 239 if (pagenum) 240 *physAddrP = pagenum; 241 else { 242 FreeARTTable((OSData *) address, size); 243 address = 0; 244 } 245 246 *virtAddrP = (void *) address; 247 248 return (OSData *) address; 249} 250 251void IOMapper::FreeARTTable(OSData *artHandle, IOByteCount size) 252{ 253 vm_address_t address = (vm_address_t) artHandle; 254 255 size = round_page(size); 256 kmem_free(kernel_map, address, size); // Just panic if address is 0 257} 258 259bool IOMapper::getBypassMask(addr64_t *maskP) const 260{ 261 return false; 262} 263 264__BEGIN_DECLS 265 266// These are C accessors to the system mapper for non-IOKit clients 267ppnum_t IOMapperIOVMAlloc(unsigned pages) 268{ 269 IOMapper::checkForSystemMapper(); 270 271 if (IOMapper::gSystem) 272 return IOMapper::gSystem->iovmAlloc((IOItemCount) pages); 273 else 274 return 0; 275} 276 277void IOMapperIOVMFree(ppnum_t addr, unsigned pages) 278{ 279 if (IOMapper::gSystem) 280 IOMapper::gSystem->iovmFree(addr, (IOItemCount) pages); 281} 282 283ppnum_t IOMapperInsertPage(ppnum_t addr, unsigned offset, ppnum_t page) 284{ 285 if (IOMapper::gSystem) { 286 if (!addr) panic("!addr"); 287 IOMapper::gSystem->iovmInsert(addr, (IOItemCount) offset, page); 288 return addr + offset; 289 } 290 else 291 return page; 292} 293 294void IOMapperInsertPPNPages(ppnum_t addr, unsigned offset, 295 ppnum_t *pageList, unsigned pageCount) 296{ 297 if (!IOMapper::gSystem) 298 panic("IOMapperInsertPPNPages no system mapper"); 299 else 300 assert(!((vm_address_t) IOMapper::gSystem & 3)); 301 302 IOMapper::gSystem-> 303 iovmInsert(addr, (IOItemCount) offset, pageList, pageCount); 304} 305 306void IOMapperInsertUPLPages(ppnum_t addr, unsigned offset, 307 upl_page_info_t *pageList, unsigned pageCount) 308{ 309 if (!IOMapper::gSystem) 310 panic("IOMapperInsertUPLPages no system mapper"); 311 else 312 assert(!((vm_address_t) IOMapper::gSystem & 3)); 313 314 IOMapper::gSystem->iovmInsert(addr, 315 (IOItemCount) offset, 316 pageList, 317 (IOItemCount) pageCount); 318} 319 320///////////////////////////////////////////////////////////////////////////// 321// 322// 323// IOLib.h APIs 324// 325// 326///////////////////////////////////////////////////////////////////////////// 327 328#include <machine/machine_routines.h> 329 330UInt8 IOMappedRead8(IOPhysicalAddress address) 331{ 332 IOMapper::checkForSystemMapper(); 333 334 if (IOMapper::gSystem) { 335 addr64_t addr = IOMapper::gSystem->mapAddr(address); 336 return (UInt8) ml_phys_read_byte_64(addr); 337 } 338 else 339 return (UInt8) ml_phys_read_byte((vm_offset_t) address); 340} 341 342UInt16 IOMappedRead16(IOPhysicalAddress address) 343{ 344 IOMapper::checkForSystemMapper(); 345 346 if (IOMapper::gSystem) { 347 addr64_t addr = IOMapper::gSystem->mapAddr(address); 348 return (UInt16) ml_phys_read_half_64(addr); 349 } 350 else 351 return (UInt16) ml_phys_read_half((vm_offset_t) address); 352} 353 354UInt32 IOMappedRead32(IOPhysicalAddress address) 355{ 356 IOMapper::checkForSystemMapper(); 357 358 if (IOMapper::gSystem) { 359 addr64_t addr = IOMapper::gSystem->mapAddr(address); 360 return (UInt32) ml_phys_read_word_64(addr); 361 } 362 else 363 return (UInt32) ml_phys_read_word((vm_offset_t) address); 364} 365 366UInt64 IOMappedRead64(IOPhysicalAddress address) 367{ 368 IOMapper::checkForSystemMapper(); 369 370 if (IOMapper::gSystem) { 371 addr64_t addr = IOMapper::gSystem->mapAddr(address); 372 return (UInt64) ml_phys_read_double_64(addr); 373 } 374 else 375 return (UInt64) ml_phys_read_double((vm_offset_t) address); 376} 377 378void IOMappedWrite8(IOPhysicalAddress address, UInt8 value) 379{ 380 IOMapper::checkForSystemMapper(); 381 382 if (IOMapper::gSystem) { 383 addr64_t addr = IOMapper::gSystem->mapAddr(address); 384 ml_phys_write_byte_64(addr, value); 385 } 386 else 387 ml_phys_write_byte((vm_offset_t) address, value); 388} 389 390void IOMappedWrite16(IOPhysicalAddress address, UInt16 value) 391{ 392 IOMapper::checkForSystemMapper(); 393 394 if (IOMapper::gSystem) { 395 addr64_t addr = IOMapper::gSystem->mapAddr(address); 396 ml_phys_write_half_64(addr, value); 397 } 398 else 399 ml_phys_write_half((vm_offset_t) address, value); 400} 401 402void IOMappedWrite32(IOPhysicalAddress address, UInt32 value) 403{ 404 IOMapper::checkForSystemMapper(); 405 406 if (IOMapper::gSystem) { 407 addr64_t addr = IOMapper::gSystem->mapAddr(address); 408 ml_phys_write_word_64(addr, value); 409 } 410 else 411 ml_phys_write_word((vm_offset_t) address, value); 412} 413 414void IOMappedWrite64(IOPhysicalAddress address, UInt64 value) 415{ 416 IOMapper::checkForSystemMapper(); 417 418 if (IOMapper::gSystem) { 419 addr64_t addr = IOMapper::gSystem->mapAddr(address); 420 ml_phys_write_double_64(addr, value); 421 } 422 else 423 ml_phys_write_double((vm_offset_t) address, value); 424} 425 426__END_DECLS 427