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