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