xref: /xnu-11215/libkern/c++/OSMetaClass.cpp (revision 76e12aa3)
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