]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOCatalogue.cpp
xnu-344.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24 *
25 * HISTORY
26 *
27 */
28
29#include <IOKit/IODeviceTreeSupport.h>
30#include <IOKit/IOService.h>
31#include <libkern/c++/OSContainers.h>
32#include <IOKit/IOCatalogue.h>
33#include <libkern/c++/OSUnserialize.h>
34extern "C" {
35#include <machine/machine_routines.h>
36#include <mach/kmod.h>
37#include <mach-o/mach_header.h>
9bccf70c 38#include <kern/host.h>
1c79356b
A
39};
40
41#include <IOKit/IOLib.h>
42
43#include <IOKit/assert.h>
44
45
46extern "C" {
47int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
48extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
49extern void OSRuntimeUnloadCPPForSegment(
50 struct segment_command * segment);
51};
52
53
54/*****
55 * At startup these function pointers are set to use the libsa in-kernel
56 * linker for recording and loading kmods. Once the root filesystem
57 * is available, the kmod_load_function pointer gets switched to point
58 * at the kmod_load_extension() function built into the kernel, and the
59 * others are set to zero. Those two functions must *always* be checked
60 * before being invoked.
61 */
62extern "C" {
63kern_return_t (*kmod_load_function)(char *extension_name) =
64 &kmod_load_extension;
65bool (*record_startup_extensions_function)(void) = 0;
66bool (*add_from_mkext_function)(OSData * mkext) = 0;
67void (*remove_startup_extension_function)(const char * name) = 0;
68};
69
70
71/*****
72 * A few parts of IOCatalogue require knowledge of
73 * whether the in-kernel linker is present. This
74 * variable is set by libsa's bootstrap code.
75 */
76int kernelLinkerPresent = 0;
77
78
79#define super OSObject
80#define kModuleKey "CFBundleIdentifier"
81
82OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
83
84#define CATALOGTEST 0
85
86IOCatalogue * gIOCatalogue;
87const OSSymbol * gIOClassKey;
88const OSSymbol * gIOProbeScoreKey;
89
90static void UniqueProperties( OSDictionary * dict )
91{
92 OSString * data;
93
94 data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
95 if( data) {
96 const OSSymbol *classSymbol = OSSymbol::withString(data);
97
98 dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
99 classSymbol->release();
100 }
101
102 data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
103 if( data) {
104 const OSSymbol *classSymbol = OSSymbol::withString(data);
105
106 dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
107 classSymbol->release();
108 }
109}
110
111void IOCatalogue::initialize( void )
112{
113 OSArray * array;
114 OSString * errorString;
115 bool rc;
116
117 extern const char * gIOKernelConfigTables;
118
119 array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
120 if (!array && errorString) {
121 IOLog("KernelConfigTables syntax error: %s\n",
122 errorString->getCStringNoCopy());
123 errorString->release();
124 }
125
126 gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
127 gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
128 assert( array && gIOClassKey && gIOProbeScoreKey);
129
130 gIOCatalogue = new IOCatalogue;
131 assert(gIOCatalogue);
132 rc = gIOCatalogue->init(array);
133 assert(rc);
134 array->release();
135}
136
137// Initialize the IOCatalog object.
138bool IOCatalogue::init(OSArray * initArray)
139{
140 IORegistryEntry * entry;
141 OSDictionary * dict;
142
143 if ( !super::init() )
144 return false;
145
146 generation = 1;
147
148 array = initArray;
149 array->retain();
150 kernelTables = OSCollectionIterator::withCollection( array );
151
152 lock = IOLockAlloc();
0b4e3aa0 153 kld_lock = IOLockAlloc();
1c79356b
A
154
155 kernelTables->reset();
156 while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
157 UniqueProperties(dict);
158 if( 0 == dict->getObject( gIOClassKey ))
159 IOLog("Missing or bad \"%s\" key\n",
160 gIOClassKey->getCStringNoCopy());
161 }
162
163#if CATALOGTEST
164 AbsoluteTime deadline;
165 clock_interval_to_deadline( 1000, kMillisecondScale );
166 thread_call_func_delayed( ping, this, deadline );
167#endif
168
169 entry = IORegistryEntry::getRegistryRoot();
170 if ( entry )
171 entry->setProperty(kIOCatalogueKey, this);
172
173 return true;
174}
175
176// Release all resources used by IOCatalogue and deallocate.
177// This will probably never be called.
178void IOCatalogue::free( void )
179{
180 if ( array )
181 array->release();
182
183 if ( kernelTables )
184 kernelTables->release();
185
186 super::free();
187}
188
189#if CATALOGTEST
190
191static int hackLimit;
192
193enum { kDriversPerIter = 4 };
194
195void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
196{
197 IOCatalogue * self = (IOCatalogue *) arg;
198 OSOrderedSet * set;
199 OSDictionary * table;
200 int newLimit;
201
202 set = OSOrderedSet::withCapacity( 1 );
203
204 IOTakeLock( &self->lock );
205
206 for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
207 table = (OSDictionary *) self->array->getObject(
208 hackLimit + newLimit );
209 if( table) {
210 set->setLastObject( table );
211
212 OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey );
213 kprintf("enabling %s\n", sym->getCStringNoCopy());
214
215 } else {
216 newLimit--;
217 break;
218 }
219 }
220
221 IOService::catalogNewDrivers( set );
222
223 hackLimit += newLimit;
224 self->generation++;
225
226 IOUnlock( &self->lock );
227
228 if( kDriversPerIter == newLimit) {
229 AbsoluteTime deadline;
230 clock_interval_to_deadline( 500, kMillisecondScale );
231 thread_call_func_delayed( ping, this, deadline );
232 }
233}
234#endif
235
236OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
237 SInt32 * generationCount )
238{
239 OSDictionary * nextTable;
240 OSOrderedSet * set;
241 OSString * imports;
242
243 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
244 (void *)gIOProbeScoreKey );
245 if( !set )
246 return( 0 );
247
248 IOTakeLock( lock );
249 kernelTables->reset();
250
251#if CATALOGTEST
252 int hackIndex = 0;
253#endif
254 while( (nextTable = (OSDictionary *) kernelTables->getNextObject())) {
255#if CATALOGTEST
256 if( hackIndex++ > hackLimit)
257 break;
258#endif
259 imports = OSDynamicCast( OSString,
260 nextTable->getObject( gIOProviderClassKey ));
261 if( imports && service->metaCast( imports ))
262 set->setObject( nextTable );
263 }
264
265 *generationCount = getGenerationCount();
266
267 IOUnlock( lock );
268
269 return( set );
270}
271
272// Is personality already in the catalog?
273OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
274 SInt32 * generationCount)
275{
276 OSDictionary * dict;
277 OSOrderedSet * set;
278
279 UniqueProperties(matching);
280
281 set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
282 (void *)gIOProbeScoreKey );
283
284 IOTakeLock( lock );
285 kernelTables->reset();
286 while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
9bccf70c
A
287
288 /* This comparison must be done with only the keys in the
289 * "matching" dict to enable general searches.
290 */
1c79356b
A
291 if ( dict->isEqualTo(matching, matching) )
292 set->setObject(dict);
293 }
294 *generationCount = getGenerationCount();
295 IOUnlock( lock );
296
297 return set;
298}
299
300// Add a new personality to the set if it has a unique IOResourceMatchKey value.
301// XXX -- svail: This should be optimized.
302// esb - There doesn't seem like any reason to do this - it causes problems
303// esb - when there are more than one loadable driver matching on the same provider class
304static void AddNewImports( OSOrderedSet * set, OSDictionary * dict )
305{
306 set->setObject(dict);
307}
308
309// Add driver config tables to catalog and start matching process.
310bool IOCatalogue::addDrivers(OSArray * drivers,
311 bool doNubMatching = true )
312{
313 OSCollectionIterator * iter;
314 OSDictionary * dict;
315 OSOrderedSet * set;
316 OSArray * persons;
317 bool ret;
318
319 ret = true;
320 persons = OSDynamicCast(OSArray, drivers);
321 if ( !persons )
322 return false;
323
324 iter = OSCollectionIterator::withCollection( persons );
325 if (!iter )
326 return false;
327
328 set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
329 (void *)gIOProbeScoreKey );
330 if ( !set ) {
331 iter->release();
332 return false;
333 }
334
335 IOTakeLock( lock );
336 while ( (dict = (OSDictionary *) iter->getNextObject()) ) {
337 UInt count;
338
339 UniqueProperties( dict );
340
341 // Add driver personality to catalogue.
342 count = array->getCount();
343 while ( count-- ) {
344 OSDictionary * driver;
345
346 // Be sure not to double up on personalities.
347 driver = (OSDictionary *)array->getObject(count);
9bccf70c
A
348
349 /* Unlike in other functions, this comparison must be exact!
350 * The catalogue must be able to contain personalities that
351 * are proper supersets of others.
352 * Do not compare just the properties present in one driver
353 * pesonality or the other.
354 */
355 if ( dict->isEqualTo(driver) ) {
1c79356b
A
356 array->removeObject(count);
357 break;
358 }
359 }
360
361 ret = array->setObject( dict );
362 if ( !ret )
363 break;
364
365 AddNewImports( set, dict );
366 }
367 // Start device matching.
368 if ( doNubMatching && (set->getCount() > 0) ) {
369 IOService::catalogNewDrivers( set );
370 generation++;
371 }
372 IOUnlock( lock );
373
1c79356b
A
374 set->release();
375 iter->release();
376
377 return ret;
378}
379
380// Remove drivers from the catalog which match the
381// properties in the matching dictionary.
382bool IOCatalogue::removeDrivers( OSDictionary * matching,
383 bool doNubMatching = true)
384{
385 OSCollectionIterator * tables;
386 OSDictionary * dict;
387 OSOrderedSet * set;
388 OSArray * arrayCopy;
389
390 if ( !matching )
391 return false;
392
393 set = OSOrderedSet::withCapacity(10,
394 IOServiceOrdering,
395 (void *)gIOProbeScoreKey);
396 if ( !set )
397 return false;
398
399 arrayCopy = OSArray::withCapacity(100);
400 if ( !arrayCopy ) {
401 set->release();
402 return false;
403 }
404
405 tables = OSCollectionIterator::withCollection(arrayCopy);
406 arrayCopy->release();
407 if ( !tables ) {
408 set->release();
409 return false;
410 }
411
412 UniqueProperties( matching );
413
414 IOTakeLock( lock );
415 kernelTables->reset();
416 arrayCopy->merge(array);
417 array->flushCollection();
418 tables->reset();
419 while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
9bccf70c
A
420
421 /* This comparison must be done with only the keys in the
422 * "matching" dict to enable general searches.
423 */
1c79356b
A
424 if ( dict->isEqualTo(matching, matching) ) {
425 AddNewImports( set, dict );
426 continue;
427 }
428
429 array->setObject(dict);
430 }
431 // Start device matching.
432 if ( doNubMatching && (set->getCount() > 0) ) {
433 IOService::catalogNewDrivers(set);
434 generation++;
435 }
436 IOUnlock( lock );
437
438 set->release();
439 tables->release();
440
441 return true;
442}
443
444// Return the generation count.
445SInt32 IOCatalogue::getGenerationCount( void ) const
446{
447 return( generation );
448}
449
450bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
451{
452 return isModuleLoaded(moduleName->getCStringNoCopy());
453}
454
455bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
456{
457 kmod_info_t * k_info;
458
459 if ( !moduleName )
460 return false;
461
462 // Is the module already loaded?
9bccf70c 463 k_info = kmod_lookupbyname_locked((char *)moduleName);
1c79356b
A
464 if ( !k_info ) {
465 kern_return_t ret;
466
0b4e3aa0
A
467 /* To make sure this operation completes even if a bad extension needs
468 * to be removed, take the kld lock for this whole block, spanning the
469 * kmod_load_function() and remove_startup_extension_function() calls.
470 */
471 IOLockLock(kld_lock);
472
1c79356b
A
473 // If the module hasn't been loaded, then load it.
474 if (kmod_load_function != 0) {
0b4e3aa0 475
1c79356b 476 ret = kmod_load_function((char *)moduleName);
0b4e3aa0 477
1c79356b
A
478 if ( ret != kIOReturnSuccess ) {
479 IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
480
481 /* If the extension couldn't be loaded this time,
482 * make it unavailable so that no more requests are
483 * made in vain. This also enables other matching
484 * extensions to have a chance.
485 */
486 if (kernelLinkerPresent && remove_startup_extension_function) {
487 (*remove_startup_extension_function)(moduleName);
488 }
0b4e3aa0 489 IOLockUnlock(kld_lock);
1c79356b
A
490 return false;
491 } else if (kernelLinkerPresent) {
492 // If kern linker is here, the driver is actually loaded,
493 // so return true.
0b4e3aa0 494 IOLockUnlock(kld_lock);
1c79356b
A
495 return true;
496 } else {
497 // kern linker isn't here, a request has been queued
498 // but the module isn't necessarily loaded yet, so stall.
0b4e3aa0 499 IOLockUnlock(kld_lock);
1c79356b
A
500 return false;
501 }
502 } else {
0b4e3aa0
A
503 IOLog("IOCatalogue: %s cannot be loaded "
504 "(kmod load function not set).\n",
505 moduleName);
1c79356b
A
506 }
507
0b4e3aa0 508 IOLockUnlock(kld_lock);
1c79356b
A
509 return false;
510 }
511
9bccf70c
A
512 if (k_info) {
513 kfree(k_info, sizeof(kmod_info_t));
514 }
515
0b4e3aa0 516 /* Lock wasn't taken if we get here. */
1c79356b
A
517 return true;
518}
519
520// Check to see if module has been loaded already.
521bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
522{
523 OSString * moduleName = NULL;
524
525 if ( !driver )
526 return false;
527
528 moduleName = OSDynamicCast(OSString, driver->getObject(kModuleKey));
529 if ( moduleName )
530 return isModuleLoaded(moduleName);
531
532 /* If a personality doesn't hold the "CFBundleIdentifier" key
533 * it is assumed to be an "in-kernel" driver.
534 */
535 return true;
536}
537
538// This function is called after a module has been loaded.
539void IOCatalogue::moduleHasLoaded( OSString * moduleName )
540{
541 OSDictionary * dict;
542
543 dict = OSDictionary::withCapacity(2);
544 dict->setObject(kModuleKey, moduleName);
545 startMatching(dict);
546 dict->release();
547}
548
549void IOCatalogue::moduleHasLoaded( const char * moduleName )
550{
551 OSString * name;
552
553 name = OSString::withCString(moduleName);
554 moduleHasLoaded(name);
555 name->release();
556}
557
558IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
559{
9bccf70c 560 kmod_info_t * k_info = 0;
1c79356b
A
561 kern_return_t ret;
562 const char * name;
563
564 ret = kIOReturnBadArgument;
565 if ( moduleName ) {
566 name = moduleName->getCStringNoCopy();
9bccf70c 567 k_info = kmod_lookupbyname_locked((char *)name);
1c79356b
A
568 if ( k_info && (k_info->reference_count < 1) ) {
569 if ( k_info->stop &&
9bccf70c
A
570 !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) {
571
572 kfree(k_info, sizeof(kmod_info_t));
1c79356b 573 return ret;
9bccf70c 574 }
1c79356b
A
575
576 ret = kmod_destroy(host_priv_self(), k_info->id);
577 }
578 }
9bccf70c
A
579
580 if (k_info) {
581 kfree(k_info, sizeof(kmod_info_t));
582 }
1c79356b
A
583
584 return ret;
585}
586
587static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
588{
589 OSCollectionIterator * tables;
1c79356b
A
590 OSDictionary * dict;
591 OSIterator * iter;
592 OSArray * arrayCopy;
593 IOService * service;
594 IOReturn ret;
595
596 if ( !matching )
597 return kIOReturnBadArgument;
598
599 ret = kIOReturnSuccess;
600 dict = 0;
601 iter = IORegistryIterator::iterateOver(gIOServicePlane,
602 kIORegistryIterateRecursively);
603 if ( !iter )
604 return kIOReturnNoMemory;
605
606 UniqueProperties( matching );
607
1c79356b
A
608 // terminate instances.
609 do {
610 iter->reset();
611 while( (service = (IOService *)iter->getNextObject()) ) {
612 dict = service->getPropertyTable();
613 if ( !dict )
614 continue;
615
9bccf70c
A
616 /* Terminate only for personalities that match the matching dictionary.
617 * This comparison must be done with only the keys in the
618 * "matching" dict to enable general matching.
619 */
1c79356b
A
620 if ( !dict->isEqualTo(matching, matching) )
621 continue;
622
623 if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) {
624 ret = kIOReturnUnsupported;
625 break;
626 }
627 }
628 } while( !service && !iter->isValid());
629 iter->release();
630
631 // remove configs from catalog.
632 if ( ret != kIOReturnSuccess )
633 return ret;
634
635 arrayCopy = OSArray::withCapacity(100);
636 if ( !arrayCopy )
637 return kIOReturnNoMemory;
638
639 tables = OSCollectionIterator::withCollection(arrayCopy);
640 arrayCopy->release();
641 if ( !tables )
642 return kIOReturnNoMemory;
643
644 arrayCopy->merge(array);
645 array->flushCollection();
646 tables->reset();
647 while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
9bccf70c
A
648
649 /* Remove from the catalogue's array any personalities
650 * that match the matching dictionary.
651 * This comparison must be done with only the keys in the
652 * "matching" dict to enable general matching.
653 */
1c79356b
A
654 if ( dict->isEqualTo(matching, matching) )
655 continue;
656
657 array->setObject(dict);
658 }
659
660 tables->release();
661
662 return ret;
663}
664
665IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
666{
667 IOReturn ret;
668
669 ret = kIOReturnSuccess;
670 IOTakeLock( lock );
671 ret = _terminateDrivers(array, matching);
672 kernelTables->reset();
673 IOUnlock( lock );
674
675 return ret;
676}
677
678IOReturn IOCatalogue::terminateDriversForModule(
679 OSString * moduleName,
680 bool unload )
681{
682 IOReturn ret;
683 OSDictionary * dict;
684
685 dict = OSDictionary::withCapacity(1);
686 if ( !dict )
687 return kIOReturnNoMemory;
688
689 dict->setObject(kModuleKey, moduleName);
9bccf70c 690
1c79356b
A
691 IOTakeLock( lock );
692
693 ret = _terminateDrivers(array, dict);
694 kernelTables->reset();
695
696 // Unload the module itself.
697 if ( unload && ret == kIOReturnSuccess ) {
698 // Do kmod stop first.
699 ret = unloadModule(moduleName);
700 }
701
702 IOUnlock( lock );
703
704 dict->release();
705
706 return ret;
707}
708
709IOReturn IOCatalogue::terminateDriversForModule(
710 const char * moduleName,
711 bool unload )
712{
713 OSString * name;
714 IOReturn ret;
715
716 name = OSString::withCString(moduleName);
717 if ( !name )
718 return kIOReturnNoMemory;
719
720 ret = terminateDriversForModule(name, unload);
721 name->release();
9bccf70c 722
1c79356b
A
723 return ret;
724}
725
726bool IOCatalogue::startMatching( OSDictionary * matching )
727{
728 OSDictionary * dict;
729 OSOrderedSet * set;
730
731 if ( !matching )
732 return false;
733
734 set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
735 (void *)gIOProbeScoreKey);
736 if ( !set )
737 return false;
738
739 IOTakeLock( lock );
740 kernelTables->reset();
741
742 while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
9bccf70c
A
743
744 /* This comparison must be done with only the keys in the
745 * "matching" dict to enable general matching.
746 */
1c79356b
A
747 if ( dict->isEqualTo(matching, matching) )
748 AddNewImports(set, dict);
749 }
750 // Start device matching.
751 if ( set->getCount() > 0 ) {
752 IOService::catalogNewDrivers(set);
753 generation++;
754 }
755
756 IOUnlock( lock );
757
758 set->release();
759
760 return true;
761}
762
763void IOCatalogue::reset(void)
764{
765 OSArray * tables;
766 OSDictionary * entry;
767 unsigned int count;
768
769 IOLog("Resetting IOCatalogue.\n");
770
771 IOTakeLock( lock );
772 tables = OSArray::withArray(array);
773 array->flushCollection();
774
775 count = tables->getCount();
776 while ( count-- ) {
777 entry = (OSDictionary *)tables->getObject(count);
778 if ( entry && !entry->getObject(kModuleKey) ) {
779 array->setObject(entry);
780 }
781 }
782
783 kernelTables->reset();
784 IOUnlock( lock );
785
786 tables->release();
787}
788
789bool IOCatalogue::serialize(OSSerialize * s) const
790{
791 bool ret;
792
793 if ( !s )
794 return false;
795
796 IOTakeLock( lock );
797 ret = array->serialize(s);
798 IOUnlock( lock );
799
800 return ret;
801}
802
803
804bool IOCatalogue::recordStartupExtensions(void) {
805 bool result = false;
806
0b4e3aa0
A
807 IOLockLock(kld_lock);
808 if (kernelLinkerPresent && record_startup_extensions_function) {
1c79356b
A
809 result = (*record_startup_extensions_function)();
810 } else {
811 IOLog("Can't record startup extensions; "
812 "kernel linker is not present.\n");
813 result = false;
814 }
0b4e3aa0 815 IOLockUnlock(kld_lock);
1c79356b
A
816
817 return result;
818}
819
820
821/*********************************************************************
822*********************************************************************/
823bool IOCatalogue::addExtensionsFromArchive(OSData * mkext) {
824 bool result = false;
825
0b4e3aa0
A
826 IOLockLock(kld_lock);
827 if (kernelLinkerPresent && add_from_mkext_function) {
1c79356b
A
828 result = (*add_from_mkext_function)(mkext);
829 } else {
830 IOLog("Can't add startup extensions from archive; "
831 "kernel linker is not present.\n");
832 result = false;
833 }
0b4e3aa0 834 IOLockUnlock(kld_lock);
1c79356b
A
835
836 return result;
837}
838
839
840/*********************************************************************
841* This function clears out all references to the in-kernel linker,
842* frees the list of startup extensions in extensionDict, and
843* deallocates the kernel's __KLD segment to reclaim that memory.
844*********************************************************************/
845kern_return_t IOCatalogue::removeKernelLinker(void) {
846 kern_return_t result = KERN_SUCCESS;
847 extern struct mach_header _mh_execute_header;
848 struct segment_command * segment;
849 char * dt_segment_name;
850 void * segment_paddress;
851 int segment_size;
852
853 /* This must be the very first thing done by this function.
854 */
0b4e3aa0 855 IOLockLock(kld_lock);
1c79356b
A
856
857
858 /* If the kernel linker isn't here, that's automatically
859 * a success.
860 */
861 if (!kernelLinkerPresent) {
862 result = KERN_SUCCESS;
863 goto finish;
864 }
865
866 IOLog("Jettisoning kernel linker.\n");
867
868 kernelLinkerPresent = 0;
869
870 /* Set the kmod_load_extension function as the means for loading
871 * a kernel extension.
872 */
873 kmod_load_function = &kmod_load_extension;
874
875 record_startup_extensions_function = 0;
876 add_from_mkext_function = 0;
877 remove_startup_extension_function = 0;
878
879
880 /* Invoke destructors for the __KLD and __LINKEDIT segments.
881 * Do this for all segments before actually freeing their
882 * memory so that any cross-dependencies (not that there
883 * should be any) are handled.
884 */
885 segment = getsegbynamefromheader(
886 &_mh_execute_header, "__KLD");
887 if (!segment) {
9bccf70c 888 IOLog("error removing kernel linker: can't find __KLD segment\n");
1c79356b
A
889 result = KERN_FAILURE;
890 goto finish;
891 }
892 OSRuntimeUnloadCPPForSegment(segment);
893
894 segment = getsegbynamefromheader(
895 &_mh_execute_header, "__LINKEDIT");
896 if (!segment) {
9bccf70c 897 IOLog("error removing kernel linker: can't find __LINKEDIT segment\n");
1c79356b
A
898 result = KERN_FAILURE;
899 goto finish;
900 }
901 OSRuntimeUnloadCPPForSegment(segment);
902
903
904 /* Free the memory that was set up by bootx.
905 */
906 dt_segment_name = "Kernel-__KLD";
907 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
908 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
909 (int)segment_size);
910 }
911
912 dt_segment_name = "Kernel-__LINKEDIT";
913 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
914 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
915 (int)segment_size);
916 }
917
918
919finish:
920
921 /* This must be the very last thing done before returning.
922 */
0b4e3aa0 923 IOLockUnlock(kld_lock);
1c79356b
A
924
925 return result;
926}