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