2 * Copyright (c) 2000 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach/kmod.h>
30 #include <libkern/kernel_mach_header.h>
31 #include <libkern/prelink.h>
34 #include <libkern/version.h>
35 #include <libkern/c++/OSContainers.h>
36 #include <libkern/OSKextLibPrivate.h>
37 #include <libkern/c++/OSKext.h>
38 #include <IOKit/IOLib.h>
39 #include <IOKit/IOService.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOCatalogue.h>
44 #pragma mark Bootstrap Declarations
46 /*********************************************************************
47 * Bootstrap Declarations
49 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
50 * code from other parts of the kernel, so function symbols are not
51 * exported; rather pointers to those functions are exported.
53 * xxx - need to think about locking for handling the 'weak' refs.
54 * xxx - do export a non-KLD function that says you've called a
55 * xxx - bootstrap function that has been removed.
57 * ALL call-ins to this segment of the kernel must be done through
58 * exported pointers. The symbols themselves are private and not to
60 *********************************************************************/
62 extern void (*record_startup_extensions_function
)(void);
63 extern void (*load_security_extensions_function
)(void);
66 static void bootstrapRecordStartupExtensions(void);
67 static void bootstrapLoadSecurityExtensions(void);
73 /*********************************************************************
75 *********************************************************************/
76 #define CONST_STRLEN(str) (sizeof(str) - 1)
79 #pragma mark Kernel Component Kext Identifiers
81 /*********************************************************************
82 * Kernel Component Kext Identifiers
84 * We could have each kernel resource kext automatically "load" as
85 * it's created, but it's nicer to have them listed in kextstat in
86 * the order of this list. We'll walk through this after setting up
87 * all the boot kexts and have them load up.
88 *********************************************************************/
89 static const char * sKernelComponentNames
[] = {
90 // The kexts for these IDs must have a version matching 'osrelease'.
94 "com.apple.kpi.iokit",
95 "com.apple.kpi.libkern",
97 "com.apple.kpi.private",
98 "com.apple.kpi.unsupported",
99 "com.apple.iokit.IONVRAMFamily",
100 "com.apple.driver.AppleNMI",
101 "com.apple.iokit.IOSystemManagementFamily",
102 "com.apple.iokit.ApplePlatformFamily",
104 #if defined(__i386__) || defined(__arm__)
105 /* These ones are not supported on x86_64 or any newer platforms.
106 * They must be version 7.9.9; check by "com.apple.kernel.", with
107 * the trailing period; "com.apple.kernel" always represents the
108 * current kernel version.
110 "com.apple.kernel.6.0",
111 "com.apple.kernel.bsd",
112 "com.apple.kernel.iokit",
113 "com.apple.kernel.libkern",
114 "com.apple.kernel.mach",
121 #pragma mark KLDBootstrap Class
123 /*********************************************************************
126 * We use a C++ class here so that it can be a friend of OSKext and
127 * get at private stuff. We can't hide the class itself, but we can
128 * hide the instance through which we invoke the functions.
129 *********************************************************************/
131 friend void bootstrapRecordStartupExtensions(void);
132 friend void bootstrapLoadSecurityExtensions(void);
135 void readStartupExtensions(void);
137 void readPrelinkedExtensions(
138 kernel_section_t
* prelinkInfoSect
);
139 void readBooterExtensions(void);
140 OSReturn
readMkextExtensions(
141 OSString
* deviceTreeName
,
142 OSData
* deviceTreeData
);
144 OSReturn
loadKernelComponentKexts(void);
145 void readBuiltinPersonalities(void);
147 void loadSecurityExtensions(void);
154 static KLDBootstrap sBootstrapObject
;
156 /*********************************************************************
157 * Set the function pointers for the entry points into the bootstrap
158 * segment upon C++ static constructor invocation.
159 *********************************************************************/
160 KLDBootstrap::KLDBootstrap(void)
162 if (this != &sBootstrapObject
) {
163 panic("Attempt to access bootstrap segment.");
165 record_startup_extensions_function
= &bootstrapRecordStartupExtensions
;
166 load_security_extensions_function
= &bootstrapLoadSecurityExtensions
;
169 /*********************************************************************
170 * Clear the function pointers for the entry points into the bootstrap
171 * segment upon C++ static destructor invocation.
172 *********************************************************************/
173 KLDBootstrap::~KLDBootstrap(void)
175 if (this != &sBootstrapObject
) {
176 panic("Attempt to access bootstrap segment.");
180 record_startup_extensions_function
= 0;
181 load_security_extensions_function
= 0;
184 /*********************************************************************
185 *********************************************************************/
187 KLDBootstrap::readStartupExtensions(void)
189 kernel_section_t
* prelinkInfoSect
= NULL
; // do not free
191 OSKextLog(/* kext */ NULL
,
192 kOSKextLogProgressLevel
|
193 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
|
194 kOSKextLogKextBookkeepingFlag
,
195 "Reading startup extensions.");
197 /* If the prelink info segment has a nonzero size, we are prelinked
198 * and won't have any individual kexts or mkexts to read.
199 * Otherwise, we need to read kexts or the mkext from what the booter
202 prelinkInfoSect
= getsectbyname(kPrelinkInfoSegment
, kPrelinkInfoSection
);
203 if (prelinkInfoSect
->size
) {
204 readPrelinkedExtensions(prelinkInfoSect
);
206 readBooterExtensions();
209 loadKernelComponentKexts();
210 readBuiltinPersonalities();
211 OSKext::sendAllKextPersonalitiesToCatalog();
216 /*********************************************************************
217 *********************************************************************/
219 KLDBootstrap::readPrelinkedExtensions(
220 kernel_section_t
* prelinkInfoSect
)
222 OSArray
* infoDictArray
= NULL
; // do not release
223 OSObject
* parsedXML
= NULL
; // must release
224 OSDictionary
* prelinkInfoDict
= NULL
; // do not release
225 OSString
* errorString
= NULL
; // must release
226 OSKext
* theKernel
= NULL
; // must release
228 kernel_segment_command_t
* prelinkTextSegment
= NULL
; // see code
229 kernel_segment_command_t
* prelinkInfoSegment
= NULL
; // see code
231 /* We make some copies of data, but if anything fails we're basically
232 * going to fail the boot, so these won't be cleaned up on error.
234 void * prelinkData
= NULL
; // see code
235 vm_size_t prelinkLength
= 0;
237 #if !__LP64__ && !defined(__arm__)
238 vm_map_offset_t prelinkDataMapOffset
= 0;
239 void * prelinkCopy
= NULL
; // see code
240 kern_return_t mem_result
= KERN_SUCCESS
;
243 OSDictionary
* infoDict
= NULL
; // do not release
245 IORegistryEntry
* registryRoot
= NULL
; // do not release
246 OSNumber
* prelinkCountObj
= NULL
; // must release
250 OSKextLog(/* kext */ NULL
,
251 kOSKextLogProgressLevel
|
252 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
253 "Starting from prelinked kernel.");
255 prelinkTextSegment
= getsegbyname(kPrelinkTextSegment
);
256 if (!prelinkTextSegment
) {
257 OSKextLog(/* kext */ NULL
,
258 kOSKextLogErrorLevel
|
259 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
260 "Can't find prelinked kexts' text segment.");
264 prelinkData
= (void *) prelinkTextSegment
->vmaddr
;
265 prelinkLength
= prelinkTextSegment
->vmsize
;
267 #if !__LP64__ && !__arm__
268 /* XXX: arm's pmap implementation doesn't seem to let us do this */
270 /* To enable paging and write/execute protections on the kext
271 * executables, we need to copy them out of the booter-created
272 * memory, reallocate that space with VM, then prelinkCopy them back in.
273 * This isn't necessary on LP64 because kexts have their own VM
274 * region on that architecture model.
277 mem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&prelinkCopy
,
279 if (mem_result
!= KERN_SUCCESS
) {
280 OSKextLog(/* kext */ NULL
,
281 kOSKextLogErrorLevel
|
282 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
283 "Can't copy prelinked kexts' text for VM reassign.");
289 memcpy(prelinkCopy
, prelinkData
, prelinkLength
);
291 /* Dump the booter memory.
293 ml_static_mfree((vm_offset_t
)prelinkData
, prelinkLength
);
295 /* Set up the VM region.
297 prelinkDataMapOffset
= (vm_map_offset_t
)(uintptr_t)prelinkData
;
298 mem_result
= vm_map_enter_mem_object(
300 &prelinkDataMapOffset
,
301 prelinkLength
, /* mask */ 0,
302 VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
,
304 (vm_object_offset_t
) 0,
306 /* cur_protection */ VM_PROT_ALL
,
307 /* max_protection */ VM_PROT_ALL
,
308 /* inheritance */ VM_INHERIT_DEFAULT
);
309 if ((mem_result
!= KERN_SUCCESS
) ||
310 (prelinkTextSegment
->vmaddr
!= prelinkDataMapOffset
))
312 OSKextLog(/* kext */ NULL
,
313 kOSKextLogErrorLevel
|
314 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
315 "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).",
316 (unsigned long long) prelinkDataMapOffset
, prelinkLength
, mem_result
);
319 prelinkData
= (void *)(uintptr_t)prelinkDataMapOffset
;
323 memcpy(prelinkData
, prelinkCopy
, prelinkLength
);
325 kmem_free(kernel_map
, (vm_offset_t
)prelinkCopy
, prelinkLength
);
326 #endif /* !__LP64__ && !__arm__*/
328 /* Unserialize the info dictionary from the prelink info section.
330 parsedXML
= OSUnserializeXML((const char *)prelinkInfoSect
->addr
,
333 prelinkInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
335 if (!prelinkInfoDict
) {
336 const char * errorCString
= "(unknown error)";
338 if (errorString
&& errorString
->getCStringNoCopy()) {
339 errorCString
= errorString
->getCStringNoCopy();
340 } else if (parsedXML
) {
341 errorCString
= "not a dictionary";
343 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
344 "Error unserializing prelink plist: %s.", errorCString
);
348 infoDictArray
= OSDynamicCast(OSArray
,
349 prelinkInfoDict
->getObject(kPrelinkInfoDictionaryKey
));
350 if (!infoDictArray
) {
351 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
352 "The prelinked kernel has no kext info dictionaries");
356 /* Create OSKext objects for each info dictionary.
358 for (i
= 0; i
< infoDictArray
->getCount(); ++i
) {
359 infoDict
= OSDynamicCast(OSDictionary
, infoDictArray
->getObject(i
));
361 OSKextLog(/* kext */ NULL
,
362 kOSKextLogErrorLevel
|
363 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
364 "Can't find info dictionary for prelinked kext #%d.", i
);
368 /* Create the kext for the entry, then release it, because the
369 * kext system keeps them around until explicitly removed.
370 * Any creation/registration failures are already logged for us.
372 OSKext
* newKext
= OSKext::withPrelinkedInfoDict(infoDict
);
373 OSSafeReleaseNULL(newKext
);
376 /* Store the number of prelinked kexts in the registry so we can tell
377 * when the system has been started from a prelinked kernel.
379 registryRoot
= IORegistryEntry::getRegistryRoot();
380 assert(registryRoot
);
382 prelinkCountObj
= OSNumber::withNumber(
383 (unsigned long long)infoDictArray
->getCount(),
384 8 * sizeof(uint32_t));
385 assert(prelinkCountObj
);
386 if (prelinkCountObj
) {
387 registryRoot
->setProperty(kOSPrelinkKextCountKey
, prelinkCountObj
);
390 OSKextLog(/* kext */ NULL
,
391 kOSKextLogProgressLevel
|
392 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
393 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
394 "%u prelinked kexts",
395 infoDictArray
->getCount());
398 /* On LP64 systems, kexts are copied to their own special VM region
399 * during OSKext init time, so we can free the whole segment now.
401 ml_static_mfree((vm_offset_t
) prelinkData
, prelinkLength
);
402 #endif /* __LP64__ */
404 /* Free the prelink info segment, we're done with it.
406 prelinkInfoSegment
= getsegbyname(kPrelinkInfoSegment
);
407 if (prelinkInfoSegment
) {
408 ml_static_mfree((vm_offset_t
)prelinkInfoSegment
->vmaddr
,
409 (vm_size_t
)prelinkInfoSegment
->vmsize
);
413 OSSafeRelease(errorString
);
414 OSSafeRelease(parsedXML
);
415 OSSafeRelease(theKernel
);
416 OSSafeRelease(prelinkCountObj
);
420 /*********************************************************************
421 *********************************************************************/
422 #define BOOTER_KEXT_PREFIX "Driver-"
423 #define BOOTER_MKEXT_PREFIX "DriversPackage-"
425 typedef struct _DeviceTreeBuffer
{
431 KLDBootstrap::readBooterExtensions(void)
433 IORegistryEntry
* booterMemoryMap
= NULL
; // must release
434 OSDictionary
* propertyDict
= NULL
; // must release
435 OSCollectionIterator
* keyIterator
= NULL
; // must release
436 OSString
* deviceTreeName
= NULL
; // do not release
438 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not free
439 char * booterDataPtr
= NULL
; // do not free
440 OSData
* booterData
= NULL
; // must release
442 OSKext
* aKext
= NULL
; // must release
444 OSKextLog(/* kext */ NULL
,
445 kOSKextLogProgressLevel
|
446 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
447 "Reading startup extensions/mkexts from booter memory.");
449 booterMemoryMap
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
451 if (!booterMemoryMap
) {
452 OSKextLog(/* kext */ NULL
,
453 kOSKextLogErrorLevel
|
454 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
,
455 "Can't read booter memory map.");
459 propertyDict
= booterMemoryMap
->dictionaryWithProperties();
461 OSKextLog(/* kext */ NULL
,
462 kOSKextLogErrorLevel
|
463 kOSKextLogDirectoryScanFlag
,
464 "Can't get property dictionary from memory map.");
468 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
470 OSKextLog(/* kext */ NULL
,
471 kOSKextLogErrorLevel
|
472 kOSKextLogGeneralFlag
,
473 "Can't allocate iterator for driver images.");
477 while ( ( deviceTreeName
=
478 OSDynamicCast(OSString
, keyIterator
->getNextObject() ))) {
480 boolean_t isMkext
= FALSE
;
481 const char * devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
482 OSData
* deviceTreeEntry
= OSDynamicCast(OSData
,
483 propertyDict
->getObject(deviceTreeName
));
485 /* Clear out the booterData from the prior iteration.
487 OSSafeReleaseNULL(booterData
);
489 /* If there is no entry for the name, we can't do much with it. */
490 if (!deviceTreeEntry
) {
494 /* Make sure it is either a kext or an mkext */
495 if (!strncmp(devTreeNameCString
, BOOTER_KEXT_PREFIX
,
496 CONST_STRLEN(BOOTER_KEXT_PREFIX
))) {
500 } else if (!strncmp(devTreeNameCString
, BOOTER_MKEXT_PREFIX
,
501 CONST_STRLEN(BOOTER_MKEXT_PREFIX
))) {
509 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
510 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
511 if (!deviceTreeBuffer
) {
512 /* We can't get to the data, so we can't do anything,
513 * not even free it from physical memory (if it's there).
515 OSKextLog(/* kext */ NULL
,
516 kOSKextLogErrorLevel
|
517 kOSKextLogDirectoryScanFlag
,
518 "Device tree entry %s has NULL pointer.",
520 goto finish
; // xxx - continue, panic?
523 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
524 if (!booterDataPtr
) {
525 OSKextLog(/* kext */ NULL
,
526 kOSKextLogErrorLevel
|
527 kOSKextLogDirectoryScanFlag
,
528 "Can't get virtual address for device tree mkext entry %s.",
533 /* Wrap the booter data buffer in an OSData and set a dealloc function
534 * so it will take care of the physical memory when freed. Kexts will
535 * retain the booterData for as long as they need it. Remove the entry
536 * from the booter memory map after this is done.
538 booterData
= OSData::withBytesNoCopy(booterDataPtr
,
539 deviceTreeBuffer
->length
);
541 OSKextLog(/* kext */ NULL
,
542 kOSKextLogErrorLevel
|
543 kOSKextLogGeneralFlag
,
544 "Error - Can't allocate OSData wrapper for device tree entry %s.",
548 booterData
->setDeallocFunction(osdata_phys_free
);
551 readMkextExtensions(deviceTreeName
, booterData
);
553 /* Create the kext for the entry, then release it, because the
554 * kext system keeps them around until explicitly removed.
555 * Any creation/registration failures are already logged for us.
557 OSKext
* newKext
= OSKext::withBooterData(deviceTreeName
, booterData
);
558 OSSafeRelease(newKext
);
561 booterMemoryMap
->removeProperty(deviceTreeName
);
563 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
567 OSSafeRelease(booterMemoryMap
);
568 OSSafeRelease(propertyDict
);
569 OSSafeRelease(keyIterator
);
570 OSSafeRelease(booterData
);
571 OSSafeRelease(aKext
);
575 /*********************************************************************
576 *********************************************************************/
578 KLDBootstrap::readMkextExtensions(
579 OSString
* deviceTreeName
,
582 OSReturn result
= kOSReturnError
;
585 IORegistryEntry
* registryRoot
= NULL
; // do not release
586 OSData
* checksumObj
= NULL
; // must release
588 OSKextLog(/* kext */ NULL
,
589 kOSKextLogStepLevel
|
590 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
591 "Reading startup mkext archive from device tree entry %s.",
592 deviceTreeName
->getCStringNoCopy());
594 /* If we successfully read the archive,
595 * then save the mkext's checksum in the IORegistry.
596 * assumes we'll only ever have one mkext to boot
598 result
= OSKext::readMkextArchive(booterData
, &checksum
);
599 if (result
== kOSReturnSuccess
) {
601 OSKextLog(/* kext */ NULL
,
602 kOSKextLogProgressLevel
|
603 kOSKextLogArchiveFlag
,
604 "Startup mkext archive has checksum 0x%x.", (int)checksum
);
606 registryRoot
= IORegistryEntry::getRegistryRoot();
607 assert(registryRoot
);
608 checksumObj
= OSData::withBytes((void *)&checksum
, sizeof(checksum
));
611 registryRoot
->setProperty(kOSStartupMkextCRC
, checksumObj
);
618 /*********************************************************************
619 *********************************************************************/
620 #define COM_APPLE "com.apple."
623 KLDBootstrap::loadSecurityExtensions(void)
625 OSDictionary
* extensionsDict
= NULL
; // must release
626 OSCollectionIterator
* keyIterator
= NULL
; // must release
627 OSString
* bundleID
= NULL
; // don't release
628 OSKext
* theKext
= NULL
; // don't release
629 OSBoolean
* isSecurityKext
= NULL
; // don't release
631 OSKextLog(/* kext */ NULL
,
632 kOSKextLogStepLevel
|
634 "Loading security extensions.");
636 extensionsDict
= OSKext::copyKexts();
637 if (!extensionsDict
) {
641 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
643 OSKextLog(/* kext */ NULL
,
644 kOSKextLogErrorLevel
|
645 kOSKextLogGeneralFlag
,
646 "Failed to allocate iterator for security extensions.");
650 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
652 const char * bundle_id
= bundleID
->getCStringNoCopy();
654 /* Skip extensions whose bundle IDs don't start with "com.apple.".
657 (strncmp(bundle_id
, COM_APPLE
, CONST_STRLEN(COM_APPLE
)) != 0)) {
662 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
667 isSecurityKext
= OSDynamicCast(OSBoolean
,
668 theKext
->getPropertyForHostArch("AppleSecurityExtension"));
669 if (isSecurityKext
&& isSecurityKext
->isTrue()) {
670 OSKextLog(/* kext */ NULL
,
671 kOSKextLogStepLevel
|
673 "Loading security extension %s.", bundleID
->getCStringNoCopy());
674 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
675 /* allowDefer */ false);
680 OSSafeRelease(keyIterator
);
681 OSSafeRelease(extensionsDict
);
686 /*********************************************************************
687 * We used to require that all listed kernel components load, but
688 * nowadays we can get them from userland so we only try to load the
689 * ones we have. If an error occurs later, such is life.
691 * Note that we look the kexts up first, so we can avoid spurious
692 * (in this context, anyhow) log messages about kexts not being found.
694 * xxx - do we even need to do this any more? Check if the kernel
695 * xxx - compoonents just load in the regular paths
696 *********************************************************************/
698 KLDBootstrap::loadKernelComponentKexts(void)
700 OSReturn result
= kOSReturnSuccess
; // optimistic
701 OSKext
* theKext
= NULL
; // must release
702 const char ** kextIDPtr
= NULL
; // do not release
704 for (kextIDPtr
= &sKernelComponentNames
[0]; *kextIDPtr
; kextIDPtr
++) {
706 OSSafeReleaseNULL(theKext
);
707 theKext
= OSKext::lookupKextWithIdentifier(*kextIDPtr
);
710 if (kOSReturnSuccess
!= OSKext::loadKextWithIdentifier(
711 *kextIDPtr
, /* allowDefer */ false)) {
713 // xxx - check KextBookkeeping, might be redundant
714 OSKextLog(/* kext */ NULL
,
715 kOSKextLogErrorLevel
|
716 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
717 "Failed to initialize kernel component %s.", *kextIDPtr
);
718 result
= kOSReturnError
;
723 OSSafeRelease(theKext
);
727 /*********************************************************************
728 *********************************************************************/
730 KLDBootstrap::readBuiltinPersonalities(void)
732 OSObject
* parsedXML
= NULL
; // must release
733 OSArray
* builtinExtensions
= NULL
; // do not release
734 OSArray
* allPersonalities
= NULL
; // must release
735 OSString
* errorString
= NULL
; // must release
736 kernel_section_t
* infosect
= NULL
; // do not free
737 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
738 unsigned int count
, i
;
740 OSKextLog(/* kext */ NULL
,
741 kOSKextLogStepLevel
|
743 "Reading built-in kernel personalities for I/O Kit drivers.");
745 /* Look in the __BUILTIN __info segment for an array of Info.plist
746 * entries. For each one, extract the personalities dictionary, add
747 * it to our array, then push them all (without matching) to
748 * the IOCatalogue. This can be used to augment the personalities
749 * in gIOKernelConfigTables, especially when linking entire kexts into
750 * the mach_kernel image.
752 infosect
= getsectbyname("__BUILTIN", "__info");
758 parsedXML
= OSUnserializeXML((const char *) (uintptr_t)infosect
->addr
,
761 builtinExtensions
= OSDynamicCast(OSArray
, parsedXML
);
763 if (!builtinExtensions
) {
764 const char * errorCString
= "(unknown error)";
766 if (errorString
&& errorString
->getCStringNoCopy()) {
767 errorCString
= errorString
->getCStringNoCopy();
768 } else if (parsedXML
) {
769 errorCString
= "not an array";
771 OSKextLog(/* kext */ NULL
,
772 kOSKextLogErrorLevel
|
774 "Error unserializing built-in personalities: %s.", errorCString
);
778 // estimate 3 personalities per Info.plist/kext
779 count
= builtinExtensions
->getCount();
780 allPersonalities
= OSArray::withCapacity(count
* 3);
782 for (i
= 0; i
< count
; i
++) {
783 OSDictionary
* infoDict
= NULL
; // do not release
784 OSString
* moduleName
= NULL
; // do not release
785 OSDictionary
* personalities
; // do not release
786 OSString
* personalityName
; // do not release
788 OSSafeReleaseNULL(personalitiesIterator
);
790 infoDict
= OSDynamicCast(OSDictionary
,
791 builtinExtensions
->getObject(i
));
796 moduleName
= OSDynamicCast(OSString
,
797 infoDict
->getObject(kCFBundleIdentifierKey
));
802 OSKextLog(/* kext */ NULL
,
803 kOSKextLogStepLevel
|
805 "Adding personalities for built-in driver %s:",
806 moduleName
->getCStringNoCopy());
808 personalities
= OSDynamicCast(OSDictionary
,
809 infoDict
->getObject("IOKitPersonalities"));
810 if (!personalities
) {
814 personalitiesIterator
= OSCollectionIterator::withCollection(personalities
);
815 if (!personalitiesIterator
) {
816 continue; // xxx - well really, what can we do? should we panic?
819 while ((personalityName
= OSDynamicCast(OSString
,
820 personalitiesIterator
->getNextObject()))) {
822 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
823 personalities
->getObject(personalityName
));
825 OSKextLog(/* kext */ NULL
,
826 kOSKextLogDetailLevel
|
828 "Adding built-in driver personality %s.",
829 personalityName
->getCStringNoCopy());
831 if (personality
&& !personality
->getObject(kCFBundleIdentifierKey
)) {
832 personality
->setObject(kCFBundleIdentifierKey
, moduleName
);
834 allPersonalities
->setObject(personality
);
838 gIOCatalogue
->addDrivers(allPersonalities
, false);
841 OSSafeRelease(parsedXML
);
842 OSSafeRelease(allPersonalities
);
843 OSSafeRelease(errorString
);
844 OSSafeRelease(personalitiesIterator
);
849 #pragma mark Bootstrap Functions
851 /*********************************************************************
852 * Bootstrap Functions
853 *********************************************************************/
854 static void bootstrapRecordStartupExtensions(void)
856 sBootstrapObject
.readStartupExtensions();
860 static void bootstrapLoadSecurityExtensions(void)
862 sBootstrapObject
.loadSecurityExtensions();