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