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