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