]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOCatalogue.cpp
xnu-1699.22.73.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 1998-2006 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
b0d623f7 29 * Copyright (c) 1998 Apple Inc. All rights reserved.
1c79356b
A
30 *
31 * HISTORY
32 *
33 */
2d21ac55
A
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 */
1c79356b 40
1c79356b
A
41extern "C" {
42#include <machine/machine_routines.h>
b0d623f7 43#include <libkern/kernel_mach_header.h>
9bccf70c 44#include <kern/host.h>
2d21ac55 45#include <security/mac_data.h>
1c79356b
A
46};
47
b0d623f7
A
48#include <libkern/c++/OSContainers.h>
49#include <libkern/c++/OSUnserialize.h>
50#include <libkern/c++/OSKext.h>
51#include <libkern/OSKextLibPrivate.h>
1c79356b 52
b0d623f7
A
53#include <IOKit/IODeviceTreeSupport.h>
54#include <IOKit/IOService.h>
55#include <IOKit/IOCatalogue.h>
1c79356b 56
b0d623f7
A
57#include <IOKit/IOLib.h>
58#include <IOKit/assert.h>
1c79356b 59
b0d623f7
A
60#if PRAGMA_MARK
61#pragma mark Internal Declarations
62#endif
63/*********************************************************************
64*********************************************************************/
1c79356b
A
65
66#define CATALOGTEST 0
67
55e303ae
A
68IOCatalogue * gIOCatalogue;
69const OSSymbol * gIOClassKey;
70const OSSymbol * gIOProbeScoreKey;
71const OSSymbol * gIOModuleIdentifierKey;
b0d623f7 72IOLock * gIOCatalogLock;
55e303ae 73
b0d623f7
A
74#if PRAGMA_MARK
75#pragma mark Utility functions
2d21ac55 76#endif
2d21ac55 77/*********************************************************************
b0d623f7
A
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
2d21ac55 82*********************************************************************/
b0d623f7
A
83static void
84AddNewImports(OSOrderedSet * set, OSDictionary * dict)
55e303ae 85{
b0d623f7 86 set->setObject(dict);
55e303ae
A
87}
88
b0d623f7
A
89#if PRAGMA_MARK
90#pragma mark IOCatalogue class implementation
91#endif
55e303ae 92/*********************************************************************
55e303ae
A
93*********************************************************************/
94
b0d623f7
A
95#define super OSObject
96OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
55e303ae
A
97
98/*********************************************************************
99*********************************************************************/
b0d623f7 100void IOCatalogue::initialize(void)
1c79356b
A
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) {
b0d623f7
A
110 IOLog("KernelConfigTables syntax error: %s\n",
111 errorString->getCStringNoCopy());
112 errorString->release();
1c79356b
A
113 }
114
55e303ae
A
115 gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
116 gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
b0d623f7 117 gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
55e303ae
A
118
119 assert( array && gIOClassKey && gIOProbeScoreKey
b0d623f7 120 && gIOModuleIdentifierKey);
1c79356b
A
121
122 gIOCatalogue = new IOCatalogue;
123 assert(gIOCatalogue);
124 rc = gIOCatalogue->init(array);
125 assert(rc);
126 array->release();
127}
128
b0d623f7
A
129/*********************************************************************
130* Initialize the IOCatalog object.
131*********************************************************************/
1c79356b
A
132bool IOCatalogue::init(OSArray * initArray)
133{
1c79356b
A
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
55e303ae 145 gIOCatalogLock = IOLockAlloc();
55e303ae
A
146
147 lock = gIOCatalogLock;
6d2010ae 148#if __i386__
b0d623f7 149 kld_lock = NULL;
6d2010ae 150#endif /* __i386__ */
1c79356b
A
151
152 kernelTables->reset();
153 while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
6d2010ae 154 OSKext::uniquePersonalityProperties(dict);
1c79356b
A
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
1c79356b
A
166 return true;
167}
168
b0d623f7
A
169/*********************************************************************
170* Release all resources used by IOCatalogue and deallocate.
171* This will probably never be called.
172*********************************************************************/
1c79356b
A
173void IOCatalogue::free( void )
174{
175 if ( array )
176 array->release();
177
178 if ( kernelTables )
179 kernelTables->release();
180
181 super::free();
182}
183
b0d623f7
A
184/*********************************************************************
185*********************************************************************/
1c79356b
A
186#if CATALOGTEST
187
188static int hackLimit;
1c79356b
A
189enum { kDriversPerIter = 4 };
190
b0d623f7
A
191void
192IOCatalogue::ping(thread_call_param_t arg, thread_call_param_t)
1c79356b
A
193{
194 IOCatalogue * self = (IOCatalogue *) arg;
195 OSOrderedSet * set;
196 OSDictionary * table;
197 int newLimit;
198
199 set = OSOrderedSet::withCapacity( 1 );
200
55e303ae 201 IOLockLock( &self->lock );
1c79356b
A
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
b0d623f7 209 OSSymbol * sym = (OSSymbol *) table->getObject(gIOClassKey);
1c79356b
A
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
55e303ae 223 IOLockUnlock( &self->lock );
1c79356b
A
224
225 if( kDriversPerIter == newLimit) {
226 AbsoluteTime deadline;
b0d623f7
A
227 clock_interval_to_deadline(500, kMillisecondScale);
228 thread_call_func_delayed(ping, this, deadline);
1c79356b
A
229 }
230}
231#endif
232
b0d623f7
A
233/*********************************************************************
234*********************************************************************/
235OSOrderedSet *
236IOCatalogue::findDrivers(
237 IOService * service,
238 SInt32 * generationCount)
1c79356b
A
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
b0d623f7 249 IOLockLock(lock);
1c79356b
A
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
b0d623f7 268 IOLockUnlock(lock);
1c79356b
A
269
270 return( set );
271}
272
b0d623f7
A
273/*********************************************************************
274* Is personality already in the catalog?
275*********************************************************************/
276OSOrderedSet *
277IOCatalogue::findDrivers(
278 OSDictionary * matching,
279 SInt32 * generationCount)
1c79356b
A
280{
281 OSDictionary * dict;
282 OSOrderedSet * set;
283
6d2010ae 284 OSKext::uniquePersonalityProperties(matching);
1c79356b
A
285
286 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
287 (void *)gIOProbeScoreKey );
288
b0d623f7 289 IOLockLock(lock);
1c79356b
A
290 kernelTables->reset();
291 while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
9bccf70c
A
292
293 /* This comparison must be done with only the keys in the
294 * "matching" dict to enable general searches.
295 */
1c79356b
A
296 if ( dict->isEqualTo(matching, matching) )
297 set->setObject(dict);
298 }
299 *generationCount = getGenerationCount();
b0d623f7 300 IOLockUnlock(lock);
1c79356b
A
301
302 return set;
303}
304
b0d623f7
A
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*********************************************************************/
316bool IOCatalogue::addDrivers(
317 OSArray * drivers,
318 bool doNubMatching)
1c79356b 319{
b0d623f7
A
320 bool result = false;
321 OSCollectionIterator * iter = NULL; // must release
322 OSOrderedSet * set = NULL; // must release
6d2010ae 323 OSObject * object = NULL; // do not release
b0d623f7 324 OSArray * persons = NULL; // do not release
1c79356b 325
1c79356b 326 persons = OSDynamicCast(OSArray, drivers);
b0d623f7
A
327 if (!persons) {
328 goto finish;
329 }
1c79356b
A
330
331 set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
b0d623f7
A
332 (void *)gIOProbeScoreKey );
333 if (!set) {
334 goto finish;
1c79356b
A
335 }
336
b0d623f7
A
337 iter = OSCollectionIterator::withCollection(persons);
338 if (!iter) {
339 goto finish;
340 }
341
6d2010ae
A
342 /* Start with success; clear it on an error.
343 */
b0d623f7
A
344 result = true;
345
346 IOLockLock(lock);
6d2010ae 347 while ( (object = iter->getNextObject()) ) {
55e303ae 348
b0d623f7
A
349 // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
350
6d2010ae
A
351 OSDictionary * personality = OSDynamicCast(OSDictionary, object);
352
b0d623f7 353 SInt count;
6d2010ae
A
354
355 if (!personality) {
356 IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
357 result = false;
358 break;
359 }
360
361 OSKext::uniquePersonalityProperties(personality);
b0d623f7
A
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 */
6d2010ae 377 if (personality->isEqualTo(driver)) {
b0d623f7
A
378 break;
379 }
380 }
381 if (count >= 0) {
382 // its a dup
383 continue;
384 }
385
6d2010ae 386 result = array->setObject(personality);
b0d623f7
A
387 if (!result) {
388 break;
389 }
390
6d2010ae 391 AddNewImports(set, personality);
1c79356b
A
392 }
393 // Start device matching.
6d2010ae 394 if (result && doNubMatching && (set->getCount() > 0)) {
b0d623f7 395 IOService::catalogNewDrivers(set);
1c79356b
A
396 generation++;
397 }
b0d623f7 398 IOLockUnlock(lock);
1c79356b 399
b0d623f7
A
400finish:
401 if (set) set->release();
402 if (iter) iter->release();
403
404 return result;
1c79356b
A
405}
406
b0d623f7
A
407/*********************************************************************
408* Remove drivers from the catalog which match the
409* properties in the matching dictionary.
410*********************************************************************/
411bool
412IOCatalogue::removeDrivers(
413 OSDictionary * matching,
414 bool doNubMatching)
1c79356b
A
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
6d2010ae 443 OSKext::uniquePersonalityProperties( matching );
1c79356b 444
b0d623f7 445 IOLockLock(lock);
1c79356b
A
446 kernelTables->reset();
447 arrayCopy->merge(array);
448 array->flushCollection();
449 tables->reset();
450 while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
9bccf70c
A
451
452 /* This comparison must be done with only the keys in the
453 * "matching" dict to enable general searches.
454 */
1c79356b
A
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 }
b0d623f7 467 IOLockUnlock(lock);
1c79356b
A
468
469 set->release();
470 tables->release();
471
472 return true;
473}
474
475// Return the generation count.
b0d623f7 476SInt32 IOCatalogue::getGenerationCount(void) const
1c79356b
A
477{
478 return( generation );
479}
480
b0d623f7 481bool IOCatalogue::isModuleLoaded(OSString * moduleName) const
1c79356b
A
482{
483 return isModuleLoaded(moduleName->getCStringNoCopy());
484}
485
b0d623f7 486bool IOCatalogue::isModuleLoaded(const char * moduleName) const
1c79356b 487{
b0d623f7
A
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;
1c79356b
A
497}
498
499// Check to see if module has been loaded already.
b0d623f7 500bool IOCatalogue::isModuleLoaded(OSDictionary * driver) const
1c79356b
A
501{
502 OSString * moduleName = NULL;
b0d623f7 503 OSString * publisherName = NULL;
1c79356b
A
504
505 if ( !driver )
506 return false;
507
b0d623f7
A
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
55e303ae 518 moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
1c79356b
A
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
b0d623f7
A
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 */
532void IOCatalogue::moduleHasLoaded(OSString * moduleName)
1c79356b 533{
b0d623f7 534 OSDictionary * dict;
1c79356b
A
535
536 dict = OSDictionary::withCapacity(2);
55e303ae 537 dict->setObject(gIOModuleIdentifierKey, moduleName);
1c79356b
A
538 startMatching(dict);
539 dict->release();
b0d623f7 540
6d2010ae 541 (void) OSKext::considerRebuildOfPrelinkedKernel(moduleName);
1c79356b
A
542}
543
b0d623f7 544void IOCatalogue::moduleHasLoaded(const char * moduleName)
1c79356b 545{
b0d623f7 546 OSString * name;
1c79356b
A
547
548 name = OSString::withCString(moduleName);
549 moduleHasLoaded(name);
550 name->release();
551}
552
b0d623f7
A
553// xxx - return is really OSReturn/kern_return_t
554IOReturn IOCatalogue::unloadModule(OSString * moduleName) const
1c79356b 555{
b0d623f7 556 return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
1c79356b
A
557}
558
b0d623f7 559static IOReturn _terminateDrivers(OSDictionary * matching)
1c79356b 560{
1c79356b
A
561 OSDictionary * dict;
562 OSIterator * iter;
1c79356b
A
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
6d2010ae 576 OSKext::uniquePersonalityProperties( matching );
1c79356b 577
1c79356b
A
578 // terminate instances.
579 do {
580 iter->reset();
581 while( (service = (IOService *)iter->getNextObject()) ) {
582 dict = service->getPropertyTable();
583 if ( !dict )
584 continue;
585
9bccf70c
A
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 */
1c79356b
A
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
91447636
A
601 return ret;
602}
603
604static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
605{
606 OSCollectionIterator * tables;
607 OSDictionary * dict;
608 OSArray * arrayCopy;
609 IOReturn ret = kIOReturnSuccess;
610
1c79356b 611 // remove configs from catalog.
1c79356b
A
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()) ) {
9bccf70c
A
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 */
1c79356b
A
632 if ( dict->isEqualTo(matching, matching) )
633 continue;
634
635 array->setObject(dict);
636 }
637
638 tables->release();
639
640 return ret;
641}
642
b0d623f7 643IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching)
1c79356b
A
644{
645 IOReturn ret;
646
91447636 647 ret = _terminateDrivers(matching);
b0d623f7 648 IOLockLock(lock);
91447636
A
649 if (kIOReturnSuccess == ret)
650 ret = _removeDrivers(array, matching);
1c79356b 651 kernelTables->reset();
b0d623f7 652 IOLockUnlock(lock);
1c79356b
A
653
654 return ret;
655}
656
657IOReturn IOCatalogue::terminateDriversForModule(
b0d623f7
A
658 OSString * moduleName,
659 bool unload)
1c79356b
A
660{
661 IOReturn ret;
662 OSDictionary * dict;
b0d623f7
A
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;
1c79356b 678
b0d623f7
A
679 if (!OSKext::canUnloadKextWithIdentifier(moduleName,
680 /* checkClasses */ false)) {
681 ret = kOSKextReturnInUse;
682 goto finish;
683 }
684 }
1c79356b 685 dict = OSDictionary::withCapacity(1);
b0d623f7
A
686 if (!dict) {
687 ret = kIOReturnNoMemory;
688 goto finish;
689 }
1c79356b 690
55e303ae 691 dict->setObject(gIOModuleIdentifierKey, moduleName);
9bccf70c 692
91447636 693 ret = _terminateDrivers(dict);
b0d623f7
A
694
695 /* No goto between IOLock calls!
696 */
697 IOLockLock(lock);
698 if (kIOReturnSuccess == ret) {
699 ret = _removeDrivers(array, dict);
700 }
1c79356b
A
701 kernelTables->reset();
702
703 // Unload the module itself.
b0d623f7 704 if (unload && isLoaded && ret == kIOReturnSuccess) {
1c79356b
A
705 ret = unloadModule(moduleName);
706 }
707
b0d623f7 708 IOLockUnlock(lock);
1c79356b
A
709
710 dict->release();
711
b0d623f7 712finish:
1c79356b
A
713 return ret;
714}
715
716IOReturn IOCatalogue::terminateDriversForModule(
b0d623f7
A
717 const char * moduleName,
718 bool unload)
1c79356b
A
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();
9bccf70c 729
1c79356b
A
730 return ret;
731}
732
733bool 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
b0d623f7 746 IOLockLock(lock);
1c79356b
A
747 kernelTables->reset();
748
749 while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
9bccf70c
A
750
751 /* This comparison must be done with only the keys in the
752 * "matching" dict to enable general matching.
753 */
1c79356b
A
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
b0d623f7 763 IOLockUnlock(lock);
1c79356b
A
764
765 set->release();
766
767 return true;
768}
769
770void IOCatalogue::reset(void)
771{
6d2010ae
A
772 IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
773 /* doMatching */ false);
774 return;
775}
776
777bool 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
1c79356b 832 IOLog("Resetting IOCatalogue.\n");
6d2010ae
A
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
941finish:
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;
1c79356b
A
949}
950
951bool IOCatalogue::serialize(OSSerialize * s) const
952{
1c79356b
A
953 if ( !s )
954 return false;
955
91447636 956 return super::serialize(s);
1c79356b
A
957}
958
55e303ae
A
959bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
960{
961 kern_return_t kr = kIOReturnSuccess;
962
963 switch ( kind )
964 {
965 case kIOCatalogGetContents:
2d21ac55 966 if (!array->serialize(s))
55e303ae
A
967 kr = kIOReturnNoMemory;
968 break;
969
970 case kIOCatalogGetModuleDemandList:
b0d623f7 971 kr = KERN_NOT_SUPPORTED;
55e303ae
A
972 break;
973
974 case kIOCatalogGetCacheMissList:
b0d623f7 975 kr = KERN_NOT_SUPPORTED;
55e303ae
A
976 break;
977
978 case kIOCatalogGetROMMkextList:
b0d623f7 979 kr = KERN_NOT_SUPPORTED;
55e303ae
A
980 break;
981
982 default:
983 kr = kIOReturnBadArgument;
984 break;
985 }
986
987 return kr;
988}
989
1c79356b 990
b0d623f7
A
991#if PRAGMA_MARK
992#pragma mark Obsolete Kext Loading Stuff
0c530ab8 993#endif
91447636 994/*********************************************************************
b0d623f7
A
995**********************************************************************
996*** BINARY COMPATIBILITY SECTION ***
997**********************************************************************
998**********************************************************************
999* These functions are no longer used are necessary for C++ binary
6d2010ae 1000* compatibility on i386.
b0d623f7 1001**********************************************************************/
6d2010ae 1002#if __i386__
b0d623f7
A
1003
1004bool IOCatalogue::recordStartupExtensions(void)
1005{ return false; }
91447636 1006
b0d623f7
A
1007bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
1008{ return KERN_NOT_SUPPORTED; }
91447636 1009
b0d623f7
A
1010kern_return_t IOCatalogue::removeKernelLinker(void)
1011{ return KERN_NOT_SUPPORTED; }
1012
6d2010ae 1013#endif /* __i386__ */