]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOCatalogue.cpp
xnu-6153.81.5.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)
561 {
562 OSDictionary * dict;
563 OSIterator * iter;
564 IOService * service;
565 IOReturn ret;
566
567 if (!matching) {
568 return kIOReturnBadArgument;
569 }
570
571 ret = kIOReturnSuccess;
572 dict = NULL;
573 iter = IORegistryIterator::iterateOver(gIOServicePlane,
574 kIORegistryIterateRecursively);
575 if (!iter) {
576 return kIOReturnNoMemory;
577 }
578
579 OSKext::uniquePersonalityProperties( matching );
580
581 // terminate instances.
582 do {
583 iter->reset();
584 while ((service = (IOService *)iter->getNextObject())) {
585 dict = service->getPropertyTable();
586 if (!dict) {
587 continue;
588 }
589
590 /* Terminate only for personalities that match the matching dictionary.
591 * This comparison must be done with only the keys in the
592 * "matching" dict to enable general matching.
593 */
594 if (!dict->isEqualTo(matching, matching)) {
595 continue;
596 }
597
598 if (!service->terminate(kIOServiceRequired | kIOServiceSynchronous)) {
599 ret = kIOReturnUnsupported;
600 break;
601 }
602 }
603 } while (!service && !iter->isValid());
604 iter->release();
605
606 return ret;
607 }
608
609 IOReturn
610 IOCatalogue::_removeDrivers(OSDictionary * matching)
611 {
612 IOReturn ret = kIOReturnSuccess;
613 OSCollectionIterator * iter;
614 OSDictionary * dict;
615 OSArray * array;
616 const OSSymbol * key;
617 unsigned int idx;
618
619 // remove configs from catalog.
620
621 iter = OSCollectionIterator::withCollection(personalities);
622 if (!iter) {
623 return kIOReturnNoMemory;
624 }
625
626 while ((key = (const OSSymbol *) iter->getNextObject())) {
627 array = (OSArray *) personalities->getObject(key);
628 if (array) {
629 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
630 /* Remove from the catalogue's array any personalities
631 * that match the matching dictionary.
632 * This comparison must be done with only the keys in the
633 * "matching" dict to enable general matching.
634 */
635 if (dict->isEqualTo(matching, matching)) {
636 array->removeObject(idx);
637 idx--;
638 }
639 }
640 }
641 }
642 iter->release();
643
644 return ret;
645 }
646
647 IOReturn
648 IOCatalogue::terminateDrivers(OSDictionary * matching)
649 {
650 IOReturn ret;
651
652 ret = _terminateDrivers(matching);
653 IORWLockWrite(lock);
654 if (kIOReturnSuccess == ret) {
655 ret = _removeDrivers(matching);
656 }
657 IORWLockUnlock(lock);
658
659 return ret;
660 }
661
662 IOReturn
663 IOCatalogue::terminateDriversForModule(
664 OSString * moduleName,
665 bool unload)
666 {
667 IOReturn ret;
668 OSDictionary * dict;
669 bool isLoaded = false;
670
671 /* Check first if the kext currently has any linkage dependents;
672 * in such a case the unload would fail so let's not terminate any
673 * IOServices (since doing so typically results in a panic when there
674 * are loaded dependencies). Note that we aren't locking the kext here
675 * so it might lose or gain dependents by the time we call unloadModule();
676 * I think that's ok, our unload can fail if a kext comes in on top of
677 * this one even after we've torn down IOService objects. Conversely,
678 * if we fail the unload here and then lose a library, the autounload
679 * thread will get us in short order.
680 */
681 if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
682 isLoaded = true;
683
684 if (!OSKext::canUnloadKextWithIdentifier(moduleName,
685 /* checkClasses */ false)) {
686 ret = kOSKextReturnInUse;
687 goto finish;
688 }
689 }
690 dict = OSDictionary::withCapacity(1);
691 if (!dict) {
692 ret = kIOReturnNoMemory;
693 goto finish;
694 }
695
696 dict->setObject(gIOModuleIdentifierKey, moduleName);
697
698 ret = _terminateDrivers(dict);
699
700 /* No goto between IOLock calls!
701 */
702 IORWLockWrite(lock);
703 if (kIOReturnSuccess == ret) {
704 ret = _removeDrivers(dict);
705 }
706
707 // Unload the module itself.
708 if (unload && isLoaded && ret == kIOReturnSuccess) {
709 ret = unloadModule(moduleName);
710 }
711
712 IORWLockUnlock(lock);
713
714 dict->release();
715
716 finish:
717 return ret;
718 }
719
720 IOReturn
721 IOCatalogue::terminateDriversForModule(
722 const char * moduleName,
723 bool unload)
724 {
725 OSString * name;
726 IOReturn ret;
727
728 name = OSString::withCString(moduleName);
729 if (!name) {
730 return kIOReturnNoMemory;
731 }
732
733 ret = terminateDriversForModule(name, unload);
734 name->release();
735
736 return ret;
737 }
738
739 #if defined(__i386__) || defined(__x86_64__)
740 bool
741 IOCatalogue::startMatching( OSDictionary * matching )
742 {
743 OSOrderedSet * set;
744
745 if (!matching) {
746 return false;
747 }
748
749 set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
750 (void *)gIOProbeScoreKey);
751 if (!set) {
752 return false;
753 }
754
755 IORWLockRead(lock);
756
757 personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
758 OSArray * array;
759 OSDictionary * dict;
760 unsigned int idx;
761
762 array = (OSArray *) value;
763 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
764 /* This comparison must be done with only the keys in the
765 * "matching" dict to enable general matching.
766 */
767 if (dict->isEqualTo(matching, matching)) {
768 set->setObject(dict);
769 }
770 }
771 return false;
772 });
773
774 // Start device matching.
775 if (set->getCount() > 0) {
776 IOService::catalogNewDrivers(set);
777 generation++;
778 }
779
780 IORWLockUnlock(lock);
781
782 set->release();
783
784 return true;
785 }
786 #endif /* defined(__i386__) || defined(__x86_64__) */
787
788 bool
789 IOCatalogue::startMatching( const OSSymbol * moduleName )
790 {
791 OSOrderedSet * set;
792
793 if (!moduleName) {
794 return false;
795 }
796
797 set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
798 (void *)gIOProbeScoreKey);
799 if (!set) {
800 return false;
801 }
802
803 IORWLockRead(lock);
804
805 personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
806 OSArray * array;
807 OSDictionary * dict;
808 OSObject * obj;
809 unsigned int idx;
810
811 array = (OSArray *) value;
812 for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
813 obj = dict->getObject(gIOModuleIdentifierKernelKey);
814 if (obj && moduleName->isEqualTo(obj)) {
815 set->setObject(dict);
816 }
817 }
818 return false;
819 });
820
821 // Start device matching.
822 if (set->getCount() > 0) {
823 IOService::catalogNewDrivers(set);
824 generation++;
825 }
826
827 IORWLockUnlock(lock);
828
829 set->release();
830
831 return true;
832 }
833
834 void
835 IOCatalogue::reset(void)
836 {
837 IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
838 /* doMatching */ false);
839 return;
840 }
841
842 bool
843 IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
844 {
845 bool result = false;
846 OSArray * newPersonalities = NULL;// do not release
847 OSCollectionIterator * iter = NULL;// must release
848 OSOrderedSet * matchSet = NULL;// must release
849 const OSSymbol * key;
850 OSArray * array;
851 OSDictionary * thisNewPersonality = NULL;// do not release
852 OSDictionary * thisOldPersonality = NULL;// do not release
853 OSDictionary * myKexts = NULL;// must release
854 signed int idx, newIdx;
855
856 if (drivers) {
857 newPersonalities = OSDynamicCast(OSArray, drivers);
858 if (!newPersonalities) {
859 goto finish;
860 }
861 }
862 matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
863 (void *)gIOProbeScoreKey);
864 if (!matchSet) {
865 goto finish;
866 }
867 iter = OSCollectionIterator::withCollection(personalities);
868 if (!iter) {
869 goto finish;
870 }
871
872 /* need copy of loaded kexts so we can check if for loaded modules without
873 * taking the OSKext lock. There is a potential of deadlocking if we get
874 * an OSKext via the normal path. See 14672140.
875 */
876 myKexts = OSKext::copyKexts();
877
878 result = true;
879
880 IOLog("Resetting IOCatalogue.\n");
881
882 /* No goto finish from here to unlock.
883 */
884 IORWLockWrite(lock);
885
886 while ((key = (const OSSymbol *) iter->getNextObject())) {
887 array = (OSArray *) personalities->getObject(key);
888 if (!array) {
889 continue;
890 }
891
892 for (idx = 0;
893 (thisOldPersonality = (OSDictionary *) array->getObject(idx));
894 idx++) {
895 if (thisOldPersonality->getObject("KernelConfigTable")) {
896 continue;
897 }
898 thisNewPersonality = NULL;
899
900 if (newPersonalities) {
901 for (newIdx = 0;
902 (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
903 newIdx++) {
904 /* Unlike in other functions, this comparison must be exact!
905 * The catalogue must be able to contain personalities that
906 * are proper supersets of others.
907 * Do not compare just the properties present in one driver
908 * personality or the other.
909 */
910 if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
911 /* skip thisNewPersonality if it is not an OSDictionary */
912 continue;
913 }
914 if (thisNewPersonality->isEqualTo(thisOldPersonality)) {
915 break;
916 }
917 }
918 }
919 if (thisNewPersonality) {
920 // dup, ignore
921 newPersonalities->removeObject(newIdx);
922 } else {
923 // not in new set - remove
924 // only remove dictionary if this module in not loaded - 9953845
925 if (isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false) {
926 if (matchSet) {
927 matchSet->setObject(thisOldPersonality);
928 }
929 array->removeObject(idx);
930 idx--;
931 }
932 }
933 } // for...
934 } // while...
935
936 // add new
937 if (newPersonalities) {
938 for (newIdx = 0;
939 (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
940 newIdx++) {
941 if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
942 /* skip thisNewPersonality if it is not an OSDictionary */
943 continue;
944 }
945
946 OSKext::uniquePersonalityProperties(thisNewPersonality);
947 addPersonality(thisNewPersonality);
948 matchSet->setObject(thisNewPersonality);
949 }
950 }
951
952 /* Finally, start device matching on all new & removed personalities.
953 */
954 if (result && doNubMatching && (matchSet->getCount() > 0)) {
955 IOService::catalogNewDrivers(matchSet);
956 generation++;
957 }
958
959 IORWLockUnlock(lock);
960
961 finish:
962 if (matchSet) {
963 matchSet->release();
964 }
965 if (iter) {
966 iter->release();
967 }
968 if (myKexts) {
969 myKexts->release();
970 }
971
972 return result;
973 }
974
975 bool
976 IOCatalogue::serialize(OSSerialize * s) const
977 {
978 if (!s) {
979 return false;
980 }
981
982 return super::serialize(s);
983 }
984
985 bool
986 IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
987 {
988 kern_return_t kr = kIOReturnSuccess;
989
990 switch (kind) {
991 case kIOCatalogGetContents:
992 kr = KERN_NOT_SUPPORTED;
993 break;
994
995 case kIOCatalogGetModuleDemandList:
996 kr = KERN_NOT_SUPPORTED;
997 break;
998
999 case kIOCatalogGetCacheMissList:
1000 kr = KERN_NOT_SUPPORTED;
1001 break;
1002
1003 case kIOCatalogGetROMMkextList:
1004 kr = KERN_NOT_SUPPORTED;
1005 break;
1006
1007 default:
1008 kr = kIOReturnBadArgument;
1009 break;
1010 }
1011
1012 return kr;
1013 }
1014
1015 /* isModuleLoadedNoOSKextLock - used to check to see if a kext is loaded
1016 * without taking the OSKext lock. We use this to avoid the problem
1017 * where taking the IOCatalog lock then the OSKext lock will dealock when
1018 * a kext load or unload is happening at the same time as IOCatalog changing.
1019 *
1020 * theKexts - is a dictionary of current kexts (from OSKext::copyKexts) with
1021 * key set to the kext bundle ID and value set to an OSKext object
1022 * theModuleDict - is an IOKit personality dictionary for a given module (kext)
1023 */
1024 static bool
1025 isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
1026 OSDictionary *theModuleDict)
1027 {
1028 bool myResult = false;
1029 const OSString * myBundleID = NULL;// do not release
1030 OSKext * myKext = NULL; // do not release
1031
1032 if (theKexts == NULL || theModuleDict == NULL) {
1033 return myResult;
1034 }
1035
1036 // gIOModuleIdentifierKey is "CFBundleIdentifier"
1037 myBundleID = OSDynamicCast(OSString,
1038 theModuleDict->getObject(gIOModuleIdentifierKey));
1039 if (myBundleID == NULL) {
1040 return myResult;
1041 }
1042
1043 myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
1044 if (myKext) {
1045 myResult = myKext->isLoaded();
1046 }
1047
1048 return myResult;
1049 }
1050
1051
1052 #if PRAGMA_MARK
1053 #pragma mark Obsolete Kext Loading Stuff
1054 #endif
1055 /*********************************************************************
1056 **********************************************************************
1057 *** BINARY COMPATIBILITY SECTION ***
1058 **********************************************************************
1059 **********************************************************************
1060 * These functions are no longer used are necessary for C++ binary
1061 * compatibility on i386.
1062 **********************************************************************/