]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOCatalogue.cpp
xnu-6153.121.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
1 /*
2 * Copyright (c) 1998-2012 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 /*
29 * Copyright (c) 1998 Apple Inc. All rights reserved.
30 *
31 * HISTORY
32 *
33 */
34 /*
35 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
36 * support for mandatory and extensible security protections. This notice
37 * is included in support of clause 2.2 (b) of the Apple Public License,
38 * Version 2.0.
39 */
40
41 extern "C" {
42 #include <machine/machine_routines.h>
43 #include <libkern/kernel_mach_header.h>
44 #include <kern/host.h>
45 #include <security/mac_data.h>
46 };
47
48 #include <libkern/c++/OSContainers.h>
49 #include <libkern/c++/OSUnserialize.h>
50 #include <libkern/c++/OSKext.h>
51 #include <libkern/OSKextLibPrivate.h>
52 #include <libkern/OSDebug.h>
53
54 #include <IOKit/IODeviceTreeSupport.h>
55 #include <IOKit/IOService.h>
56 #include <IOKit/IOCatalogue.h>
57
58 #include <IOKit/IOLib.h>
59 #include <IOKit/assert.h>
60
61 #if PRAGMA_MARK
62 #pragma mark Internal Declarations
63 #endif
64 /*********************************************************************
65 *********************************************************************/
66
67 IOCatalogue * gIOCatalogue;
68 const OSSymbol * gIOClassKey;
69 const OSSymbol * gIOProbeScoreKey;
70 const OSSymbol * gIOModuleIdentifierKey;
71 const OSSymbol * gIOModuleIdentifierKernelKey;
72 IORWLock * gIOCatalogLock;
73
74 #if PRAGMA_MARK
75 #pragma mark Utility functions
76 #endif
77
78 #if PRAGMA_MARK
79 #pragma mark IOCatalogue class implementation
80 #endif
81 /*********************************************************************
82 *********************************************************************/
83
84 #define super OSObject
85 OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
86
87 static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
88 OSDictionary *theModuleDict);
89
90
91 /*********************************************************************
92 *********************************************************************/
93 void
94 IOCatalogue::initialize(void)
95 {
96 OSArray * array;
97 OSString * errorString;
98 bool rc;
99
100 extern const char * gIOKernelConfigTables;
101
102 array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
103 if (!array && errorString) {
104 IOLog("KernelConfigTables syntax error: %s\n",
105 errorString->getCStringNoCopy());
106 errorString->release();
107 }
108
109 gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
110 gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
111 gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
112 gIOModuleIdentifierKernelKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKernelKey );
113
114
115 assert( array && gIOClassKey && gIOProbeScoreKey
116 && gIOModuleIdentifierKey);
117
118 gIOCatalogue = new IOCatalogue;
119 assert(gIOCatalogue);
120 rc = gIOCatalogue->init(array);
121 assert(rc);
122 array->release();
123 }
124
125 /*********************************************************************
126 * Initialize the IOCatalog object.
127 *********************************************************************/
128 OSArray *
129 IOCatalogue::arrayForPersonality(OSDictionary * dict)
130 {
131 const OSSymbol * sym;
132
133 sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
134 if (!sym) {
135 return NULL;
136 }
137
138 return (OSArray *) personalities->getObject(sym);
139 }
140
141 void
142 IOCatalogue::addPersonality(OSDictionary * dict)
143 {
144 const OSSymbol * sym;
145 OSArray * arr;
146
147 sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
148 if (!sym) {
149 return;
150 }
151 arr = (OSArray *) personalities->getObject(sym);
152 if (arr) {
153 arr->setObject(dict);
154 } else {
155 arr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
156 personalities->setObject(sym, arr);
157 arr->release();
158 }
159 }
160
161 /*********************************************************************
162 * Initialize the IOCatalog object.
163 *********************************************************************/
164 bool
165 IOCatalogue::init(OSArray * initArray)
166 {
167 OSDictionary * dict;
168 OSObject * obj;
169
170 if (!super::init()) {
171 return false;
172 }
173
174 generation = 1;
175
176 personalities = OSDictionary::withCapacity(32);
177 personalities->setOptions(OSCollection::kSort, OSCollection::kSort);
178 for (unsigned int idx = 0; (obj = initArray->getObject(idx)); idx++) {
179 dict = OSDynamicCast(OSDictionary, obj);
180 if (!dict) {
181 continue;
182 }
183 OSKext::uniquePersonalityProperties(dict);
184 if (NULL == dict->getObject( gIOClassKey )) {
185 IOLog("Missing or bad \"%s\" key\n",
186 gIOClassKey->getCStringNoCopy());
187 continue;
188 }
189 dict->setObject("KernelConfigTable", kOSBooleanTrue);
190 addPersonality(dict);
191 }
192
193 gIOCatalogLock = IORWLockAlloc();
194 lock = gIOCatalogLock;
195
196 return true;
197 }
198
199 /*********************************************************************
200 * Release all resources used by IOCatalogue and deallocate.
201 * This will probably never be called.
202 *********************************************************************/
203 void
204 IOCatalogue::free( void )
205 {
206 panic("");
207 }
208
209 /*********************************************************************
210 *********************************************************************/
211 OSOrderedSet *
212 IOCatalogue::findDrivers(
213 IOService * service,
214 SInt32 * generationCount)
215 {
216 OSDictionary * nextTable;
217 OSOrderedSet * set;
218 OSArray * array;
219 const OSMetaClass * meta;
220 unsigned int idx;
221
222 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
223 (void *)gIOProbeScoreKey );
224 if (!set) {
225 return NULL;
226 }
227
228 IORWLockRead(lock);
229
230 meta = service->getMetaClass();
231 while (meta) {
232 array = (OSArray *) personalities->getObject(meta->getClassNameSymbol());
233 if (array) {
234 for (idx = 0; (nextTable = (OSDictionary *) array->getObject(idx)); idx++) {
235 set->setObject(nextTable);
236 }
237 }
238 if (meta == &IOService::gMetaClass) {
239 break;
240 }
241 meta = meta->getSuperClass();
242 }
243
244 *generationCount = getGenerationCount();
245
246 IORWLockUnlock(lock);
247
248 return set;
249 }
250
251 /*********************************************************************
252 * Is personality already in the catalog?
253 *********************************************************************/
254 OSOrderedSet *
255 IOCatalogue::findDrivers(
256 OSDictionary * matching,
257 SInt32 * generationCount)
258 {
259 OSCollectionIterator * iter;
260 OSDictionary * dict;
261 OSOrderedSet * set;
262 OSArray * array;
263 const OSSymbol * key;
264 unsigned int idx;
265
266 OSKext::uniquePersonalityProperties(matching);
267
268 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
269 (void *)gIOProbeScoreKey );
270 if (!set) {
271 return NULL;
272 }
273 iter = OSCollectionIterator::withCollection(personalities);
274 if (!iter) {
275 set->release();
276 return NULL;
277 }
278
279 IORWLockRead(lock);
280 while ((key = (const OSSymbol *) iter->getNextObject())) {
281 array = (OSArray *) personalities->getObject(key);
282 if (array) {
283 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
284 /* This comparison must be done with only the keys in the
285 * "matching" dict to enable general searches.
286 */
287 if (dict->isEqualTo(matching, matching)) {
288 set->setObject(dict);
289 }
290 }
291 }
292 }
293 *generationCount = getGenerationCount();
294 IORWLockUnlock(lock);
295
296 iter->release();
297 return set;
298 }
299
300 /*********************************************************************
301 * Add driver config tables to catalog and start matching process.
302 *
303 * Important that existing personalities are kept (not replaced)
304 * if duplicates found. Personalities can come from OSKext objects
305 * or from userland kext library. We want to minimize distinct
306 * copies between OSKext & IOCatalogue.
307 *
308 * xxx - userlib used to refuse to send personalities with IOKitDebug
309 * xxx - during safe boot. That would be better implemented here.
310 *********************************************************************/
311
312 bool
313 IOCatalogue::addDrivers(
314 OSArray * drivers,
315 bool doNubMatching)
316 {
317 bool result = false;
318 OSCollectionIterator * iter = NULL; // must release
319 OSOrderedSet * set = NULL; // must release
320 OSObject * object = NULL; // do not release
321 OSArray * persons = NULL;// do not release
322
323 persons = OSDynamicCast(OSArray, drivers);
324 if (!persons) {
325 goto finish;
326 }
327
328 set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
329 (void *)gIOProbeScoreKey );
330 if (!set) {
331 goto finish;
332 }
333
334 iter = OSCollectionIterator::withCollection(persons);
335 if (!iter) {
336 goto finish;
337 }
338
339 /* Start with success; clear it on an error.
340 */
341 result = true;
342
343 IORWLockWrite(lock);
344 while ((object = iter->getNextObject())) {
345 // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
346
347 OSDictionary * personality = OSDynamicCast(OSDictionary, object);
348
349 SInt count;
350
351 if (!personality) {
352 IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
353 result = false;
354 break;
355 }
356
357 OSKext::uniquePersonalityProperties(personality);
358
359 // Add driver personality to catalogue.
360
361 OSArray * array = arrayForPersonality(personality);
362 if (!array) {
363 addPersonality(personality);
364 } else {
365 count = array->getCount();
366 while (count--) {
367 OSDictionary * driver;
368
369 // Be sure not to double up on personalities.
370 driver = (OSDictionary *)array->getObject(count);
371
372 /* Unlike in other functions, this comparison must be exact!
373 * The catalogue must be able to contain personalities that
374 * are proper supersets of others.
375 * Do not compare just the properties present in one driver
376 * personality or the other.
377 */
378 if (personality->isEqualTo(driver)) {
379 break;
380 }
381 }
382 if (count >= 0) {
383 // its a dup
384 continue;
385 }
386 result = array->setObject(personality);
387 if (!result) {
388 break;
389 }
390 }
391
392 set->setObject(personality);
393 }
394 // Start device matching.
395 if (result && doNubMatching && (set->getCount() > 0)) {
396 IOService::catalogNewDrivers(set);
397 generation++;
398 }
399 IORWLockUnlock(lock);
400
401 finish:
402 if (set) {
403 set->release();
404 }
405 if (iter) {
406 iter->release();
407 }
408
409 return result;
410 }
411
412 /*********************************************************************
413 * Remove drivers from the catalog which match the
414 * properties in the matching dictionary.
415 *********************************************************************/
416 bool
417 IOCatalogue::removeDrivers(
418 OSDictionary * matching,
419 bool doNubMatching)
420 {
421 OSOrderedSet * set;
422 OSCollectionIterator * iter;
423 OSDictionary * dict;
424 OSArray * array;
425 const OSSymbol * key;
426 unsigned int idx;
427
428 if (!matching) {
429 return false;
430 }
431
432 set = OSOrderedSet::withCapacity(10,
433 IOServiceOrdering,
434 (void *)gIOProbeScoreKey);
435 if (!set) {
436 return false;
437 }
438 iter = OSCollectionIterator::withCollection(personalities);
439 if (!iter) {
440 set->release();
441 return false;
442 }
443
444 IORWLockWrite(lock);
445 while ((key = (const OSSymbol *) iter->getNextObject())) {
446 array = (OSArray *) personalities->getObject(key);
447 if (array) {
448 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
449 /* This comparison must be done with only the keys in the
450 * "matching" dict to enable general searches.
451 */
452 if (dict->isEqualTo(matching, matching)) {
453 set->setObject(dict);
454 array->removeObject(idx);
455 idx--;
456 }
457 }
458 }
459 // Start device matching.
460 if (doNubMatching && (set->getCount() > 0)) {
461 IOService::catalogNewDrivers(set);
462 generation++;
463 }
464 }
465 IORWLockUnlock(lock);
466
467 set->release();
468 iter->release();
469
470 return true;
471 }
472
473 // Return the generation count.
474 SInt32
475 IOCatalogue::getGenerationCount(void) const
476 {
477 return generation;
478 }
479
480 // Check to see if kernel module has been loaded already, and request its load.
481 bool
482 IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
483 {
484 OSString * moduleName = NULL;
485 OSString * publisherName = NULL;
486 OSReturn ret;
487
488 if (kextRef) {
489 *kextRef = NULL;
490 }
491 if (!driver) {
492 return false;
493 }
494
495 /* The personalities of codeless kexts often contain the bundle ID of the
496 * kext they reference, and not the bundle ID of the codeless kext itself.
497 * The prelinked kernel needs to know the bundle ID of the codeless kext
498 * so it can include these personalities, so OSKext stores that bundle ID
499 * in the IOPersonalityPublisher key, and we record it as requested here.
500 */
501 publisherName = OSDynamicCast(OSString,
502 driver->getObject(kIOPersonalityPublisherKey));
503 OSKext::recordIdentifierRequest(publisherName);
504
505 moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey));
506 if (moduleName) {
507 ret = OSKext::loadKextWithIdentifier(moduleName, kextRef);
508 if (kOSKextReturnDeferred == ret) {
509 // a request has been queued but the module isn't necessarily
510 // loaded yet, so stall.
511 return false;
512 }
513 OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
514 if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) {
515 OSObject *dextRef = NULL;
516 ret = OSKext::loadKextWithIdentifier(moduleDextName, &dextRef);
517 OSSafeReleaseNULL(dextRef);
518 }
519 // module is present or never will be
520 return true;
521 }
522
523 /* If a personality doesn't hold the "CFBundleIdentifier" or "CFBundleIdentifierKernel" key
524 * it is assumed to be an "in-kernel" driver.
525 */
526 return true;
527 }
528
529 /* This function is called after a module has been loaded.
530 * Is invoked from user client call, ultimately from IOKitLib's
531 * IOCatalogueModuleLoaded(). Sent from kextd.
532 */
533 void
534 IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName)
535 {
536 startMatching(moduleName);
537
538 (void) OSKext::setDeferredLoadSucceeded();
539 (void) OSKext::considerRebuildOfPrelinkedKernel();
540 }
541
542 void
543 IOCatalogue::moduleHasLoaded(const char * moduleName)
544 {
545 const OSSymbol * name;
546
547 name = OSSymbol::withCString(moduleName);
548 moduleHasLoaded(name);
549 name->release();
550 }
551
552 // xxx - return is really OSReturn/kern_return_t
553 IOReturn
554 IOCatalogue::unloadModule(OSString * moduleName) const
555 {
556 return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
557 }
558
559 IOReturn
560 IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className)
561 {
562 OSDictionary * dict;
563 OSIterator * iter;
564 IOService * service;
565 IOReturn ret;
566
567 ret = kIOReturnSuccess;
568 dict = NULL;
569 iter = IORegistryIterator::iterateOver(gIOServicePlane,
570 kIORegistryIterateRecursively);
571 if (!iter) {
572 return kIOReturnNoMemory;
573 }
574
575 if (matching) {
576 OSKext::uniquePersonalityProperties( matching );
577 }
578
579 // terminate instances.
580 do {
581 iter->reset();
582 while ((service = (IOService *)iter->getNextObject())) {
583 if (className && !service->metaCast(className)) {
584 continue;
585 }
586 if (matching) {
587 /* Terminate only for personalities that match the matching dictionary.
588 * This comparison must be done with only the keys in the
589 * "matching" dict to enable general matching.
590 */
591 dict = service->getPropertyTable();
592 if (!dict) {
593 continue;
594 }
595 if (!dict->isEqualTo(matching, matching)) {
596 continue;
597 }
598 }
599
600 OSKext * kext;
601 const char * bundleIDStr;
602 OSObject * prop;
603 bool okToTerminate;
604 for (okToTerminate = true;;) {
605 kext = service->getMetaClass()->getKext();
606 if (!kext) {
607 break;
608 }
609 bundleIDStr = kext->getIdentifierCString();
610 if (!bundleIDStr) {
611 break;
612 }
613 prop = kext->getPropertyForHostArch(kOSBundleAllowUserTerminateKey);
614 if (prop) {
615 okToTerminate = (kOSBooleanTrue == prop);
616 break;
617 }
618 if (!strcmp(kOSKextKernelIdentifier, bundleIDStr)) {
619 okToTerminate = false;
620 break;
621 }
622 if (!strncmp("com.apple.", bundleIDStr, strlen("com.apple."))) {
623 okToTerminate = false;
624 break;
625 }
626 break;
627 }
628 if (!okToTerminate) {
629 #if DEVELOPMENT || DEBUG
630 okToTerminate = true;
631 #endif /* DEVELOPMENT || DEBUG */
632 IOLog("%sallowing kextunload terminate for bundleID %s\n",
633 okToTerminate ? "" : "dis", bundleIDStr ? bundleIDStr : "?");
634 if (!okToTerminate) {
635 ret = kIOReturnUnsupported;
636 break;
637 }
638 }
639 if (!service->terminate(kIOServiceRequired | kIOServiceSynchronous)) {
640 ret = kIOReturnUnsupported;
641 break;
642 }
643 }
644 } while (!service && !iter->isValid());
645 iter->release();
646
647 return ret;
648 }
649
650 IOReturn
651 IOCatalogue::_removeDrivers(OSDictionary * matching)
652 {
653 IOReturn ret = kIOReturnSuccess;
654 OSCollectionIterator * iter;
655 OSDictionary * dict;
656 OSArray * array;
657 const OSSymbol * key;
658 unsigned int idx;
659
660 // remove configs from catalog.
661
662 iter = OSCollectionIterator::withCollection(personalities);
663 if (!iter) {
664 return kIOReturnNoMemory;
665 }
666
667 while ((key = (const OSSymbol *) iter->getNextObject())) {
668 array = (OSArray *) personalities->getObject(key);
669 if (array) {
670 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
671 /* Remove from the catalogue's array any personalities
672 * that match the matching dictionary.
673 * This comparison must be done with only the keys in the
674 * "matching" dict to enable general matching.
675 */
676 if (dict->isEqualTo(matching, matching)) {
677 array->removeObject(idx);
678 idx--;
679 }
680 }
681 }
682 }
683 iter->release();
684
685 return ret;
686 }
687
688 IOReturn
689 IOCatalogue::terminateDrivers(OSDictionary * matching)
690 {
691 IOReturn ret;
692
693 if (!matching) {
694 return kIOReturnBadArgument;
695 }
696 ret = terminateDrivers(matching, NULL);
697 IORWLockWrite(lock);
698 if (kIOReturnSuccess == ret) {
699 ret = _removeDrivers(matching);
700 }
701 IORWLockUnlock(lock);
702
703 return ret;
704 }
705
706 IOReturn
707 IOCatalogue::terminateDriversForModule(
708 OSString * moduleName,
709 bool unload)
710 {
711 IOReturn ret;
712 OSDictionary * dict;
713 bool isLoaded = false;
714
715 /* Check first if the kext currently has any linkage dependents;
716 * in such a case the unload would fail so let's not terminate any
717 * IOServices (since doing so typically results in a panic when there
718 * are loaded dependencies). Note that we aren't locking the kext here
719 * so it might lose or gain dependents by the time we call unloadModule();
720 * I think that's ok, our unload can fail if a kext comes in on top of
721 * this one even after we've torn down IOService objects. Conversely,
722 * if we fail the unload here and then lose a library, the autounload
723 * thread will get us in short order.
724 */
725 if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
726 isLoaded = true;
727
728 if (!OSKext::canUnloadKextWithIdentifier(moduleName,
729 /* checkClasses */ false)) {
730 ret = kOSKextReturnInUse;
731 goto finish;
732 }
733 }
734 dict = OSDictionary::withCapacity(1);
735 if (!dict) {
736 ret = kIOReturnNoMemory;
737 goto finish;
738 }
739
740 dict->setObject(gIOModuleIdentifierKey, moduleName);
741
742 ret = terminateDrivers(dict, NULL);
743
744 /* No goto between IOLock calls!
745 */
746 IORWLockWrite(lock);
747 if (kIOReturnSuccess == ret) {
748 ret = _removeDrivers(dict);
749 }
750
751 // Unload the module itself.
752 if (unload && isLoaded && ret == kIOReturnSuccess) {
753 ret = unloadModule(moduleName);
754 }
755
756 IORWLockUnlock(lock);
757
758 dict->release();
759
760 finish:
761 return ret;
762 }
763
764 IOReturn
765 IOCatalogue::terminateDriversForModule(
766 const char * moduleName,
767 bool unload)
768 {
769 OSString * name;
770 IOReturn ret;
771
772 name = OSString::withCString(moduleName);
773 if (!name) {
774 return kIOReturnNoMemory;
775 }
776
777 ret = terminateDriversForModule(name, unload);
778 name->release();
779
780 return ret;
781 }
782
783 #if defined(__i386__) || defined(__x86_64__)
784 bool
785 IOCatalogue::startMatching( OSDictionary * matching )
786 {
787 OSOrderedSet * set;
788
789 if (!matching) {
790 return false;
791 }
792
793 set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
794 (void *)gIOProbeScoreKey);
795 if (!set) {
796 return false;
797 }
798
799 IORWLockRead(lock);
800
801 personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
802 OSArray * array;
803 OSDictionary * dict;
804 unsigned int idx;
805
806 array = (OSArray *) value;
807 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
808 /* This comparison must be done with only the keys in the
809 * "matching" dict to enable general matching.
810 */
811 if (dict->isEqualTo(matching, matching)) {
812 set->setObject(dict);
813 }
814 }
815 return false;
816 });
817
818 // Start device matching.
819 if (set->getCount() > 0) {
820 IOService::catalogNewDrivers(set);
821 generation++;
822 }
823
824 IORWLockUnlock(lock);
825
826 set->release();
827
828 return true;
829 }
830 #endif /* defined(__i386__) || defined(__x86_64__) */
831
832 bool
833 IOCatalogue::startMatching( const OSSymbol * moduleName )
834 {
835 OSOrderedSet * set;
836
837 if (!moduleName) {
838 return false;
839 }
840
841 set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
842 (void *)gIOProbeScoreKey);
843 if (!set) {
844 return false;
845 }
846
847 IORWLockRead(lock);
848
849 personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
850 OSArray * array;
851 OSDictionary * dict;
852 OSObject * obj;
853 unsigned int idx;
854
855 array = (OSArray *) value;
856 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
857 obj = dict->getObject(gIOModuleIdentifierKernelKey);
858 if (obj && moduleName->isEqualTo(obj)) {
859 set->setObject(dict);
860 }
861 }
862 return false;
863 });
864
865 // Start device matching.
866 if (set->getCount() > 0) {
867 IOService::catalogNewDrivers(set);
868 generation++;
869 }
870
871 IORWLockUnlock(lock);
872
873 set->release();
874
875 return true;
876 }
877
878 void
879 IOCatalogue::reset(void)
880 {
881 IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
882 /* doMatching */ false);
883 return;
884 }
885
886 bool
887 IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
888 {
889 bool result = false;
890 OSArray * newPersonalities = NULL;// do not release
891 OSCollectionIterator * iter = NULL;// must release
892 OSOrderedSet * matchSet = NULL;// must release
893 const OSSymbol * key;
894 OSArray * array;
895 OSDictionary * thisNewPersonality = NULL;// do not release
896 OSDictionary * thisOldPersonality = NULL;// do not release
897 OSDictionary * myKexts = NULL;// must release
898 signed int idx, newIdx;
899
900 if (drivers) {
901 newPersonalities = OSDynamicCast(OSArray, drivers);
902 if (!newPersonalities) {
903 goto finish;
904 }
905 }
906 matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
907 (void *)gIOProbeScoreKey);
908 if (!matchSet) {
909 goto finish;
910 }
911 iter = OSCollectionIterator::withCollection(personalities);
912 if (!iter) {
913 goto finish;
914 }
915
916 /* need copy of loaded kexts so we can check if for loaded modules without
917 * taking the OSKext lock. There is a potential of deadlocking if we get
918 * an OSKext via the normal path. See 14672140.
919 */
920 myKexts = OSKext::copyKexts();
921
922 result = true;
923
924 IOLog("Resetting IOCatalogue.\n");
925
926 /* No goto finish from here to unlock.
927 */
928 IORWLockWrite(lock);
929
930 while ((key = (const OSSymbol *) iter->getNextObject())) {
931 array = (OSArray *) personalities->getObject(key);
932 if (!array) {
933 continue;
934 }
935
936 for (idx = 0;
937 (thisOldPersonality = (OSDictionary *) array->getObject(idx));
938 idx++) {
939 if (thisOldPersonality->getObject("KernelConfigTable")) {
940 continue;
941 }
942 thisNewPersonality = NULL;
943
944 if (newPersonalities) {
945 for (newIdx = 0;
946 (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
947 newIdx++) {
948 /* Unlike in other functions, this comparison must be exact!
949 * The catalogue must be able to contain personalities that
950 * are proper supersets of others.
951 * Do not compare just the properties present in one driver
952 * personality or the other.
953 */
954 if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
955 /* skip thisNewPersonality if it is not an OSDictionary */
956 continue;
957 }
958 if (thisNewPersonality->isEqualTo(thisOldPersonality)) {
959 break;
960 }
961 }
962 }
963 if (thisNewPersonality) {
964 // dup, ignore
965 newPersonalities->removeObject(newIdx);
966 } else {
967 // not in new set - remove
968 // only remove dictionary if this module in not loaded - 9953845
969 if (isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false) {
970 if (matchSet) {
971 matchSet->setObject(thisOldPersonality);
972 }
973 array->removeObject(idx);
974 idx--;
975 }
976 }
977 } // for...
978 } // while...
979
980 // add new
981 if (newPersonalities) {
982 for (newIdx = 0;
983 (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
984 newIdx++) {
985 if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
986 /* skip thisNewPersonality if it is not an OSDictionary */
987 continue;
988 }
989
990 OSKext::uniquePersonalityProperties(thisNewPersonality);
991 addPersonality(thisNewPersonality);
992 matchSet->setObject(thisNewPersonality);
993 }
994 }
995
996 /* Finally, start device matching on all new & removed personalities.
997 */
998 if (result && doNubMatching && (matchSet->getCount() > 0)) {
999 IOService::catalogNewDrivers(matchSet);
1000 generation++;
1001 }
1002
1003 IORWLockUnlock(lock);
1004
1005 finish:
1006 if (matchSet) {
1007 matchSet->release();
1008 }
1009 if (iter) {
1010 iter->release();
1011 }
1012 if (myKexts) {
1013 myKexts->release();
1014 }
1015
1016 return result;
1017 }
1018
1019 bool
1020 IOCatalogue::serialize(OSSerialize * s) const
1021 {
1022 if (!s) {
1023 return false;
1024 }
1025
1026 return super::serialize(s);
1027 }
1028
1029 bool
1030 IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
1031 {
1032 kern_return_t kr = kIOReturnSuccess;
1033
1034 switch (kind) {
1035 case kIOCatalogGetContents:
1036 kr = KERN_NOT_SUPPORTED;
1037 break;
1038
1039 case kIOCatalogGetModuleDemandList:
1040 kr = KERN_NOT_SUPPORTED;
1041 break;
1042
1043 case kIOCatalogGetCacheMissList:
1044 kr = KERN_NOT_SUPPORTED;
1045 break;
1046
1047 case kIOCatalogGetROMMkextList:
1048 kr = KERN_NOT_SUPPORTED;
1049 break;
1050
1051 default:
1052 kr = kIOReturnBadArgument;
1053 break;
1054 }
1055
1056 return kr;
1057 }
1058
1059 /* isModuleLoadedNoOSKextLock - used to check to see if a kext is loaded
1060 * without taking the OSKext lock. We use this to avoid the problem
1061 * where taking the IOCatalog lock then the OSKext lock will dealock when
1062 * a kext load or unload is happening at the same time as IOCatalog changing.
1063 *
1064 * theKexts - is a dictionary of current kexts (from OSKext::copyKexts) with
1065 * key set to the kext bundle ID and value set to an OSKext object
1066 * theModuleDict - is an IOKit personality dictionary for a given module (kext)
1067 */
1068 static bool
1069 isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
1070 OSDictionary *theModuleDict)
1071 {
1072 bool myResult = false;
1073 const OSString * myBundleID = NULL;// do not release
1074 OSKext * myKext = NULL; // do not release
1075
1076 if (theKexts == NULL || theModuleDict == NULL) {
1077 return myResult;
1078 }
1079
1080 // gIOModuleIdentifierKey is "CFBundleIdentifier"
1081 myBundleID = OSDynamicCast(OSString,
1082 theModuleDict->getObject(gIOModuleIdentifierKey));
1083 if (myBundleID == NULL) {
1084 return myResult;
1085 }
1086
1087 myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
1088 if (myKext) {
1089 myResult = myKext->isLoaded();
1090 }
1091
1092 return myResult;
1093 }
1094
1095
1096 #if PRAGMA_MARK
1097 #pragma mark Obsolete Kext Loading Stuff
1098 #endif
1099 /*********************************************************************
1100 **********************************************************************
1101 *** BINARY COMPATIBILITY SECTION ***
1102 **********************************************************************
1103 **********************************************************************
1104 * These functions are no longer used are necessary for C++ binary
1105 * compatibility on i386.
1106 **********************************************************************/