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