1 /* 2 * Copyright (c) 2000-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 /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */ 29 30 #include <string.h> 31 32 #include <libkern/OSReturn.h> 33 34 #include <libkern/c++/OSMetaClass.h> 35 #include <libkern/c++/OSObject.h> 36 #include <libkern/c++/OSKext.h> 37 38 #include <libkern/c++/OSCollectionIterator.h> 39 #include <libkern/c++/OSDictionary.h> 40 #include <libkern/c++/OSArray.h> 41 #include <libkern/c++/OSSet.h> 42 #include <libkern/c++/OSSymbol.h> 43 #include <libkern/c++/OSNumber.h> 44 #include <libkern/c++/OSSerialize.h> 45 46 #include <libkern/c++/OSLib.h> 47 #include <libkern/OSAtomic.h> 48 49 #include <IOKit/IOLib.h> 50 51 #include <IOKit/IOKitDebug.h> 52 53 54 __BEGIN_DECLS 55 56 #include <sys/systm.h> 57 #include <mach/mach_types.h> 58 #include <kern/locks.h> 59 #include <kern/clock.h> 60 #include <kern/thread_call.h> 61 #include <kern/host.h> 62 #include <mach/mach_interface.h> 63 64 #if PRAGMA_MARK 65 #pragma mark Macros 66 #endif /* PRAGMA_MARK */ 67 /********************************************************************* 68 * Macros 69 *********************************************************************/ 70 __END_DECLS 71 72 #if PRAGMA_MARK 73 #pragma mark Internal constants & data structs 74 #endif /* PRAGMA_MARK */ 75 /********************************************************************* 76 * Internal constants & data structs 77 *********************************************************************/ 78 OSKextLogSpec kOSMetaClassLogSpec = 79 kOSKextLogErrorLevel | 80 kOSKextLogLoadFlag | 81 kOSKextLogKextBookkeepingFlag; 82 83 static enum { 84 kCompletedBootstrap = 0, 85 kNoDictionaries = 1, 86 kMakingDictionaries = 2 87 } sBootstrapState = kNoDictionaries; 88 89 static const int kClassCapacityIncrement = 40; 90 static const int kKModCapacityIncrement = 10; 91 static OSDictionary * sAllClassesDict; 92 static unsigned int sDeepestClass; 93 IOLock * sAllClassesLock = NULL; 94 IOLock * sInstancesLock = NULL; 95 96 /* 97 * While loading a kext and running all its constructors to register 98 * all OSMetaClass classes, the classes are queued up here. Only one 99 * kext can be in flight at a time, guarded by sStalledClassesLock 100 */ 101 static struct StalledData { 102 const char * kextIdentifier; 103 OSReturn result; 104 unsigned int capacity; 105 unsigned int count; 106 OSMetaClass ** classes; 107 } * sStalled; 108 IOLock * sStalledClassesLock = NULL; 109 110 struct ExpansionData { 111 OSOrderedSet * instances; 112 OSKext * kext; 113 uint32_t retain; 114 #if IOTRACKING 115 IOTrackingQueue * tracking; 116 #endif 117 }; 118 119 120 #if PRAGMA_MARK 121 #pragma mark OSMetaClassBase 122 #endif /* PRAGMA_MARK */ 123 /********************************************************************* 124 * OSMetaClassBase. 125 *********************************************************************/ 126 127 #if APPLE_KEXT_VTABLE_PADDING 128 /********************************************************************* 129 * Reserved vtable functions. 130 *********************************************************************/ 131 #if SLOT_USED 132 void OSMetaClassBase::_RESERVEDOSMetaClassBase0() 133 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); } 134 void OSMetaClassBase::_RESERVEDOSMetaClassBase1() 135 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); } 136 void OSMetaClassBase::_RESERVEDOSMetaClassBase2() 137 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 2); } 138 #endif /* SLOT_USED */ 139 140 // As these slots are used move them up inside the #if above 141 void OSMetaClassBase::_RESERVEDOSMetaClassBase3() 142 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); } 143 void OSMetaClassBase::_RESERVEDOSMetaClassBase4() 144 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); } 145 void OSMetaClassBase::_RESERVEDOSMetaClassBase5() 146 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); } 147 void OSMetaClassBase::_RESERVEDOSMetaClassBase6() 148 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6); } 149 #endif 150 151 152 /********************************************************************* 153 *********************************************************************/ 154 155 #if defined(__arm__) || defined(__arm64__) 156 157 158 159 /* 160 IHI0059A "C++ Application Binary Interface Standard for the ARM 64 - bit Architecture": 161 162 3.2.1 Representation of pointer to member function The generic C++ ABI [GC++ABI] 163 specifies that a pointer to member function is a pair of words <ptr, adj>. The 164 least significant bit of ptr discriminates between (0) the address of a non- 165 virtual member function and (1) the offset in the class's virtual table of the 166 address of a virtual function. This encoding cannot work for the AArch64 167 instruction set where the architecture reserves all bits of code addresses. This 168 ABI specifies that adj contains twice the this adjustment, plus 1 if the member 169 function is virtual. The least significant bit of adj then makes exactly the 170 same discrimination as the least significant bit of ptr does for Itanium. A 171 pointer to member function is NULL when ptr = 0 and the least significant bit of 172 adj is zero. 173 */ 174 175 OSMetaClassBase::_ptf_t 176 OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self, void (OSMetaClassBase::*func)(void)) 177 { 178 typedef long int ptrdiff_t; 179 struct ptmf_t { 180 _ptf_t fPFN; 181 ptrdiff_t delta; 182 }; 183 union { 184 void (OSMetaClassBase::*fIn)(void); 185 struct ptmf_t pTMF; 186 } map; 187 _ptf_t pfn; 188 189 map.fIn = func; 190 pfn = map.pTMF.fPFN; 191 192 if (map.pTMF.delta & 1) { 193 // virtual 194 union { 195 const OSMetaClassBase *fObj; 196 _ptf_t **vtablep; 197 } u; 198 u.fObj = self; 199 200 // Virtual member function so dereference table 201 pfn = *(_ptf_t *)(((uintptr_t)*u.vtablep) + (uintptr_t)pfn); 202 return pfn; 203 204 } else { 205 // Not virtual, i.e. plain member func 206 return pfn; 207 } 208 } 209 210 #endif /* defined(__arm__) || defined(__arm64__) */ 211 /********************************************************************* 212 * These used to be inline in the header but gcc didn't believe us 213 * Now we MUST pull the inline out at least until the compiler is 214 * repaired. 215 * 216 * Helper inlines for runtime type preprocessor macros 217 *********************************************************************/ 218 219 /********************************************************************* 220 *********************************************************************/ 221 OSMetaClassBase * 222 OSMetaClassBase::safeMetaCast( 223 const OSMetaClassBase * me, 224 const OSMetaClass * toType) 225 { 226 return (me)? me->metaCast(toType) : 0; 227 } 228 229 /********************************************************************* 230 *********************************************************************/ 231 bool 232 OSMetaClassBase::checkTypeInst( 233 const OSMetaClassBase * inst, 234 const OSMetaClassBase * typeinst) 235 { 236 const OSMetaClass * toType = OSTypeIDInst(typeinst); 237 return typeinst && inst && (0 != inst->metaCast(toType)); 238 } 239 240 /********************************************************************* 241 *********************************************************************/ 242 void OSMetaClassBase:: 243 initialize() 244 { 245 sAllClassesLock = IOLockAlloc(); 246 sStalledClassesLock = IOLockAlloc(); 247 sInstancesLock = IOLockAlloc(); 248 } 249 250 #if APPLE_KEXT_VTABLE_PADDING 251 /********************************************************************* 252 * If you need this slot you had better setup an IOCTL style interface. 253 * 'Cause the whole kernel world depends on OSMetaClassBase and YOU 254 * CANT change the VTABLE size ever. 255 *********************************************************************/ 256 void 257 OSMetaClassBase::_RESERVEDOSMetaClassBase7() 258 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); } 259 #endif 260 261 /********************************************************************* 262 *********************************************************************/ 263 OSMetaClassBase::OSMetaClassBase() 264 { 265 } 266 267 /********************************************************************* 268 *********************************************************************/ 269 OSMetaClassBase::~OSMetaClassBase() 270 { 271 void ** thisVTable; 272 273 thisVTable = (void **) this; 274 *thisVTable = (void *) -1UL; 275 } 276 277 /********************************************************************* 278 *********************************************************************/ 279 bool 280 OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const 281 { 282 return this == anObj; 283 } 284 285 /********************************************************************* 286 *********************************************************************/ 287 OSMetaClassBase * 288 OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const 289 { 290 return toMeta->checkMetaCast(this); 291 } 292 293 /********************************************************************* 294 *********************************************************************/ 295 OSMetaClassBase * 296 OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const 297 { 298 return OSMetaClass::checkMetaCastWithName(toMetaSymb, this); 299 } 300 301 /********************************************************************* 302 *********************************************************************/ 303 OSMetaClassBase * 304 OSMetaClassBase::metaCast(const OSString * toMetaStr) const 305 { 306 const OSSymbol * tempSymb = OSSymbol::withString(toMetaStr); 307 OSMetaClassBase * ret = 0; 308 if (tempSymb) { 309 ret = metaCast(tempSymb); 310 tempSymb->release(); 311 } 312 return ret; 313 } 314 315 /********************************************************************* 316 *********************************************************************/ 317 OSMetaClassBase * 318 OSMetaClassBase::metaCast(const char * toMetaCStr) const 319 { 320 const OSSymbol * tempSymb = OSSymbol::withCString(toMetaCStr); 321 OSMetaClassBase * ret = 0; 322 if (tempSymb) { 323 ret = metaCast(tempSymb); 324 tempSymb->release(); 325 } 326 return ret; 327 } 328 329 #if PRAGMA_MARK 330 #pragma mark OSMetaClassMeta 331 #endif /* PRAGMA_MARK */ 332 /********************************************************************* 333 * OSMetaClassMeta - the bootstrap metaclass of OSMetaClass 334 *********************************************************************/ 335 class OSMetaClassMeta : public OSMetaClass 336 { 337 public: 338 OSMetaClassMeta(); 339 OSObject * alloc() const; 340 }; 341 OSMetaClassMeta::OSMetaClassMeta() 342 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass)) 343 { } 344 OSObject * OSMetaClassMeta::alloc() const { return 0; } 345 346 static OSMetaClassMeta sOSMetaClassMeta; 347 348 const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta; 349 const OSMetaClass * OSMetaClass::getMetaClass() const 350 { return &sOSMetaClassMeta; } 351 352 #if PRAGMA_MARK 353 #pragma mark OSMetaClass 354 #endif /* PRAGMA_MARK */ 355 /********************************************************************* 356 * OSMetaClass 357 *********************************************************************/ 358 359 #if APPLE_KEXT_VTABLE_PADDING 360 /********************************************************************* 361 * Reserved functions. 362 *********************************************************************/ 363 void OSMetaClass::_RESERVEDOSMetaClass0() 364 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); } 365 void OSMetaClass::_RESERVEDOSMetaClass1() 366 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); } 367 void OSMetaClass::_RESERVEDOSMetaClass2() 368 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); } 369 void OSMetaClass::_RESERVEDOSMetaClass3() 370 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); } 371 void OSMetaClass::_RESERVEDOSMetaClass4() 372 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); } 373 void OSMetaClass::_RESERVEDOSMetaClass5() 374 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); } 375 void OSMetaClass::_RESERVEDOSMetaClass6() 376 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); } 377 void OSMetaClass::_RESERVEDOSMetaClass7() 378 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); } 379 #endif 380 381 /********************************************************************* 382 *********************************************************************/ 383 static void 384 OSMetaClassLogErrorForKext( 385 OSReturn error, 386 OSKext * aKext) 387 { 388 const char * message = NULL; 389 390 switch (error) { 391 case kOSReturnSuccess: 392 return; 393 case kOSMetaClassNoInit: // xxx - never returned; logged at fail site 394 message = "OSMetaClass: preModLoad() wasn't called (runtime internal error)."; 395 break; 396 case kOSMetaClassNoDicts: 397 message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries."; 398 break; 399 case kOSMetaClassNoKModSet: 400 message = "OSMetaClass: Allocation failure for internal kext recording set/set missing."; 401 break; 402 case kOSMetaClassNoInsKModSet: 403 message = "OSMetaClass: Failed to record class in kext."; 404 break; 405 case kOSMetaClassDuplicateClass: 406 message = "OSMetaClass: Duplicate class encountered."; 407 break; 408 case kOSMetaClassNoSuper: // xxx - never returned 409 message = "OSMetaClass: Can't associate a class with its superclass."; 410 break; 411 case kOSMetaClassInstNoSuper: // xxx - never returned 412 message = "OSMetaClass: Instance construction error; unknown superclass."; 413 break; 414 case kOSMetaClassNoKext: 415 message = "OSMetaClass: Kext not found for metaclass."; 416 break; 417 case kOSMetaClassInternal: 418 default: 419 message = "OSMetaClass: Runtime internal error."; 420 break; 421 } 422 423 if (message) { 424 OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message); 425 } 426 return; 427 } 428 429 void 430 OSMetaClass::logError(OSReturn error) 431 { 432 OSMetaClassLogErrorForKext(error, NULL); 433 } 434 435 /********************************************************************* 436 * The core constructor for a MetaClass (defined with this name always 437 * but within the scope of its represented class). 438 * 439 * MetaClass constructors are invoked in OSRuntimeInitializeCPP(), 440 * in between calls to OSMetaClass::preModLoad(), which sets up for 441 * registration, and OSMetaClass::postModLoad(), which actually 442 * records all the class/kext relationships of the new MetaClasses. 443 *********************************************************************/ 444 OSMetaClass::OSMetaClass( 445 const char * inClassName, 446 const OSMetaClass * inSuperClass, 447 unsigned int inClassSize) 448 { 449 instanceCount = 0; 450 classSize = inClassSize; 451 superClassLink = inSuperClass; 452 453 reserved = IONew(ExpansionData, 1); 454 bzero(reserved, sizeof(ExpansionData)); 455 #if IOTRACKING 456 uint32_t numSiteQs = 0; 457 if ((this == &OSSymbol ::gMetaClass) 458 || (this == &OSString ::gMetaClass) 459 || (this == &OSNumber ::gMetaClass) 460 || (this == &OSString ::gMetaClass) 461 || (this == &OSData ::gMetaClass) 462 || (this == &OSDictionary::gMetaClass) 463 || (this == &OSArray ::gMetaClass) 464 || (this == &OSSet ::gMetaClass)) numSiteQs = 27; 465 466 reserved->tracking = IOTrackingQueueAlloc(inClassName, (uintptr_t) this, 467 inClassSize, 0, kIOTrackingQueueTypeAlloc, 468 numSiteQs); 469 #endif 470 471 /* Hack alert: We are just casting inClassName and storing it in 472 * an OSString * instance variable. This may be because you can't 473 * create C++ objects in static constructors, but I really don't know! 474 */ 475 className = (const OSSymbol *)inClassName; 476 477 // sStalledClassesLock taken in preModLoad 478 if (!sStalled) { 479 /* There's no way we can look up the kext here, unfortunately. 480 */ 481 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec, 482 "OSMetaClass: preModLoad() wasn't called for class %s " 483 "(runtime internal error).", 484 inClassName); 485 } else if (!sStalled->result) { 486 // Grow stalled array if neccessary 487 if (sStalled->count >= sStalled->capacity) { 488 OSMetaClass **oldStalled = sStalled->classes; 489 int oldSize = sStalled->capacity * sizeof(OSMetaClass *); 490 int newSize = oldSize 491 + kKModCapacityIncrement * sizeof(OSMetaClass *); 492 493 sStalled->classes = (OSMetaClass **)kalloc_tag(newSize, VM_KERN_MEMORY_OSKEXT); 494 if (!sStalled->classes) { 495 sStalled->classes = oldStalled; 496 sStalled->result = kOSMetaClassNoTempData; 497 return; 498 } 499 500 sStalled->capacity += kKModCapacityIncrement; 501 memmove(sStalled->classes, oldStalled, oldSize); 502 kfree(oldStalled, oldSize); 503 OSMETA_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize)); 504 } 505 506 sStalled->classes[sStalled->count++] = this; 507 } 508 } 509 510 /********************************************************************* 511 *********************************************************************/ 512 OSMetaClass::~OSMetaClass() 513 { 514 OSKext * myKext = reserved ? reserved->kext : 0; // do not release 515 516 /* Hack alert: 'className' is a C string during early C++ init, and 517 * is converted to a real OSSymbol only when we record the OSKext in 518 * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext. 519 * We can't safely cast or check 'className'. 520 * 521 * Also, release className *after* calling into the kext, 522 * as removeClass() may access className. 523 */ 524 IOLockLock(sAllClassesLock); 525 if (sAllClassesDict) { 526 if (myKext) { 527 sAllClassesDict->removeObject(className); 528 } else { 529 sAllClassesDict->removeObject((const char *)className); 530 } 531 } 532 IOLockUnlock(sAllClassesLock); 533 534 if (myKext) { 535 if (myKext->removeClass(this) != kOSReturnSuccess) { 536 // xxx - what can we do? 537 } 538 className->release(); 539 } 540 541 // sStalledClassesLock taken in preModLoad 542 if (sStalled) { 543 unsigned int i; 544 545 /* First pass find class in stalled list. If we find it that means 546 * we started C++ init with constructors but now we're tearing down 547 * because of some failure. 548 */ 549 for (i = 0; i < sStalled->count; i++) { 550 if (this == sStalled->classes[i]) { 551 break; 552 } 553 } 554 555 /* Remove this metaclass from the stalled list so postModLoad() doesn't 556 * try to register it. 557 */ 558 if (i < sStalled->count) { 559 sStalled->count--; 560 if (i < sStalled->count) { 561 memmove(&sStalled->classes[i], &sStalled->classes[i+1], 562 (sStalled->count - i) * sizeof(OSMetaClass *)); 563 } 564 } 565 } 566 #if IOTRACKING 567 IOTrackingQueueFree(reserved->tracking); 568 #endif 569 IODelete(reserved, ExpansionData, 1); 570 } 571 572 /********************************************************************* 573 * Empty overrides. 574 *********************************************************************/ 575 void OSMetaClass::retain() const { } 576 void OSMetaClass::release() const { } 577 void OSMetaClass::release(__unused int when) const { } 578 void OSMetaClass::taggedRetain(__unused const void * tag) const { } 579 void OSMetaClass::taggedRelease(__unused const void * tag) const { } 580 void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { } 581 int OSMetaClass::getRetainCount() const { return 0; } 582 583 /********************************************************************* 584 *********************************************************************/ 585 const char * 586 OSMetaClass::getClassName() const 587 { 588 if (!className) return NULL; 589 return className->getCStringNoCopy(); 590 } 591 /********************************************************************* 592 *********************************************************************/ 593 const OSSymbol * 594 OSMetaClass::getClassNameSymbol() const 595 { 596 return className; 597 } 598 /********************************************************************* 599 *********************************************************************/ 600 unsigned int 601 OSMetaClass::getClassSize() const 602 { 603 return classSize; 604 } 605 606 /********************************************************************* 607 *********************************************************************/ 608 void * 609 OSMetaClass::preModLoad(const char * kextIdentifier) 610 { 611 IOLockLock(sStalledClassesLock); 612 613 assert (sStalled == NULL); 614 sStalled = (StalledData *)kalloc_tag(sizeof(* sStalled), VM_KERN_MEMORY_OSKEXT); 615 if (sStalled) { 616 sStalled->classes = (OSMetaClass **) 617 kalloc_tag(kKModCapacityIncrement * sizeof(OSMetaClass *), VM_KERN_MEMORY_OSKEXT); 618 if (!sStalled->classes) { 619 kfree(sStalled, sizeof(*sStalled)); 620 return 0; 621 } 622 OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + 623 sizeof(*sStalled)); 624 625 sStalled->result = kOSReturnSuccess; 626 sStalled->capacity = kKModCapacityIncrement; 627 sStalled->count = 0; 628 sStalled->kextIdentifier = kextIdentifier; 629 bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *)); 630 } 631 632 // keep sStalledClassesLock locked until postModLoad 633 634 return sStalled; 635 } 636 637 /********************************************************************* 638 *********************************************************************/ 639 bool 640 OSMetaClass::checkModLoad(void * loadHandle) 641 { 642 return sStalled && loadHandle == sStalled && 643 sStalled->result == kOSReturnSuccess; 644 } 645 646 /********************************************************************* 647 *********************************************************************/ 648 OSReturn 649 OSMetaClass::postModLoad(void * loadHandle) 650 { 651 OSReturn result = kOSReturnSuccess; 652 OSSymbol * myKextName = 0; // must release 653 OSKext * myKext = 0; // must release 654 655 if (!sStalled || loadHandle != sStalled) { 656 result = kOSMetaClassInternal; 657 goto finish; 658 } 659 660 if (sStalled->result) { 661 result = sStalled->result; 662 } else switch (sBootstrapState) { 663 664 case kNoDictionaries: 665 sBootstrapState = kMakingDictionaries; 666 // No break; fall through 667 [[clang::fallthrough]]; 668 669 case kMakingDictionaries: 670 sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); 671 if (!sAllClassesDict) { 672 result = kOSMetaClassNoDicts; 673 break; 674 } 675 sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort); 676 677 // No break; fall through 678 [[clang::fallthrough]]; 679 680 case kCompletedBootstrap: 681 { 682 unsigned int i; 683 myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy( 684 sStalled->kextIdentifier)); 685 686 if (!sStalled->count) { 687 break; // Nothing to do so just get out 688 } 689 690 myKext = OSKext::lookupKextWithIdentifier(myKextName); 691 if (!myKext) { 692 result = kOSMetaClassNoKext; 693 694 /* Log this error here so we can include the kext name. 695 */ 696 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec, 697 "OSMetaClass: Can't record classes for kext %s - kext not found.", 698 sStalled->kextIdentifier); 699 break; 700 } 701 702 /* First pass checking classes aren't already loaded. If any already 703 * exist, we don't register any, and so we don't technically have 704 * to do any C++ teardown. 705 * 706 * Hack alert: me->className has been a C string until now. 707 * We only release the OSSymbol if we store the kext. 708 */ 709 IOLockLock(sAllClassesLock); 710 for (i = 0; i < sStalled->count; i++) { 711 const OSMetaClass * me = sStalled->classes[i]; 712 OSMetaClass * orig = OSDynamicCast(OSMetaClass, 713 sAllClassesDict->getObject((const char *)me->className)); 714 715 if (orig) { 716 717 /* Log this error here so we can include the class name. 718 * xxx - we should look up the other kext that defines the class 719 */ 720 #if CONFIG_EMBEDDED 721 panic( 722 #else 723 OSKextLog(myKext, kOSMetaClassLogSpec, 724 #endif /* CONFIG_EMBEDDED */ 725 "OSMetaClass: Kext %s class %s is a duplicate;" 726 "kext %s already has a class by that name.", 727 sStalled->kextIdentifier, (const char *)me->className, 728 ((OSKext *)orig->reserved->kext)->getIdentifierCString()); 729 result = kOSMetaClassDuplicateClass; 730 break; 731 } 732 unsigned int depth = 1; 733 while ((me = me->superClassLink)) depth++; 734 if (depth > sDeepestClass) sDeepestClass = depth; 735 } 736 IOLockUnlock(sAllClassesLock); 737 738 /* Bail if we didn't go through the entire list of new classes 739 * (if we hit a duplicate). 740 */ 741 if (i != sStalled->count) { 742 break; 743 } 744 745 // Second pass symbolling strings and inserting classes in dictionary 746 IOLockLock(sAllClassesLock); 747 for (i = 0; i < sStalled->count; i++) { 748 OSMetaClass * me = sStalled->classes[i]; 749 750 /* Hack alert: me->className has been a C string until now. 751 * We only release the OSSymbol in ~OSMetaClass() 752 * if we set the reference to the kext. 753 */ 754 me->className = 755 OSSymbol::withCStringNoCopy((const char *)me->className); 756 757 // xxx - I suppose if these fail we're going to panic soon.... 758 sAllClassesDict->setObject(me->className, me); 759 760 /* Do not retain the kext object here. 761 */ 762 me->reserved->kext = myKext; 763 if (myKext) { 764 result = myKext->addClass(me, sStalled->count); 765 if (result != kOSReturnSuccess) { 766 /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */ 767 break; 768 } 769 } 770 } 771 IOLockUnlock(sAllClassesLock); 772 sBootstrapState = kCompletedBootstrap; 773 break; 774 } 775 776 default: 777 result = kOSMetaClassInternal; 778 break; 779 } 780 781 finish: 782 /* Don't call logError() for success or the conditions logged above 783 * or by called function. 784 */ 785 if (result != kOSReturnSuccess && 786 result != kOSMetaClassNoInsKModSet && 787 result != kOSMetaClassDuplicateClass && 788 result != kOSMetaClassNoKext) { 789 790 OSMetaClassLogErrorForKext(result, myKext); 791 } 792 793 OSSafeReleaseNULL(myKextName); 794 OSSafeReleaseNULL(myKext); 795 796 if (sStalled) { 797 OSMETA_ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) + 798 sizeof(*sStalled))); 799 kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *)); 800 kfree(sStalled, sizeof(*sStalled)); 801 sStalled = 0; 802 } 803 804 IOLockUnlock(sStalledClassesLock); 805 806 return result; 807 } 808 809 810 /********************************************************************* 811 *********************************************************************/ 812 void 813 OSMetaClass::instanceConstructed() const 814 { 815 // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink) 816 if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) { 817 superClassLink->instanceConstructed(); 818 } 819 } 820 821 /********************************************************************* 822 *********************************************************************/ 823 void 824 OSMetaClass::instanceDestructed() const 825 { 826 if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) { 827 superClassLink->instanceDestructed(); 828 } 829 830 if (((int)instanceCount) < 0) { 831 OSKext * myKext = reserved->kext; 832 833 OSKextLog(myKext, kOSMetaClassLogSpec, 834 // xxx - this phrasing is rather cryptic 835 "OSMetaClass: Class %s - bad retain (%d)", 836 getClassName(), instanceCount); 837 } 838 } 839 840 /********************************************************************* 841 *********************************************************************/ 842 bool 843 OSMetaClass::modHasInstance(const char * kextIdentifier) 844 { 845 bool result = false; 846 OSKext * theKext = NULL; // must release 847 848 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier); 849 if (!theKext) { 850 goto finish; 851 } 852 853 result = theKext->hasOSMetaClassInstances(); 854 855 finish: 856 OSSafeReleaseNULL(theKext); 857 return result; 858 } 859 860 /********************************************************************* 861 *********************************************************************/ 862 void 863 OSMetaClass::reportModInstances(const char * kextIdentifier) 864 { 865 OSKext::reportOSMetaClassInstances(kextIdentifier, 866 kOSKextLogExplicitLevel); 867 return; 868 } 869 /********************************************************************* 870 *********************************************************************/ 871 872 void 873 OSMetaClass::addInstance(const OSObject * instance, bool super) const 874 { 875 if (!super) IOLockLock(sInstancesLock); 876 877 if (!reserved->instances) { 878 reserved->instances = OSOrderedSet::withCapacity(16); 879 if (superClassLink) { 880 superClassLink->addInstance(reserved->instances, true); 881 } 882 } 883 reserved->instances->setLastObject(instance); 884 885 if (!super) IOLockUnlock(sInstancesLock); 886 } 887 888 void 889 OSMetaClass::removeInstance(const OSObject * instance, bool super) const 890 { 891 if (!super) IOLockLock(sInstancesLock); 892 893 if (reserved->instances) { 894 reserved->instances->removeObject(instance); 895 if (0 == reserved->instances->getCount()) { 896 if (superClassLink) { 897 superClassLink->removeInstance(reserved->instances, true); 898 } 899 IOLockLock(sAllClassesLock); 900 reserved->instances->release(); 901 reserved->instances = 0; 902 IOLockUnlock(sAllClassesLock); 903 } 904 } 905 906 if (!super) IOLockUnlock(sInstancesLock); 907 } 908 909 void 910 OSMetaClass::applyToInstances(OSOrderedSet * set, 911 OSMetaClassInstanceApplierFunction applier, 912 void * context) 913 { 914 enum { kLocalDepth = 24 }; 915 unsigned int _nextIndex[kLocalDepth]; 916 OSOrderedSet * _sets[kLocalDepth]; 917 unsigned int * nextIndex = &_nextIndex[0]; 918 OSOrderedSet ** sets = &_sets[0]; 919 OSObject * obj; 920 OSOrderedSet * childSet; 921 unsigned int maxDepth; 922 unsigned int idx; 923 unsigned int level; 924 bool done; 925 926 maxDepth = sDeepestClass; 927 if (maxDepth > kLocalDepth) 928 { 929 nextIndex = IONew(typeof(nextIndex[0]), maxDepth); 930 sets = IONew(typeof(sets[0]), maxDepth); 931 } 932 done = false; 933 level = 0; 934 idx = 0; 935 do 936 { 937 while (!done && (obj = set->getObject(idx++))) 938 { 939 if ((childSet = OSDynamicCast(OSOrderedSet, obj))) 940 { 941 if (level >= maxDepth) panic(">maxDepth"); 942 sets[level] = set; 943 nextIndex[level] = idx; 944 level++; 945 set = childSet; 946 idx = 0; 947 break; 948 } 949 done = (*applier)(obj, context); 950 } 951 if (!obj) 952 { 953 if (!done && level) 954 { 955 level--; 956 set = sets[level]; 957 idx = nextIndex[level]; 958 } else done = true; 959 } 960 } 961 while (!done); 962 if (maxDepth > kLocalDepth) 963 { 964 IODelete(nextIndex, typeof(nextIndex[0]), maxDepth); 965 IODelete(sets, typeof(sets[0]), maxDepth); 966 } 967 } 968 969 void 970 OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier, 971 void * context) const 972 { 973 IOLockLock(sInstancesLock); 974 if (reserved->instances) applyToInstances(reserved->instances, applier, context); 975 IOLockUnlock(sInstancesLock); 976 } 977 978 void 979 OSMetaClass::applyToInstancesOfClassName( 980 const OSSymbol * name, 981 OSMetaClassInstanceApplierFunction applier, 982 void * context) 983 { 984 OSMetaClass * meta; 985 OSOrderedSet * set = 0; 986 987 IOLockLock(sAllClassesLock); 988 if (sAllClassesDict 989 && (meta = (OSMetaClass *) sAllClassesDict->getObject(name)) 990 && (set = meta->reserved->instances)) 991 { 992 set->retain(); 993 } 994 IOLockUnlock(sAllClassesLock); 995 996 if (!set) return; 997 998 IOLockLock(sInstancesLock); 999 applyToInstances(set, applier, context); 1000 IOLockUnlock(sInstancesLock); 1001 set->release(); 1002 } 1003 1004 /********************************************************************* 1005 *********************************************************************/ 1006 void 1007 OSMetaClass::considerUnloads() 1008 { 1009 OSKext::considerUnloads(); 1010 } 1011 1012 /********************************************************************* 1013 *********************************************************************/ 1014 bool 1015 OSMetaClass::removeClasses(OSCollection * metaClasses) 1016 { 1017 OSCollectionIterator * classIterator; 1018 OSMetaClass * checkClass; 1019 bool result; 1020 1021 classIterator = OSCollectionIterator::withCollection(metaClasses); 1022 if (!classIterator) return (false); 1023 1024 IOLockLock(sAllClassesLock); 1025 1026 result = false; 1027 do 1028 { 1029 while ((checkClass = (OSMetaClass *)classIterator->getNextObject()) 1030 && !checkClass->getInstanceCount() 1031 && !checkClass->reserved->retain) {} 1032 if (checkClass) break; 1033 classIterator->reset(); 1034 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) 1035 { 1036 sAllClassesDict->removeObject(checkClass->className); 1037 } 1038 result = true; 1039 } 1040 while (false); 1041 1042 IOLockUnlock(sAllClassesLock); 1043 OSSafeReleaseNULL(classIterator); 1044 1045 return (result); 1046 } 1047 1048 1049 /********************************************************************* 1050 *********************************************************************/ 1051 const OSMetaClass * 1052 OSMetaClass::getMetaClassWithName(const OSSymbol * name) 1053 { 1054 OSMetaClass * retMeta = 0; 1055 1056 if (!name) { 1057 return 0; 1058 } 1059 1060 IOLockLock(sAllClassesLock); 1061 if (sAllClassesDict) { 1062 retMeta = (OSMetaClass *) sAllClassesDict->getObject(name); 1063 } 1064 IOLockUnlock(sAllClassesLock); 1065 1066 return retMeta; 1067 } 1068 1069 /********************************************************************* 1070 *********************************************************************/ 1071 const OSMetaClass * 1072 OSMetaClass::copyMetaClassWithName(const OSSymbol * name) 1073 { 1074 const OSMetaClass * meta; 1075 1076 if (!name) return (0); 1077 1078 meta = 0; 1079 IOLockLock(sAllClassesLock); 1080 if (sAllClassesDict) { 1081 meta = (OSMetaClass *) sAllClassesDict->getObject(name); 1082 if (meta) OSIncrementAtomic(&meta->reserved->retain); 1083 } 1084 IOLockUnlock(sAllClassesLock); 1085 1086 return (meta); 1087 } 1088 1089 /********************************************************************* 1090 *********************************************************************/ 1091 void 1092 OSMetaClass::releaseMetaClass() const 1093 { 1094 OSDecrementAtomic(&reserved->retain); 1095 } 1096 1097 /********************************************************************* 1098 *********************************************************************/ 1099 OSObject * 1100 OSMetaClass::allocClassWithName(const OSSymbol * name) 1101 { 1102 const OSMetaClass * meta; 1103 OSObject * result; 1104 1105 result = 0; 1106 meta = copyMetaClassWithName(name); 1107 if (meta) 1108 { 1109 result = meta->alloc(); 1110 meta->releaseMetaClass(); 1111 } 1112 1113 return result; 1114 } 1115 1116 /********************************************************************* 1117 *********************************************************************/ 1118 OSObject * 1119 OSMetaClass::allocClassWithName(const OSString * name) 1120 { 1121 const OSSymbol * tmpKey = OSSymbol::withString(name); 1122 OSObject * result = allocClassWithName(tmpKey); 1123 tmpKey->release(); 1124 return result; 1125 } 1126 1127 /********************************************************************* 1128 *********************************************************************/ 1129 OSObject * 1130 OSMetaClass::allocClassWithName(const char * name) 1131 { 1132 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name); 1133 OSObject * result = allocClassWithName(tmpKey); 1134 tmpKey->release(); 1135 return result; 1136 } 1137 1138 1139 /********************************************************************* 1140 *********************************************************************/ 1141 OSMetaClassBase * 1142 OSMetaClass::checkMetaCastWithName( 1143 const OSSymbol * name, 1144 const OSMetaClassBase * in) 1145 { 1146 OSMetaClassBase * result = 0; 1147 1148 const OSMetaClass * const meta = getMetaClassWithName(name); 1149 1150 if (meta) { 1151 result = meta->checkMetaCast(in); 1152 } 1153 1154 return result; 1155 } 1156 1157 /********************************************************************* 1158 *********************************************************************/ 1159 OSMetaClassBase * OSMetaClass:: 1160 checkMetaCastWithName( 1161 const OSString * name, 1162 const OSMetaClassBase * in) 1163 { 1164 const OSSymbol * tmpKey = OSSymbol::withString(name); 1165 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in); 1166 1167 tmpKey->release(); 1168 return result; 1169 } 1170 1171 /********************************************************************* 1172 *********************************************************************/ 1173 OSMetaClassBase * 1174 OSMetaClass::checkMetaCastWithName( 1175 const char * name, 1176 const OSMetaClassBase * in) 1177 { 1178 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name); 1179 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in); 1180 1181 tmpKey->release(); 1182 return result; 1183 } 1184 1185 /********************************************************************* 1186 * OSMetaClass::checkMetaCast() 1187 * Check to see if the 'check' object has this object in its metaclass chain. 1188 * Returns check if it is indeed a kind of the current meta class, 0 otherwise. 1189 * 1190 * Generally this method is not invoked directly but is used to implement 1191 * the OSMetaClassBase::metaCast member function. 1192 * 1193 * See also OSMetaClassBase::metaCast 1194 *********************************************************************/ 1195 OSMetaClassBase * OSMetaClass::checkMetaCast( 1196 const OSMetaClassBase * check) const 1197 { 1198 const OSMetaClass * const toMeta = this; 1199 const OSMetaClass * fromMeta; 1200 1201 for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) { 1202 if (toMeta == fromMeta) { 1203 return const_cast<OSMetaClassBase *>(check); // Discard const 1204 } 1205 if (!fromMeta->superClassLink) { 1206 break; 1207 } 1208 } 1209 1210 return 0; 1211 } 1212 1213 /********************************************************************* 1214 *********************************************************************/ 1215 void 1216 OSMetaClass::reservedCalled(int ind) const 1217 { 1218 const char * cname = className->getCStringNoCopy(); 1219 panic("%s::_RESERVED%s%d called.", cname, cname, ind); 1220 } 1221 1222 /********************************************************************* 1223 *********************************************************************/ 1224 const 1225 OSMetaClass * 1226 OSMetaClass::getSuperClass() const 1227 { 1228 return superClassLink; 1229 } 1230 1231 /********************************************************************* 1232 * xxx - I want to rename this :-/ 1233 *********************************************************************/ 1234 const OSSymbol * 1235 OSMetaClass::getKmodName() const 1236 { 1237 OSKext * myKext = reserved ? reserved->kext : 0; 1238 if (myKext) { 1239 return myKext->getIdentifier(); 1240 } 1241 return OSSymbol::withCStringNoCopy("unknown"); 1242 } 1243 1244 /********************************************************************* 1245 *********************************************************************/ 1246 unsigned int 1247 OSMetaClass::getInstanceCount() const 1248 { 1249 return instanceCount; 1250 } 1251 1252 /********************************************************************* 1253 *********************************************************************/ 1254 /* static */ 1255 void 1256 OSMetaClass::printInstanceCounts() 1257 { 1258 OSCollectionIterator * classes; 1259 OSSymbol * className; 1260 OSMetaClass * meta; 1261 1262 IOLockLock(sAllClassesLock); 1263 classes = OSCollectionIterator::withCollection(sAllClassesDict); 1264 assert(classes); 1265 1266 while( (className = (OSSymbol *)classes->getNextObject())) { 1267 meta = (OSMetaClass *)sAllClassesDict->getObject(className); 1268 assert(meta); 1269 1270 printf("%24s count: %03d x 0x%03x = 0x%06x\n", 1271 className->getCStringNoCopy(), 1272 meta->getInstanceCount(), 1273 meta->getClassSize(), 1274 meta->getInstanceCount() * meta->getClassSize() ); 1275 } 1276 printf("\n"); 1277 classes->release(); 1278 IOLockUnlock(sAllClassesLock); 1279 return; 1280 } 1281 1282 /********************************************************************* 1283 *********************************************************************/ 1284 OSDictionary * 1285 OSMetaClass::getClassDictionary() 1286 { 1287 panic("OSMetaClass::getClassDictionary() is obsoleted.\n"); 1288 return 0; 1289 } 1290 1291 /********************************************************************* 1292 *********************************************************************/ 1293 bool 1294 OSMetaClass::serialize(__unused OSSerialize * s) const 1295 { 1296 panic("OSMetaClass::serialize(): Obsoleted\n"); 1297 return false; 1298 } 1299 1300 /********************************************************************* 1301 *********************************************************************/ 1302 /* static */ 1303 void 1304 OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary) 1305 { 1306 OSDictionary * classDict = NULL; 1307 1308 IOLockLock(sAllClassesLock); 1309 1310 classDict = OSDictionary::withCapacity(sAllClassesDict->getCount()); 1311 if (!classDict) { 1312 goto finish; 1313 } 1314 1315 do { 1316 OSCollectionIterator * classes; 1317 const OSSymbol * className; 1318 1319 classes = OSCollectionIterator::withCollection(sAllClassesDict); 1320 if (!classes) { 1321 break; 1322 } 1323 1324 while ((className = (const OSSymbol *)classes->getNextObject())) { 1325 const OSMetaClass * meta; 1326 OSNumber * count; 1327 1328 meta = (OSMetaClass *)sAllClassesDict->getObject(className); 1329 count = OSNumber::withNumber(meta->getInstanceCount(), 32); 1330 if (count) { 1331 classDict->setObject(className, count); 1332 count->release(); 1333 } 1334 } 1335 classes->release(); 1336 1337 serializeDictionary->setObject("Classes", classDict); 1338 } while (0); 1339 1340 finish: 1341 OSSafeReleaseNULL(classDict); 1342 1343 IOLockUnlock(sAllClassesLock); 1344 1345 return; 1346 } 1347 1348 1349 /********************************************************************* 1350 *********************************************************************/ 1351 1352 #if IOTRACKING 1353 1354 void *OSMetaClass::trackedNew(size_t size) 1355 { 1356 IOTracking * mem; 1357 1358 mem = (typeof(mem)) kalloc_tag_bt(size + sizeof(IOTracking), VM_KERN_MEMORY_LIBKERN); 1359 assert(mem); 1360 if (!mem) return (mem); 1361 1362 memset(mem, 0, size + sizeof(IOTracking)); 1363 mem++; 1364 1365 OSIVAR_ACCUMSIZE(size); 1366 1367 return (mem); 1368 } 1369 1370 void OSMetaClass::trackedDelete(void * instance, size_t size) 1371 { 1372 IOTracking * mem = (typeof(mem)) instance; mem--; 1373 1374 kfree(mem, size + sizeof(IOTracking)); 1375 OSIVAR_ACCUMSIZE(-size); 1376 } 1377 1378 void OSMetaClass::trackedInstance(OSObject * instance) const 1379 { 1380 IOTracking * mem = (typeof(mem)) instance; mem--; 1381 1382 return (IOTrackingAdd(reserved->tracking, mem, classSize, false, VM_KERN_MEMORY_NONE)); 1383 } 1384 1385 void OSMetaClass::trackedFree(OSObject * instance) const 1386 { 1387 IOTracking * mem = (typeof(mem)) instance; mem--; 1388 1389 return (IOTrackingRemove(reserved->tracking, mem, classSize)); 1390 } 1391 1392 void OSMetaClass::trackedAccumSize(OSObject * instance, size_t size) const 1393 { 1394 IOTracking * mem = (typeof(mem)) instance; mem--; 1395 1396 return (IOTrackingAccumSize(reserved->tracking, mem, size)); 1397 } 1398 1399 IOTrackingQueue * OSMetaClass::getTracking() const 1400 { 1401 return (reserved->tracking); 1402 } 1403 1404 #endif /* IOTRACKING */ 1405