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