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*********************************************************************/
78OSKextLogSpec kOSMetaClassLogSpec =
79 kOSKextLogErrorLevel |
80 kOSKextLogLoadFlag |
81 kOSKextLogKextBookkeepingFlag;
82
83static enum {
84 kCompletedBootstrap = 0,
85 kNoDictionaries = 1,
86 kMakingDictionaries = 2
87} sBootstrapState = kNoDictionaries;
88
89static const int kClassCapacityIncrement = 40;
90static const int kKModCapacityIncrement = 10;
91static OSDictionary * sAllClassesDict;
92static unsigned int sDeepestClass;
93IOLock * sAllClassesLock = NULL;
94IOLock * 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 */
101static struct StalledData {
102 const char * kextIdentifier;
103 OSReturn result;
104 unsigned int capacity;
105 unsigned int count;
106 OSMetaClass ** classes;
107} * sStalled;
108IOLock * sStalledClassesLock = NULL;
109
110struct 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
132void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
133 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); }
134void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
135 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); }
136void 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
141void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
142 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); }
143void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
144 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); }
145void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
146 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); }
147void 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/*
160IHI0059A "C++ Application Binary Interface Standard for the ARM 64 - bit Architecture":
161
1623.2.1 Representation of pointer to member function The generic C++ ABI [GC++ABI]
163specifies that a pointer to member function is a pair of words <ptr, adj>. The
164least significant bit of ptr discriminates between (0) the address of a non-
165virtual member function and (1) the offset in the class's virtual table of the
166address of a virtual function. This encoding cannot work for the AArch64
167instruction set where the architecture reserves all bits of code addresses. This
168ABI specifies that adj contains twice the this adjustment, plus 1 if the member
169function is virtual. The least significant bit of adj then makes exactly the
170same discrimination as the least significant bit of ptr does for Itanium. A
171pointer to member function is NULL when ptr = 0 and the least significant bit of
172adj is zero.
173*/
174
175OSMetaClassBase::_ptf_t
176OSMetaClassBase::_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*********************************************************************/
221OSMetaClassBase *
222OSMetaClassBase::safeMetaCast(
223 const OSMetaClassBase * me,
224 const OSMetaClass * toType)
225{
226 return (me)? me->metaCast(toType) : 0;
227}
228
229/*********************************************************************
230*********************************************************************/
231bool
232OSMetaClassBase::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*********************************************************************/
242void OSMetaClassBase::
243initialize()
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*********************************************************************/
256void
257OSMetaClassBase::_RESERVEDOSMetaClassBase7()
258{ panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
259#endif
260
261/*********************************************************************
262*********************************************************************/
263OSMetaClassBase::OSMetaClassBase()
264{
265}
266
267/*********************************************************************
268*********************************************************************/
269OSMetaClassBase::~OSMetaClassBase()
270{
271 void ** thisVTable;
272
273 thisVTable = (void **) this;
274 *thisVTable = (void *) -1UL;
275}
276
277/*********************************************************************
278*********************************************************************/
279bool
280OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const
281{
282 return this == anObj;
283}
284
285/*********************************************************************
286*********************************************************************/
287OSMetaClassBase *
288OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const
289{
290 return toMeta->checkMetaCast(this);
291}
292
293/*********************************************************************
294*********************************************************************/
295OSMetaClassBase *
296OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const
297{
298 return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
299}
300
301/*********************************************************************
302*********************************************************************/
303OSMetaClassBase *
304OSMetaClassBase::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*********************************************************************/
317OSMetaClassBase *
318OSMetaClassBase::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*********************************************************************/
335class OSMetaClassMeta : public OSMetaClass
336{
337public:
338 OSMetaClassMeta();
339 OSObject * alloc() const;
340};
341OSMetaClassMeta::OSMetaClassMeta()
342 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
343 { }
344OSObject * OSMetaClassMeta::alloc() const { return 0; }
345
346static OSMetaClassMeta sOSMetaClassMeta;
347
348const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
349const 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*********************************************************************/
363void OSMetaClass::_RESERVEDOSMetaClass0()
364 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); }
365void OSMetaClass::_RESERVEDOSMetaClass1()
366 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); }
367void OSMetaClass::_RESERVEDOSMetaClass2()
368 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); }
369void OSMetaClass::_RESERVEDOSMetaClass3()
370 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); }
371void OSMetaClass::_RESERVEDOSMetaClass4()
372 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); }
373void OSMetaClass::_RESERVEDOSMetaClass5()
374 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); }
375void OSMetaClass::_RESERVEDOSMetaClass6()
376 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
377void OSMetaClass::_RESERVEDOSMetaClass7()
378 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
379#endif
380
381/*********************************************************************
382*********************************************************************/
383static void
384OSMetaClassLogErrorForKext(
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
429void
430OSMetaClass::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*********************************************************************/
444OSMetaClass::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*********************************************************************/
512OSMetaClass::~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*********************************************************************/
575void OSMetaClass::retain() const { }
576void OSMetaClass::release() const { }
577void OSMetaClass::release(__unused int when) const { }
578void OSMetaClass::taggedRetain(__unused const void * tag) const { }
579void OSMetaClass::taggedRelease(__unused const void * tag) const { }
580void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { }
581int OSMetaClass::getRetainCount() const { return 0; }
582
583/*********************************************************************
584*********************************************************************/
585const char *
586OSMetaClass::getClassName() const
587{
588 if (!className) return NULL;
589 return className->getCStringNoCopy();
590}
591/*********************************************************************
592*********************************************************************/
593const OSSymbol *
594OSMetaClass::getClassNameSymbol() const
595{
596 return className;
597}
598/*********************************************************************
599*********************************************************************/
600unsigned int
601OSMetaClass::getClassSize() const
602{
603 return classSize;
604}
605
606/*********************************************************************
607*********************************************************************/
608void *
609OSMetaClass::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*********************************************************************/
639bool
640OSMetaClass::checkModLoad(void * loadHandle)
641{
642 return sStalled && loadHandle == sStalled &&
643 sStalled->result == kOSReturnSuccess;
644}
645
646/*********************************************************************
647*********************************************************************/
648OSReturn
649OSMetaClass::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
781finish:
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*********************************************************************/
812void
813OSMetaClass::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*********************************************************************/
823void
824OSMetaClass::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*********************************************************************/
842bool
843OSMetaClass::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
855finish:
856 OSSafeReleaseNULL(theKext);
857 return result;
858}
859
860/*********************************************************************
861*********************************************************************/
862void
863OSMetaClass::reportModInstances(const char * kextIdentifier)
864{
865 OSKext::reportOSMetaClassInstances(kextIdentifier,
866 kOSKextLogExplicitLevel);
867 return;
868}
869/*********************************************************************
870*********************************************************************/
871
872void
873OSMetaClass::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
888void
889OSMetaClass::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
909void
910OSMetaClass::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
969void
970OSMetaClass::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
978void
979OSMetaClass::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*********************************************************************/
1006void
1007OSMetaClass::considerUnloads()
1008{
1009 OSKext::considerUnloads();
1010}
1011
1012/*********************************************************************
1013*********************************************************************/
1014bool
1015OSMetaClass::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*********************************************************************/
1051const OSMetaClass *
1052OSMetaClass::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*********************************************************************/
1071const OSMetaClass *
1072OSMetaClass::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*********************************************************************/
1091void
1092OSMetaClass::releaseMetaClass() const
1093{
1094 OSDecrementAtomic(&reserved->retain);
1095}
1096
1097/*********************************************************************
1098*********************************************************************/
1099OSObject *
1100OSMetaClass::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*********************************************************************/
1118OSObject *
1119OSMetaClass::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*********************************************************************/
1129OSObject *
1130OSMetaClass::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*********************************************************************/
1141OSMetaClassBase *
1142OSMetaClass::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*********************************************************************/
1159OSMetaClassBase * OSMetaClass::
1160checkMetaCastWithName(
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*********************************************************************/
1173OSMetaClassBase *
1174OSMetaClass::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*********************************************************************/
1195OSMetaClassBase * 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*********************************************************************/
1215void
1216OSMetaClass::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*********************************************************************/
1224const
1225OSMetaClass *
1226OSMetaClass::getSuperClass() const
1227{
1228 return superClassLink;
1229}
1230
1231/*********************************************************************
1232* xxx - I want to rename this :-/
1233*********************************************************************/
1234const OSSymbol *
1235OSMetaClass::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*********************************************************************/
1246unsigned int
1247OSMetaClass::getInstanceCount() const
1248{
1249 return instanceCount;
1250}
1251
1252/*********************************************************************
1253*********************************************************************/
1254/* static */
1255void
1256OSMetaClass::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*********************************************************************/
1284OSDictionary *
1285OSMetaClass::getClassDictionary()
1286{
1287 panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
1288 return 0;
1289}
1290
1291/*********************************************************************
1292*********************************************************************/
1293bool
1294OSMetaClass::serialize(__unused OSSerialize * s) const
1295{
1296 panic("OSMetaClass::serialize(): Obsoleted\n");
1297 return false;
1298}
1299
1300/*********************************************************************
1301*********************************************************************/
1302/* static */
1303void
1304OSMetaClass::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
1340finish:
1341 OSSafeReleaseNULL(classDict);
1342
1343 IOLockUnlock(sAllClassesLock);
1344
1345 return;
1346}
1347
1348
1349/*********************************************************************
1350*********************************************************************/
1351
1352#if IOTRACKING
1353
1354void *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
1370void 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
1378void 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
1385void OSMetaClass::trackedFree(OSObject * instance) const
1386{
1387 IOTracking * mem = (typeof(mem)) instance; mem--;
1388
1389 return (IOTrackingRemove(reserved->tracking, mem, classSize));
1390}
1391
1392void 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
1399IOTrackingQueue * OSMetaClass::getTracking() const
1400{
1401 return (reserved->tracking);
1402}
1403
1404#endif /* IOTRACKING */
1405