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