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