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 #define KASLR_KEXT_DEBUG 0
48 #pragma mark Bootstrap Declarations
50 /*********************************************************************
51 * Bootstrap Declarations
53 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
54 * code from other parts of the kernel, so function symbols are not
55 * exported; rather pointers to those functions are exported.
57 * xxx - need to think about locking for handling the 'weak' refs.
58 * xxx - do export a non-KLD function that says you've called a
59 * xxx - bootstrap function that has been removed.
61 * ALL call-ins to this segment of the kernel must be done through
62 * exported pointers. The symbols themselves are private and not to
64 *********************************************************************/
66 extern void (*record_startup_extensions_function
)(void);
67 extern void (*load_security_extensions_function
)(void);
70 static void bootstrapRecordStartupExtensions(void);
71 static void bootstrapLoadSecurityExtensions(void);
77 /*********************************************************************
79 *********************************************************************/
80 #define CONST_STRLEN(str) (sizeof(str) - 1)
83 #pragma mark Kernel Component Kext Identifiers
85 /*********************************************************************
86 * Kernel Component Kext Identifiers
88 * We could have each kernel resource kext automatically "load" as
89 * it's created, but it's nicer to have them listed in kextstat in
90 * the order of this list. We'll walk through this after setting up
91 * all the boot kexts and have them load up.
92 *********************************************************************/
93 static const char * sKernelComponentNames
[] = {
94 // The kexts for these IDs must have a version matching 'osrelease'.
98 "com.apple.kpi.iokit",
99 "com.apple.kpi.libkern",
100 "com.apple.kpi.mach",
101 "com.apple.kpi.private",
102 "com.apple.kpi.unsupported",
103 "com.apple.iokit.IONVRAMFamily",
104 "com.apple.driver.AppleNMI",
105 "com.apple.iokit.IOSystemManagementFamily",
106 "com.apple.iokit.ApplePlatformFamily",
111 #pragma mark KLDBootstrap Class
113 /*********************************************************************
116 * We use a C++ class here so that it can be a friend of OSKext and
117 * get at private stuff. We can't hide the class itself, but we can
118 * hide the instance through which we invoke the functions.
119 *********************************************************************/
121 friend void bootstrapRecordStartupExtensions(void);
122 friend void bootstrapLoadSecurityExtensions(void);
125 void readStartupExtensions(void);
127 void readPrelinkedExtensions(
128 kernel_section_t
* prelinkInfoSect
);
129 void readBooterExtensions(void);
130 OSReturn
readMkextExtensions(
131 OSString
* deviceTreeName
,
132 OSData
* deviceTreeData
);
134 OSReturn
loadKernelComponentKexts(void);
135 void loadKernelExternalComponents(void);
136 void readBuiltinPersonalities(void);
138 void loadSecurityExtensions(void);
145 static KLDBootstrap sBootstrapObject
;
147 /*********************************************************************
148 * Set the function pointers for the entry points into the bootstrap
149 * segment upon C++ static constructor invocation.
150 *********************************************************************/
151 KLDBootstrap::KLDBootstrap(void)
153 if (this != &sBootstrapObject
) {
154 panic("Attempt to access bootstrap segment.");
156 record_startup_extensions_function
= &bootstrapRecordStartupExtensions
;
157 load_security_extensions_function
= &bootstrapLoadSecurityExtensions
;
160 /*********************************************************************
161 * Clear the function pointers for the entry points into the bootstrap
162 * segment upon C++ static destructor invocation.
163 *********************************************************************/
164 KLDBootstrap::~KLDBootstrap(void)
166 if (this != &sBootstrapObject
) {
167 panic("Attempt to access bootstrap segment.");
171 record_startup_extensions_function
= 0;
172 load_security_extensions_function
= 0;
175 /*********************************************************************
176 *********************************************************************/
178 KLDBootstrap::readStartupExtensions(void)
180 kernel_section_t
* prelinkInfoSect
= NULL
; // do not free
182 OSKextLog(/* kext */ NULL
,
183 kOSKextLogProgressLevel
|
184 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
|
185 kOSKextLogKextBookkeepingFlag
,
186 "Reading startup extensions.");
188 /* If the prelink info segment has a nonzero size, we are prelinked
189 * and won't have any individual kexts or mkexts to read.
190 * Otherwise, we need to read kexts or the mkext from what the booter
193 prelinkInfoSect
= getsectbyname(kPrelinkInfoSegment
, kPrelinkInfoSection
);
194 if (prelinkInfoSect
->size
) {
195 readPrelinkedExtensions(prelinkInfoSect
);
197 readBooterExtensions();
200 loadKernelComponentKexts();
201 loadKernelExternalComponents();
202 readBuiltinPersonalities();
203 OSKext::sendAllKextPersonalitiesToCatalog();
208 /*********************************************************************
209 *********************************************************************/
211 KLDBootstrap::readPrelinkedExtensions(
212 kernel_section_t
* prelinkInfoSect
)
214 OSArray
* infoDictArray
= NULL
; // do not release
215 OSObject
* parsedXML
= NULL
; // must release
216 OSDictionary
* prelinkInfoDict
= NULL
; // do not release
217 OSString
* errorString
= NULL
; // must release
218 OSKext
* theKernel
= NULL
; // must release
220 kernel_segment_command_t
* prelinkTextSegment
= NULL
; // see code
221 kernel_segment_command_t
* prelinkInfoSegment
= NULL
; // see code
223 /* We make some copies of data, but if anything fails we're basically
224 * going to fail the boot, so these won't be cleaned up on error.
226 void * prelinkData
= NULL
; // see code
227 vm_size_t prelinkLength
= 0;
230 vm_map_offset_t prelinkDataMapOffset
= 0;
231 void * prelinkCopy
= NULL
; // see code
232 kern_return_t mem_result
= KERN_SUCCESS
;
235 OSDictionary
* infoDict
= NULL
; // do not release
237 IORegistryEntry
* registryRoot
= NULL
; // do not release
238 OSNumber
* prelinkCountObj
= NULL
; // must release
242 bool developerDevice
;
245 OSKextLog(/* kext */ NULL
,
246 kOSKextLogProgressLevel
|
247 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
248 "Starting from prelinked kernel.");
250 prelinkTextSegment
= getsegbyname(kPrelinkTextSegment
);
251 if (!prelinkTextSegment
) {
252 OSKextLog(/* kext */ NULL
,
253 kOSKextLogErrorLevel
|
254 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
255 "Can't find prelinked kexts' text segment.");
260 unsigned long scratchSize
;
261 vm_offset_t scratchAddr
;
263 IOLog("kaslr: prelinked kernel address info: \n");
265 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__TEXT", &scratchSize
);
266 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
267 (unsigned long)scratchAddr
,
268 (unsigned long)(scratchAddr
+ scratchSize
),
271 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__DATA", &scratchSize
);
272 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
273 (unsigned long)scratchAddr
,
274 (unsigned long)(scratchAddr
+ scratchSize
),
277 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__LINKEDIT", &scratchSize
);
278 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
279 (unsigned long)scratchAddr
,
280 (unsigned long)(scratchAddr
+ scratchSize
),
283 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__KLD", &scratchSize
);
284 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
285 (unsigned long)scratchAddr
,
286 (unsigned long)(scratchAddr
+ scratchSize
),
289 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__PRELINK_TEXT", &scratchSize
);
290 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
291 (unsigned long)scratchAddr
,
292 (unsigned long)(scratchAddr
+ scratchSize
),
295 scratchAddr
= (vm_offset_t
) getsegdatafromheader(&_mh_execute_header
, "__PRELINK_INFO", &scratchSize
);
296 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
297 (unsigned long)scratchAddr
,
298 (unsigned long)(scratchAddr
+ scratchSize
),
302 prelinkData
= (void *) prelinkTextSegment
->vmaddr
;
303 prelinkLength
= prelinkTextSegment
->vmsize
;
306 /* To enable paging and write/execute protections on the kext
307 * executables, we need to copy them out of the booter-created
308 * memory, reallocate that space with VM, then prelinkCopy them back in.
310 * This isn't necessary on x86_64 because kexts have their own VM
311 * region for that architecture.
313 * XXX: arm's pmap implementation doesn't seem to let us do this.
316 mem_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&prelinkCopy
,
318 if (mem_result
!= KERN_SUCCESS
) {
319 OSKextLog(/* kext */ NULL
,
320 kOSKextLogErrorLevel
|
321 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
322 "Can't copy prelinked kexts' text for VM reassign.");
328 memcpy(prelinkCopy
, prelinkData
, prelinkLength
);
330 /* Dump the booter memory.
332 ml_static_mfree((vm_offset_t
)prelinkData
, prelinkLength
);
334 /* Set up the VM region.
336 prelinkDataMapOffset
= (vm_map_offset_t
)(uintptr_t)prelinkData
;
337 mem_result
= vm_map_enter_mem_object(
339 &prelinkDataMapOffset
,
340 prelinkLength
, /* mask */ 0,
341 VM_FLAGS_FIXED
| VM_FLAGS_OVERWRITE
,
343 (vm_object_offset_t
) 0,
345 /* cur_protection */ VM_PROT_ALL
,
346 /* max_protection */ VM_PROT_ALL
,
347 /* inheritance */ VM_INHERIT_DEFAULT
);
348 if ((mem_result
!= KERN_SUCCESS
) ||
349 (prelinkTextSegment
->vmaddr
!= prelinkDataMapOffset
))
351 OSKextLog(/* kext */ NULL
,
352 kOSKextLogErrorLevel
|
353 kOSKextLogGeneralFlag
| kOSKextLogArchiveFlag
,
354 "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).",
355 (unsigned long long) prelinkDataMapOffset
, prelinkLength
, mem_result
);
358 prelinkData
= (void *)(uintptr_t)prelinkDataMapOffset
;
362 memcpy(prelinkData
, prelinkCopy
, prelinkLength
);
364 kmem_free(kernel_map
, (vm_offset_t
)prelinkCopy
, prelinkLength
);
365 #endif /* __i386__ */
367 /* Unserialize the info dictionary from the prelink info section.
369 parsedXML
= OSUnserializeXML((const char *)prelinkInfoSect
->addr
,
372 prelinkInfoDict
= OSDynamicCast(OSDictionary
, parsedXML
);
374 if (!prelinkInfoDict
) {
375 const char * errorCString
= "(unknown error)";
377 if (errorString
&& errorString
->getCStringNoCopy()) {
378 errorCString
= errorString
->getCStringNoCopy();
379 } else if (parsedXML
) {
380 errorCString
= "not a dictionary";
382 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
383 "Error unserializing prelink plist: %s.", errorCString
);
388 /* Check if we should keep developer kexts around. Default:
392 * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
395 developerDevice
= true;
397 developerDevice
= false;
400 PE_parse_boot_argn("developer", &developerDevice
, sizeof(developerDevice
));
401 #endif /* NO_KEXTD */
403 infoDictArray
= OSDynamicCast(OSArray
,
404 prelinkInfoDict
->getObject(kPrelinkInfoDictionaryKey
));
405 if (!infoDictArray
) {
406 OSKextLog(/* kext */ NULL
, kOSKextLogErrorLevel
| kOSKextLogArchiveFlag
,
407 "The prelinked kernel has no kext info dictionaries");
411 /* Create OSKext objects for each info dictionary.
413 for (i
= 0; i
< infoDictArray
->getCount(); ++i
) {
414 infoDict
= OSDynamicCast(OSDictionary
, infoDictArray
->getObject(i
));
416 OSKextLog(/* kext */ NULL
,
417 kOSKextLogErrorLevel
|
418 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
419 "Can't find info dictionary for prelinked kext #%d.", i
);
424 /* If we're not on a developer device, skip and free developer kexts.
426 if (developerDevice
== false) {
427 OSBoolean
*devOnlyBool
= OSDynamicCast(OSBoolean
,
428 infoDict
->getObject(kOSBundleDeveloperOnlyKey
));
429 if (devOnlyBool
== kOSBooleanTrue
) {
430 OSString
*bundleID
= OSDynamicCast(OSString
,
431 infoDict
->getObject(kCFBundleIdentifierKey
));
433 OSKextLog(NULL
, kOSKextLogWarningLevel
| kOSKextLogGeneralFlag
,
434 "Kext %s not loading on non-dev device.", bundleID
->getCStringNoCopy());
437 OSNumber
*addressNum
= OSDynamicCast(OSNumber
,
438 infoDict
->getObject(kPrelinkExecutableLoadKey
));
439 OSNumber
*lengthNum
= OSDynamicCast(OSNumber
,
440 infoDict
->getObject(kPrelinkExecutableSizeKey
));
441 if (addressNum
&& lengthNum
) {
442 #error Pick the right way to free prelinked data on this arch
445 infoDictArray
->removeObject(i
--);
449 #endif /* NO_KEXTD */
451 /* Create the kext for the entry, then release it, because the
452 * kext system keeps them around until explicitly removed.
453 * Any creation/registration failures are already logged for us.
455 OSKext
* newKext
= OSKext::withPrelinkedInfoDict(infoDict
);
456 OSSafeReleaseNULL(newKext
);
459 /* Store the number of prelinked kexts in the registry so we can tell
460 * when the system has been started from a prelinked kernel.
462 registryRoot
= IORegistryEntry::getRegistryRoot();
463 assert(registryRoot
);
465 prelinkCountObj
= OSNumber::withNumber(
466 (unsigned long long)infoDictArray
->getCount(),
467 8 * sizeof(uint32_t));
468 assert(prelinkCountObj
);
469 if (prelinkCountObj
) {
470 registryRoot
->setProperty(kOSPrelinkKextCountKey
, prelinkCountObj
);
473 OSKextLog(/* kext */ NULL
,
474 kOSKextLogProgressLevel
|
475 kOSKextLogGeneralFlag
| kOSKextLogKextBookkeepingFlag
|
476 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
477 "%u prelinked kexts",
478 infoDictArray
->getCount());
480 #if CONFIG_KEXT_BASEMENT
481 /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
482 * special VM region during OSKext init time, so we can free the whole
485 ml_static_mfree((vm_offset_t
) prelinkData
, prelinkLength
);
486 #endif /* __x86_64__ */
488 /* Free the prelink info segment, we're done with it.
490 prelinkInfoSegment
= getsegbyname(kPrelinkInfoSegment
);
491 if (prelinkInfoSegment
) {
492 ml_static_mfree((vm_offset_t
)prelinkInfoSegment
->vmaddr
,
493 (vm_size_t
)prelinkInfoSegment
->vmsize
);
497 OSSafeRelease(errorString
);
498 OSSafeRelease(parsedXML
);
499 OSSafeRelease(theKernel
);
500 OSSafeRelease(prelinkCountObj
);
504 /*********************************************************************
505 *********************************************************************/
506 #define BOOTER_KEXT_PREFIX "Driver-"
507 #define BOOTER_MKEXT_PREFIX "DriversPackage-"
509 typedef struct _DeviceTreeBuffer
{
515 KLDBootstrap::readBooterExtensions(void)
517 IORegistryEntry
* booterMemoryMap
= NULL
; // must release
518 OSDictionary
* propertyDict
= NULL
; // must release
519 OSCollectionIterator
* keyIterator
= NULL
; // must release
520 OSString
* deviceTreeName
= NULL
; // do not release
522 const _DeviceTreeBuffer
* deviceTreeBuffer
= NULL
; // do not free
523 char * booterDataPtr
= NULL
; // do not free
524 OSData
* booterData
= NULL
; // must release
526 OSKext
* aKext
= NULL
; // must release
528 OSKextLog(/* kext */ NULL
,
529 kOSKextLogProgressLevel
|
530 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
531 "Reading startup extensions/mkexts from booter memory.");
533 booterMemoryMap
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
);
535 if (!booterMemoryMap
) {
536 OSKextLog(/* kext */ NULL
,
537 kOSKextLogErrorLevel
|
538 kOSKextLogGeneralFlag
| kOSKextLogDirectoryScanFlag
,
539 "Can't read booter memory map.");
543 propertyDict
= booterMemoryMap
->dictionaryWithProperties();
545 OSKextLog(/* kext */ NULL
,
546 kOSKextLogErrorLevel
|
547 kOSKextLogDirectoryScanFlag
,
548 "Can't get property dictionary from memory map.");
552 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
554 OSKextLog(/* kext */ NULL
,
555 kOSKextLogErrorLevel
|
556 kOSKextLogGeneralFlag
,
557 "Can't allocate iterator for driver images.");
561 while ( ( deviceTreeName
=
562 OSDynamicCast(OSString
, keyIterator
->getNextObject() ))) {
564 boolean_t isMkext
= FALSE
;
565 const char * devTreeNameCString
= deviceTreeName
->getCStringNoCopy();
566 OSData
* deviceTreeEntry
= OSDynamicCast(OSData
,
567 propertyDict
->getObject(deviceTreeName
));
569 /* Clear out the booterData from the prior iteration.
571 OSSafeReleaseNULL(booterData
);
573 /* If there is no entry for the name, we can't do much with it. */
574 if (!deviceTreeEntry
) {
578 /* Make sure it is either a kext or an mkext */
579 if (!strncmp(devTreeNameCString
, BOOTER_KEXT_PREFIX
,
580 CONST_STRLEN(BOOTER_KEXT_PREFIX
))) {
584 } else if (!strncmp(devTreeNameCString
, BOOTER_MKEXT_PREFIX
,
585 CONST_STRLEN(BOOTER_MKEXT_PREFIX
))) {
593 deviceTreeBuffer
= (const _DeviceTreeBuffer
*)
594 deviceTreeEntry
->getBytesNoCopy(0, sizeof(deviceTreeBuffer
));
595 if (!deviceTreeBuffer
) {
596 /* We can't get to the data, so we can't do anything,
597 * not even free it from physical memory (if it's there).
599 OSKextLog(/* kext */ NULL
,
600 kOSKextLogErrorLevel
|
601 kOSKextLogDirectoryScanFlag
,
602 "Device tree entry %s has NULL pointer.",
604 goto finish
; // xxx - continue, panic?
607 booterDataPtr
= (char *)ml_static_ptovirt(deviceTreeBuffer
->paddr
);
608 if (!booterDataPtr
) {
609 OSKextLog(/* kext */ NULL
,
610 kOSKextLogErrorLevel
|
611 kOSKextLogDirectoryScanFlag
,
612 "Can't get virtual address for device tree mkext entry %s.",
617 /* Wrap the booter data buffer in an OSData and set a dealloc function
618 * so it will take care of the physical memory when freed. Kexts will
619 * retain the booterData for as long as they need it. Remove the entry
620 * from the booter memory map after this is done.
622 booterData
= OSData::withBytesNoCopy(booterDataPtr
,
623 deviceTreeBuffer
->length
);
625 OSKextLog(/* kext */ NULL
,
626 kOSKextLogErrorLevel
|
627 kOSKextLogGeneralFlag
,
628 "Error - Can't allocate OSData wrapper for device tree entry %s.",
632 booterData
->setDeallocFunction(osdata_phys_free
);
635 readMkextExtensions(deviceTreeName
, booterData
);
637 /* Create the kext for the entry, then release it, because the
638 * kext system keeps them around until explicitly removed.
639 * Any creation/registration failures are already logged for us.
641 OSKext
* newKext
= OSKext::withBooterData(deviceTreeName
, booterData
);
642 OSSafeRelease(newKext
);
645 booterMemoryMap
->removeProperty(deviceTreeName
);
647 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
651 OSSafeRelease(booterMemoryMap
);
652 OSSafeRelease(propertyDict
);
653 OSSafeRelease(keyIterator
);
654 OSSafeRelease(booterData
);
655 OSSafeRelease(aKext
);
659 /*********************************************************************
660 *********************************************************************/
662 KLDBootstrap::readMkextExtensions(
663 OSString
* deviceTreeName
,
666 OSReturn result
= kOSReturnError
;
669 IORegistryEntry
* registryRoot
= NULL
; // do not release
670 OSData
* checksumObj
= NULL
; // must release
672 OSKextLog(/* kext */ NULL
,
673 kOSKextLogStepLevel
|
674 kOSKextLogDirectoryScanFlag
| kOSKextLogArchiveFlag
,
675 "Reading startup mkext archive from device tree entry %s.",
676 deviceTreeName
->getCStringNoCopy());
678 /* If we successfully read the archive,
679 * then save the mkext's checksum in the IORegistry.
680 * assumes we'll only ever have one mkext to boot
682 result
= OSKext::readMkextArchive(booterData
, &checksum
);
683 if (result
== kOSReturnSuccess
) {
685 OSKextLog(/* kext */ NULL
,
686 kOSKextLogProgressLevel
|
687 kOSKextLogArchiveFlag
,
688 "Startup mkext archive has checksum 0x%x.", (int)checksum
);
690 registryRoot
= IORegistryEntry::getRegistryRoot();
691 assert(registryRoot
);
692 checksumObj
= OSData::withBytes((void *)&checksum
, sizeof(checksum
));
695 registryRoot
->setProperty(kOSStartupMkextCRC
, checksumObj
);
702 /*********************************************************************
703 *********************************************************************/
704 #define COM_APPLE "com.apple."
707 KLDBootstrap::loadSecurityExtensions(void)
709 OSDictionary
* extensionsDict
= NULL
; // must release
710 OSCollectionIterator
* keyIterator
= NULL
; // must release
711 OSString
* bundleID
= NULL
; // don't release
712 OSKext
* theKext
= NULL
; // don't release
713 OSBoolean
* isSecurityKext
= NULL
; // don't release
715 OSKextLog(/* kext */ NULL
,
716 kOSKextLogStepLevel
|
718 "Loading security extensions.");
720 extensionsDict
= OSKext::copyKexts();
721 if (!extensionsDict
) {
725 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
727 OSKextLog(/* kext */ NULL
,
728 kOSKextLogErrorLevel
|
729 kOSKextLogGeneralFlag
,
730 "Failed to allocate iterator for security extensions.");
734 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
736 const char * bundle_id
= bundleID
->getCStringNoCopy();
738 /* Skip extensions whose bundle IDs don't start with "com.apple.".
741 (strncmp(bundle_id
, COM_APPLE
, CONST_STRLEN(COM_APPLE
)) != 0)) {
746 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
751 isSecurityKext
= OSDynamicCast(OSBoolean
,
752 theKext
->getPropertyForHostArch(kAppleSecurityExtensionKey
));
753 if (isSecurityKext
&& isSecurityKext
->isTrue()) {
754 OSKextLog(/* kext */ NULL
,
755 kOSKextLogStepLevel
|
757 "Loading security extension %s.", bundleID
->getCStringNoCopy());
758 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
759 /* allowDefer */ false);
764 OSSafeRelease(keyIterator
);
765 OSSafeRelease(extensionsDict
);
770 /*********************************************************************
771 * We used to require that all listed kernel components load, but
772 * nowadays we can get them from userland so we only try to load the
773 * ones we have. If an error occurs later, such is life.
775 * Note that we look the kexts up first, so we can avoid spurious
776 * (in this context, anyhow) log messages about kexts not being found.
778 * xxx - do we even need to do this any more? Check if the kernel
779 * xxx - compoonents just load in the regular paths
780 *********************************************************************/
782 KLDBootstrap::loadKernelComponentKexts(void)
784 OSReturn result
= kOSReturnSuccess
; // optimistic
785 OSKext
* theKext
= NULL
; // must release
786 const char ** kextIDPtr
= NULL
; // do not release
788 for (kextIDPtr
= &sKernelComponentNames
[0]; *kextIDPtr
; kextIDPtr
++) {
790 OSSafeReleaseNULL(theKext
);
791 theKext
= OSKext::lookupKextWithIdentifier(*kextIDPtr
);
794 if (kOSReturnSuccess
!= OSKext::loadKextWithIdentifier(
795 *kextIDPtr
, /* allowDefer */ false)) {
797 // xxx - check KextBookkeeping, might be redundant
798 OSKextLog(/* kext */ NULL
,
799 kOSKextLogErrorLevel
|
800 kOSKextLogDirectoryScanFlag
| kOSKextLogKextBookkeepingFlag
,
801 "Failed to initialize kernel component %s.", *kextIDPtr
);
802 result
= kOSReturnError
;
807 OSSafeRelease(theKext
);
811 /*********************************************************************
812 * Ensure that Kernel External Components are loaded early in boot,
813 * before other kext personalities get sent to the IOCatalogue. These
814 * kexts are treated specially because they may provide the implementation
815 * for kernel-vended KPI, so they must register themselves before
816 * general purpose IOKit probing begins.
817 *********************************************************************/
819 #define COM_APPLE_KEC "com.apple.kec."
822 KLDBootstrap::loadKernelExternalComponents(void)
824 OSDictionary
* extensionsDict
= NULL
; // must release
825 OSCollectionIterator
* keyIterator
= NULL
; // must release
826 OSString
* bundleID
= NULL
; // don't release
827 OSKext
* theKext
= NULL
; // don't release
828 OSBoolean
* isKernelExternalComponent
= NULL
; // don't release
830 OSKextLog(/* kext */ NULL
,
831 kOSKextLogStepLevel
|
833 "Loading Kernel External Components.");
835 extensionsDict
= OSKext::copyKexts();
836 if (!extensionsDict
) {
840 keyIterator
= OSCollectionIterator::withCollection(extensionsDict
);
842 OSKextLog(/* kext */ NULL
,
843 kOSKextLogErrorLevel
|
844 kOSKextLogGeneralFlag
,
845 "Failed to allocate iterator for Kernel External Components.");
849 while ((bundleID
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
851 const char * bundle_id
= bundleID
->getCStringNoCopy();
853 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
856 (strncmp(bundle_id
, COM_APPLE_KEC
, CONST_STRLEN(COM_APPLE_KEC
)) != 0)) {
861 theKext
= OSDynamicCast(OSKext
, extensionsDict
->getObject(bundleID
));
866 isKernelExternalComponent
= OSDynamicCast(OSBoolean
,
867 theKext
->getPropertyForHostArch(kAppleKernelExternalComponentKey
));
868 if (isKernelExternalComponent
&& isKernelExternalComponent
->isTrue()) {
869 OSKextLog(/* kext */ NULL
,
870 kOSKextLogStepLevel
|
872 "Loading kernel external component %s.", bundleID
->getCStringNoCopy());
873 OSKext::loadKextWithIdentifier(bundleID
->getCStringNoCopy(),
874 /* allowDefer */ false);
879 OSSafeRelease(keyIterator
);
880 OSSafeRelease(extensionsDict
);
885 /*********************************************************************
886 *********************************************************************/
888 KLDBootstrap::readBuiltinPersonalities(void)
890 OSObject
* parsedXML
= NULL
; // must release
891 OSArray
* builtinExtensions
= NULL
; // do not release
892 OSArray
* allPersonalities
= NULL
; // must release
893 OSString
* errorString
= NULL
; // must release
894 kernel_section_t
* infosect
= NULL
; // do not free
895 OSCollectionIterator
* personalitiesIterator
= NULL
; // must release
896 unsigned int count
, i
;
898 OSKextLog(/* kext */ NULL
,
899 kOSKextLogStepLevel
|
901 "Reading built-in kernel personalities for I/O Kit drivers.");
903 /* Look in the __BUILTIN __info segment for an array of Info.plist
904 * entries. For each one, extract the personalities dictionary, add
905 * it to our array, then push them all (without matching) to
906 * the IOCatalogue. This can be used to augment the personalities
907 * in gIOKernelConfigTables, especially when linking entire kexts into
908 * the mach_kernel image.
910 infosect
= getsectbyname("__BUILTIN", "__info");
916 parsedXML
= OSUnserializeXML((const char *) (uintptr_t)infosect
->addr
,
919 builtinExtensions
= OSDynamicCast(OSArray
, parsedXML
);
921 if (!builtinExtensions
) {
922 const char * errorCString
= "(unknown error)";
924 if (errorString
&& errorString
->getCStringNoCopy()) {
925 errorCString
= errorString
->getCStringNoCopy();
926 } else if (parsedXML
) {
927 errorCString
= "not an array";
929 OSKextLog(/* kext */ NULL
,
930 kOSKextLogErrorLevel
|
932 "Error unserializing built-in personalities: %s.", errorCString
);
936 // estimate 3 personalities per Info.plist/kext
937 count
= builtinExtensions
->getCount();
938 allPersonalities
= OSArray::withCapacity(count
* 3);
940 for (i
= 0; i
< count
; i
++) {
941 OSDictionary
* infoDict
= NULL
; // do not release
942 OSString
* moduleName
= NULL
; // do not release
943 OSDictionary
* personalities
; // do not release
944 OSString
* personalityName
; // do not release
946 OSSafeReleaseNULL(personalitiesIterator
);
948 infoDict
= OSDynamicCast(OSDictionary
,
949 builtinExtensions
->getObject(i
));
954 moduleName
= OSDynamicCast(OSString
,
955 infoDict
->getObject(kCFBundleIdentifierKey
));
960 OSKextLog(/* kext */ NULL
,
961 kOSKextLogStepLevel
|
963 "Adding personalities for built-in driver %s:",
964 moduleName
->getCStringNoCopy());
966 personalities
= OSDynamicCast(OSDictionary
,
967 infoDict
->getObject("IOKitPersonalities"));
968 if (!personalities
) {
972 personalitiesIterator
= OSCollectionIterator::withCollection(personalities
);
973 if (!personalitiesIterator
) {
974 continue; // xxx - well really, what can we do? should we panic?
977 while ((personalityName
= OSDynamicCast(OSString
,
978 personalitiesIterator
->getNextObject()))) {
980 OSDictionary
* personality
= OSDynamicCast(OSDictionary
,
981 personalities
->getObject(personalityName
));
983 OSKextLog(/* kext */ NULL
,
984 kOSKextLogDetailLevel
|
986 "Adding built-in driver personality %s.",
987 personalityName
->getCStringNoCopy());
989 if (personality
&& !personality
->getObject(kCFBundleIdentifierKey
)) {
990 personality
->setObject(kCFBundleIdentifierKey
, moduleName
);
992 allPersonalities
->setObject(personality
);
996 gIOCatalogue
->addDrivers(allPersonalities
, false);
999 OSSafeRelease(parsedXML
);
1000 OSSafeRelease(allPersonalities
);
1001 OSSafeRelease(errorString
);
1002 OSSafeRelease(personalitiesIterator
);
1007 #pragma mark Bootstrap Functions
1009 /*********************************************************************
1010 * Bootstrap Functions
1011 *********************************************************************/
1012 static void bootstrapRecordStartupExtensions(void)
1014 sBootstrapObject
.readStartupExtensions();
1018 static void bootstrapLoadSecurityExtensions(void)
1020 sBootstrapObject
.loadSecurityExtensions();