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