xref: /xnu-11215/libsa/bootstrap.cpp (revision bb611c8f)
1 /*
2  * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
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.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 extern "C" {
29 #include <mach/kmod.h>
30 #include <libkern/kernel_mach_header.h>
31 #include <libkern/prelink.h>
32 #include <libkern/crypto/sha2.h>
33 }
34 
35 #define IOKIT_ENABLE_SHARED_PTR
36 
37 #include <libkern/version.h>
38 #include <libkern/c++/OSContainers.h>
39 #include <libkern/OSKextLibPrivate.h>
40 #include <libkern/c++/OSKext.h>
41 #include <IOKit/IOLib.h>
42 #include <IOKit/IOService.h>
43 #include <IOKit/IODeviceTreeSupport.h>
44 #include <IOKit/IOCatalogue.h>
45 
46 #if __x86_64__
47 #define KASLR_KEXT_DEBUG 0
48 #endif
49 
50 #if PRAGMA_MARK
51 #pragma mark Bootstrap Declarations
52 #endif
53 /*********************************************************************
54 * Bootstrap Declarations
55 *
56 * The ENTIRE point of the libsa/KLD segment is to isolate bootstrap
57 * code from other parts of the kernel, so function symbols are not
58 * exported; rather pointers to those functions are exported.
59 *
60 * xxx - need to think about locking for handling the 'weak' refs.
61 * xxx - do export a non-KLD function that says you've called a
62 * xxx - bootstrap function that has been removed.
63 *
64 * ALL call-ins to this segment of the kernel must be done through
65 * exported pointers. The symbols themselves are private and not to
66 * be linked against.
67 *********************************************************************/
68 extern "C" {
69 extern void (*record_startup_extensions_function)(void);
70 extern void (*load_security_extensions_function)(void);
71 };
72 
73 static void bootstrapRecordStartupExtensions(void);
74 static void bootstrapLoadSecurityExtensions(void);
75 
76 
77 #if NO_KEXTD
78 extern "C" bool IORamDiskBSDRoot(void);
79 #endif
80 
81 #if PRAGMA_MARK
82 #pragma mark Macros
83 #endif
84 /*********************************************************************
85 * Macros
86 *********************************************************************/
87 #define CONST_STRLEN(str) (sizeof(str) - 1)
88 
89 #if PRAGMA_MARK
90 #pragma mark Kernel Component Kext Identifiers
91 #endif
92 /*********************************************************************
93 * Kernel Component Kext Identifiers
94 *
95 * We could have each kernel resource kext automatically "load" as
96 * it's created, but it's nicer to have them listed in kextstat in
97 * the order of this list. We'll walk through this after setting up
98 * all the boot kexts and have them load up.
99 *********************************************************************/
100 static const char * sKernelComponentNames[] = {
101 	// The kexts for these IDs must have a version matching 'osrelease'.
102 	"com.apple.kernel",
103 	"com.apple.kpi.bsd",
104 	"com.apple.kpi.dsep",
105 	"com.apple.kpi.iokit",
106 	"com.apple.kpi.kasan",
107 	"com.apple.kpi.libkern",
108 	"com.apple.kpi.mach",
109 	"com.apple.kpi.private",
110 	"com.apple.kpi.unsupported",
111 	"com.apple.iokit.IONVRAMFamily",
112 	"com.apple.driver.AppleNMI",
113 	"com.apple.iokit.IOSystemManagementFamily",
114 	"com.apple.iokit.ApplePlatformFamily",
115 	NULL
116 };
117 
118 #if PRAGMA_MARK
119 #pragma mark KLDBootstrap Class
120 #endif
121 /*********************************************************************
122 * KLDBootstrap Class
123 *
124 * We use a C++ class here so that it can be a friend of OSKext and
125 * get at private stuff. We can't hide the class itself, but we can
126 * hide the instance through which we invoke the functions.
127 *********************************************************************/
128 class KLDBootstrap {
129 	friend void bootstrapRecordStartupExtensions(void);
130 	friend void bootstrapLoadSecurityExtensions(void);
131 
132 private:
133 	void readStartupExtensions(void);
134 
135 	void readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type);
136 	void readBooterExtensions(void);
137 
138 	OSReturn loadKernelComponentKexts(void);
139 	void     loadKernelExternalComponents(void);
140 	void     readBuiltinPersonalities(void);
141 
142 	void     loadSecurityExtensions(void);
143 
144 public:
145 	KLDBootstrap(void);
146 	~KLDBootstrap(void);
147 };
148 
149 LIBKERN_ALWAYS_DESTROY static KLDBootstrap sBootstrapObject;
150 
151 /*********************************************************************
152 * Set the function pointers for the entry points into the bootstrap
153 * segment upon C++ static constructor invocation.
154 *********************************************************************/
155 KLDBootstrap::KLDBootstrap(void)
156 {
157 	if (this != &sBootstrapObject) {
158 		panic("Attempt to access bootstrap segment.");
159 	}
160 	record_startup_extensions_function = &bootstrapRecordStartupExtensions;
161 	load_security_extensions_function = &bootstrapLoadSecurityExtensions;
162 }
163 
164 /*********************************************************************
165 * Clear the function pointers for the entry points into the bootstrap
166 * segment upon C++ static destructor invocation.
167 *********************************************************************/
168 KLDBootstrap::~KLDBootstrap(void)
169 {
170 	if (this != &sBootstrapObject) {
171 		panic("Attempt to access bootstrap segment.");
172 	}
173 
174 
175 	record_startup_extensions_function = NULL;
176 	load_security_extensions_function = NULL;
177 }
178 
179 /*********************************************************************
180 *********************************************************************/
181 void
182 KLDBootstrap::readStartupExtensions(void)
183 {
184 	kernel_section_t * prelinkInfoSect = NULL; // do not free
185 
186 	OSKextLog(/* kext */ NULL,
187 	    kOSKextLogProgressLevel |
188 	    kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag |
189 	    kOSKextLogKextBookkeepingFlag,
190 	    "Reading startup extensions.");
191 
192 	kc_format_t kc_format;
193 	kernel_mach_header_t *mh = &_mh_execute_header;
194 	if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
195 		mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
196 	}
197 
198 	/* If the prelink info segment has a nonzero size, we are prelinked
199 	 * and won't have any individual kexts or mkexts to read.
200 	 * Otherwise, we need to read kexts or the mkext from what the booter
201 	 * has handed us.
202 	 */
203 	prelinkInfoSect = getsectbynamefromheader(mh, kPrelinkInfoSegment, kPrelinkInfoSection);
204 	if (prelinkInfoSect->size) {
205 		readPrelinkedExtensions(mh, KCKindPrimary);
206 	} else {
207 		readBooterExtensions();
208 	}
209 
210 	kernel_mach_header_t *akc_mh;
211 	akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
212 	if (akc_mh) {
213 		readPrelinkedExtensions(akc_mh, KCKindAuxiliary);
214 	}
215 
216 	loadKernelComponentKexts();
217 	loadKernelExternalComponents();
218 	readBuiltinPersonalities();
219 	OSKext::sendAllKextPersonalitiesToCatalog(true);
220 
221 	return;
222 }
223 
224 /*********************************************************************
225 *********************************************************************/
226 void
227 KLDBootstrap::readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type)
228 {
229 	bool ret;
230 	OSSharedPtr<OSData> loaded_kcUUID;
231 	OSSharedPtr<OSString> errorString;
232 	OSSharedPtr<OSObject> parsedXML;
233 	kernel_section_t *infoPlistSection = NULL;
234 	OSDictionary *infoDict = NULL;         // do not release
235 
236 	OSKextLog(/* kext */ NULL,
237 	    kOSKextLogProgressLevel |
238 	    kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
239 	    "Starting from prelinked kernel.");
240 
241 	/*
242 	 * The 'infoPlistSection' should contains an XML dictionary that
243 	 * contains some meta data about the KC, and also describes each kext
244 	 * included in the kext collection. Unserialize this dictionary and
245 	 * then iterate over each kext.
246 	 */
247 	infoPlistSection = getsectbynamefromheader(mh, kPrelinkInfoSegment, kPrelinkInfoSection);
248 	parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
249 	if (parsedXML) {
250 		infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
251 	}
252 
253 	if (!infoDict) {
254 		const char *errorCString = "(unknown error)";
255 
256 		if (errorString && errorString->getCStringNoCopy()) {
257 			errorCString = errorString->getCStringNoCopy();
258 		} else if (parsedXML) {
259 			errorCString = "not a dictionary";
260 		}
261 		OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
262 		    "Error unserializing kext info plist section: %s.", errorCString);
263 		return;
264 	}
265 
266 	/* Validate that the Kext Collection is prelinked to the loaded KC */
267 	if (type == KCKindAuxiliary) {
268 		if (OSKext::validateKCFileSetUUID(infoDict, KCKindAuxiliary) != 0) {
269 			OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
270 			    "Early boot AuxKC  doesn't appear to be linked against the loaded BootKC.");
271 			return;
272 		}
273 
274 		/*
275 		 * Defer further processing of the AuxKC, but keep the
276 		 * processed info dictionary around so we can ml_static_free
277 		 * the segment.
278 		 */
279 		if (!OSKext::registerDeferredKextCollection(mh, parsedXML, KCKindAuxiliary)) {
280 			OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
281 			    "Error deferring AuxKC kext processing: Kexts in this collection will be unusable.");
282 		}
283 		goto skip_adding_kexts;
284 	}
285 
286 	/*
287 	 * this function does all the heavy lifting of adding OSKext objects
288 	 * and potentially sliding them if necessary
289 	 */
290 	ret = OSKext::addKextsFromKextCollection(mh, infoDict,
291 	    kPrelinkTextSegment, loaded_kcUUID, (mh->filetype == MH_FILESET) ? type : KCKindUnknown);
292 
293 	if (!ret) {
294 		OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
295 		    "Error loading kext info from prelinked primary KC");
296 		return;
297 	}
298 
299 	/* Copy in the kernelcache UUID */
300 	if (!loaded_kcUUID) {
301 		OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
302 		    "WARNING: did not find UUID in %s KC!", (type == KCKindAuxiliary) ? "Aux" : "Primary");
303 	} else if (type != KCKindAuxiliary) {
304 		kernelcache_uuid_valid = TRUE;
305 		memcpy((void *)&kernelcache_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
306 		uuid_unparse_upper(kernelcache_uuid, kernelcache_uuid_string);
307 	} else {
308 		auxkc_uuid_valid = TRUE;
309 		memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
310 		uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
311 	}
312 
313 skip_adding_kexts:
314 #if CONFIG_KEXT_BASEMENT
315 	if (mh->filetype != MH_FILESET) {
316 		/*
317 		 * On CONFIG_KEXT_BASEMENT systems which do _not_ boot the new
318 		 * MH_FILESET kext collection, kexts are copied to their own
319 		 * special VM region during OSKext init time, so we can free
320 		 * the whole segment now.
321 		 */
322 		kernel_segment_command_t *prelinkTextSegment = NULL;
323 		prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
324 		if (!prelinkTextSegment) {
325 			OSKextLog(/* kext */ NULL,
326 			    kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
327 			    "Can't find prelinked kexts' text segment.");
328 			return;
329 		}
330 
331 		ml_static_mfree((vm_offset_t)prelinkTextSegment->vmaddr, prelinkTextSegment->vmsize);
332 	}
333 #endif /* CONFIG_KEXT_BASEMENT */
334 
335 	/*
336 	 * Free the prelink info segment, we're done with it.
337 	 */
338 	kernel_segment_command_t *prelinkInfoSegment = NULL;
339 	prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
340 	if (prelinkInfoSegment) {
341 		ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
342 		    (vm_size_t)prelinkInfoSegment->vmsize);
343 	}
344 
345 	return;
346 }
347 
348 
349 /*********************************************************************
350 *********************************************************************/
351 #define BOOTER_KEXT_PREFIX   "Driver-"
352 
353 typedef struct _DeviceTreeBuffer {
354 	uint32_t paddr;
355 	uint32_t length;
356 } _DeviceTreeBuffer;
357 
358 void
359 KLDBootstrap::readBooterExtensions(void)
360 {
361 	OSSharedPtr<IORegistryEntry> booterMemoryMap;
362 	OSSharedPtr<OSDictionary>    propertyDict;
363 	OSSharedPtr<OSCollectionIterator>      keyIterator;
364 	OSString                  * deviceTreeName          = NULL;// do not release
365 
366 	const _DeviceTreeBuffer   * deviceTreeBuffer        = NULL;// do not free
367 	char                      * booterDataPtr           = NULL;// do not free
368 	OSSharedPtr<OSData>         booterData;
369 	OSSharedPtr<OSKext>         aKext;
370 
371 	OSKextLog(/* kext */ NULL,
372 	    kOSKextLogProgressLevel |
373 	    kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
374 	    "Reading startup extensions from booter memory.");
375 
376 	booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);
377 
378 	if (!booterMemoryMap) {
379 		OSKextLog(/* kext */ NULL,
380 		    kOSKextLogErrorLevel |
381 		    kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
382 		    "Can't read booter memory map.");
383 		goto finish;
384 	}
385 
386 	propertyDict = booterMemoryMap->dictionaryWithProperties();
387 	if (!propertyDict) {
388 		OSKextLog(/* kext */ NULL,
389 		    kOSKextLogErrorLevel |
390 		    kOSKextLogDirectoryScanFlag,
391 		    "Can't get property dictionary from memory map.");
392 		goto finish;
393 	}
394 
395 	keyIterator = OSCollectionIterator::withCollection(propertyDict.get());
396 	if (!keyIterator) {
397 		OSKextLog(/* kext */ NULL,
398 		    kOSKextLogErrorLevel |
399 		    kOSKextLogGeneralFlag,
400 		    "Can't allocate iterator for driver images.");
401 		goto finish;
402 	}
403 
404 	/* Create dictionary of excluded kexts
405 	 */
406 #ifndef CONFIG_EMBEDDED
407 	OSKext::createExcludeListFromBooterData(propertyDict.get(), keyIterator.get());
408 #endif
409 	// !! reset the iterator, not the pointer
410 	keyIterator->reset();
411 
412 	while ((deviceTreeName =
413 	    OSDynamicCast(OSString, keyIterator->getNextObject()))) {
414 		const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
415 		OSData * deviceTreeEntry = OSDynamicCast(OSData,
416 		    propertyDict->getObject(deviceTreeName));
417 
418 		/* If there is no entry for the name, we can't do much with it. */
419 		if (!deviceTreeEntry) {
420 			continue;
421 		}
422 
423 		/* Make sure it is a kext */
424 		if (strncmp(devTreeNameCString,
425 		    BOOTER_KEXT_PREFIX,
426 		    CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
427 			continue;
428 		}
429 
430 		deviceTreeBuffer = (const _DeviceTreeBuffer *)
431 		    deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
432 		if (!deviceTreeBuffer) {
433 			/* We can't get to the data, so we can't do anything,
434 			 * not even free it from physical memory (if it's there).
435 			 */
436 			OSKextLog(/* kext */ NULL,
437 			    kOSKextLogErrorLevel |
438 			    kOSKextLogDirectoryScanFlag,
439 			    "Device tree entry %s has NULL pointer.",
440 			    devTreeNameCString);
441 			goto finish; // xxx - continue, panic?
442 		}
443 
444 		booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
445 		if (!booterDataPtr) {
446 			OSKextLog(/* kext */ NULL,
447 			    kOSKextLogErrorLevel |
448 			    kOSKextLogDirectoryScanFlag,
449 			    "Can't get virtual address for device tree entry %s.",
450 			    devTreeNameCString);
451 			goto finish;
452 		}
453 
454 		/* Wrap the booter data buffer in an OSData and set a dealloc function
455 		 * so it will take care of the physical memory when freed. Kexts will
456 		 * retain the booterData for as long as they need it. Remove the entry
457 		 * from the booter memory map after this is done.
458 		 */
459 		booterData = OSData::withBytesNoCopy(booterDataPtr,
460 		    deviceTreeBuffer->length);
461 		if (!booterData) {
462 			OSKextLog(/* kext */ NULL,
463 			    kOSKextLogErrorLevel |
464 			    kOSKextLogGeneralFlag,
465 			    "Error - Can't allocate OSData wrapper for device tree entry %s.",
466 			    devTreeNameCString);
467 			goto finish;
468 		}
469 		booterData->setDeallocFunction(osdata_phys_free);
470 
471 		/* Create the kext for the entry, then release it, because the
472 		 * kext system keeps them around until explicitly removed.
473 		 * Any creation/registration failures are already logged for us.
474 		 */
475 		OSSharedPtr<OSKext> newKext = OSKext::withBooterData(deviceTreeName, booterData.get());
476 
477 		booterMemoryMap->removeProperty(deviceTreeName);
478 	} /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
479 
480 finish:
481 	return;
482 }
483 
484 /*********************************************************************
485 *********************************************************************/
486 #define COM_APPLE  "com.apple."
487 
488 void
489 KLDBootstrap::loadSecurityExtensions(void)
490 {
491 	OSSharedPtr<OSDictionary>         extensionsDict;
492 	OSSharedPtr<OSCollectionIterator> keyIterator;
493 	OSString             * bundleID       = NULL;// don't release
494 	OSKext               * theKext        = NULL;// don't release
495 
496 	OSKextLog(/* kext */ NULL,
497 	    kOSKextLogStepLevel |
498 	    kOSKextLogLoadFlag,
499 	    "Loading security extensions.");
500 
501 	extensionsDict = OSKext::copyKexts();
502 	if (!extensionsDict) {
503 		return;
504 	}
505 
506 	keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
507 	if (!keyIterator) {
508 		OSKextLog(/* kext */ NULL,
509 		    kOSKextLogErrorLevel |
510 		    kOSKextLogGeneralFlag,
511 		    "Failed to allocate iterator for security extensions.");
512 		goto finish;
513 	}
514 
515 	while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
516 		const char * bundle_id = bundleID->getCStringNoCopy();
517 
518 		/* Skip extensions whose bundle IDs don't start with "com.apple.".
519 		 */
520 		if (!bundle_id ||
521 		    (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) {
522 			continue;
523 		}
524 
525 		theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
526 		if (!theKext) {
527 			continue;
528 		}
529 
530 		if (kOSBooleanTrue == theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)) {
531 			OSKextLog(/* kext */ NULL,
532 			    kOSKextLogStepLevel |
533 			    kOSKextLogLoadFlag,
534 			    "Loading security extension %s.", bundleID->getCStringNoCopy());
535 			OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
536 			    /* allowDefer */ false);
537 		}
538 	}
539 
540 finish:
541 	return;
542 }
543 
544 /*********************************************************************
545 * We used to require that all listed kernel components load, but
546 * nowadays we can get them from userland so we only try to load the
547 * ones we have. If an error occurs later, such is life.
548 *
549 * Note that we look the kexts up first, so we can avoid spurious
550 * (in this context, anyhow) log messages about kexts not being found.
551 *
552 * xxx - do we even need to do this any more? Check if the kernel
553 * xxx - compoonents just load in the regular paths
554 *********************************************************************/
555 OSReturn
556 KLDBootstrap::loadKernelComponentKexts(void)
557 {
558 	OSReturn            result      = kOSReturnSuccess;// optimistic
559 	OSSharedPtr<OSKext> theKext;
560 	const char       ** kextIDPtr   = NULL;          // do not release
561 
562 	for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
563 		theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr);
564 
565 		if (theKext) {
566 			if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
567 				    *kextIDPtr, /* allowDefer */ false)) {
568 				// xxx - check KextBookkeeping, might be redundant
569 				OSKextLog(/* kext */ NULL,
570 				    kOSKextLogErrorLevel |
571 				    kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
572 				    "Failed to initialize kernel component %s.", *kextIDPtr);
573 				result = kOSReturnError;
574 			}
575 		}
576 	}
577 
578 	return result;
579 }
580 
581 /*********************************************************************
582 * Ensure that Kernel External Components are loaded early in boot,
583 * before other kext personalities get sent to the IOCatalogue. These
584 * kexts are treated specially because they may provide the implementation
585 * for kernel-vended KPI, so they must register themselves before
586 * general purpose IOKit probing begins.
587 *********************************************************************/
588 
589 #define COM_APPLE_KEC  "com.apple.kec."
590 
591 void
592 KLDBootstrap::loadKernelExternalComponents(void)
593 {
594 	OSSharedPtr<OSDictionary>         extensionsDict;
595 	OSSharedPtr<OSCollectionIterator> keyIterator;
596 	OSString             * bundleID       = NULL;// don't release
597 	OSKext               * theKext        = NULL;// don't release
598 	OSBoolean            * isKernelExternalComponent = NULL;// don't release
599 
600 	OSKextLog(/* kext */ NULL,
601 	    kOSKextLogStepLevel |
602 	    kOSKextLogLoadFlag,
603 	    "Loading Kernel External Components.");
604 
605 	extensionsDict = OSKext::copyKexts();
606 	if (!extensionsDict) {
607 		return;
608 	}
609 
610 	keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
611 	if (!keyIterator) {
612 		OSKextLog(/* kext */ NULL,
613 		    kOSKextLogErrorLevel |
614 		    kOSKextLogGeneralFlag,
615 		    "Failed to allocate iterator for Kernel External Components.");
616 		goto finish;
617 	}
618 
619 	while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
620 		const char * bundle_id = bundleID->getCStringNoCopy();
621 
622 		/* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
623 		 */
624 		if (!bundle_id ||
625 		    (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
626 			continue;
627 		}
628 
629 		theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
630 		if (!theKext) {
631 			continue;
632 		}
633 
634 		isKernelExternalComponent = OSDynamicCast(OSBoolean,
635 		    theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
636 		if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
637 			OSKextLog(/* kext */ NULL,
638 			    kOSKextLogStepLevel |
639 			    kOSKextLogLoadFlag,
640 			    "Loading kernel external component %s.", bundleID->getCStringNoCopy());
641 			OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
642 			    /* allowDefer */ false);
643 		}
644 	}
645 
646 finish:
647 	return;
648 }
649 
650 /*********************************************************************
651 *********************************************************************/
652 void
653 KLDBootstrap::readBuiltinPersonalities(void)
654 {
655 	OSSharedPtr<OSObject>   parsedXML;
656 	OSArray               * builtinExtensions     = NULL;// do not release
657 	OSSharedPtr<OSArray>    allPersonalities;
658 	OSSharedPtr<OSString>   errorString;
659 	kernel_section_t      * infosect              = NULL;// do not free
660 	OSSharedPtr<OSCollectionIterator>  personalitiesIterator;
661 	unsigned int            count, i;
662 
663 	OSKextLog(/* kext */ NULL,
664 	    kOSKextLogStepLevel |
665 	    kOSKextLogLoadFlag,
666 	    "Reading built-in kernel personalities for I/O Kit drivers.");
667 
668 	/* Look in the __BUILTIN __info segment for an array of Info.plist
669 	 * entries. For each one, extract the personalities dictionary, add
670 	 * it to our array, then push them all (without matching) to
671 	 * the IOCatalogue. This can be used to augment the personalities
672 	 * in gIOKernelConfigTables, especially when linking entire kexts into
673 	 * the mach_kernel image.
674 	 */
675 	infosect   = getsectbyname("__BUILTIN", "__info");
676 	if (!infosect) {
677 		// this isn't fatal
678 		goto finish;
679 	}
680 
681 	parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr,
682 	    errorString);
683 	if (parsedXML) {
684 		builtinExtensions = OSDynamicCast(OSArray, parsedXML.get());
685 	}
686 	if (!builtinExtensions) {
687 		const char * errorCString = "(unknown error)";
688 
689 		if (errorString && errorString->getCStringNoCopy()) {
690 			errorCString = errorString->getCStringNoCopy();
691 		} else if (parsedXML) {
692 			errorCString = "not an array";
693 		}
694 		OSKextLog(/* kext */ NULL,
695 		    kOSKextLogErrorLevel |
696 		    kOSKextLogLoadFlag,
697 		    "Error unserializing built-in personalities: %s.", errorCString);
698 		goto finish;
699 	}
700 
701 	// estimate 3 personalities per Info.plist/kext
702 	count = builtinExtensions->getCount();
703 	allPersonalities = OSArray::withCapacity(count * 3);
704 
705 	for (i = 0; i < count; i++) {
706 		OSDictionary            * infoDict = NULL;// do not release
707 		OSString                * moduleName = NULL;// do not release
708 		OSDictionary            * personalities;// do not release
709 		OSString                * personalityName;// do not release
710 
711 		infoDict = OSDynamicCast(OSDictionary,
712 		    builtinExtensions->getObject(i));
713 		if (!infoDict) {
714 			continue;
715 		}
716 
717 		moduleName = OSDynamicCast(OSString,
718 		    infoDict->getObject(kCFBundleIdentifierKey));
719 		if (!moduleName) {
720 			continue;
721 		}
722 
723 		OSKextLog(/* kext */ NULL,
724 		    kOSKextLogStepLevel |
725 		    kOSKextLogLoadFlag,
726 		    "Adding personalities for built-in driver %s:",
727 		    moduleName->getCStringNoCopy());
728 
729 		personalities = OSDynamicCast(OSDictionary,
730 		    infoDict->getObject("IOKitPersonalities"));
731 		if (!personalities) {
732 			continue;
733 		}
734 
735 		personalitiesIterator = OSCollectionIterator::withCollection(personalities);
736 		if (!personalitiesIterator) {
737 			continue; // xxx - well really, what can we do? should we panic?
738 		}
739 
740 		while ((personalityName = OSDynamicCast(OSString,
741 		    personalitiesIterator->getNextObject()))) {
742 			OSDictionary * personality = OSDynamicCast(OSDictionary,
743 			    personalities->getObject(personalityName));
744 
745 			OSKextLog(/* kext */ NULL,
746 			    kOSKextLogDetailLevel |
747 			    kOSKextLogLoadFlag,
748 			    "Adding built-in driver personality %s.",
749 			    personalityName->getCStringNoCopy());
750 
751 			if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
752 				personality->setObject(kCFBundleIdentifierKey, moduleName);
753 			}
754 			allPersonalities->setObject(personality);
755 		}
756 	}
757 
758 	gIOCatalogue->addDrivers(allPersonalities.get(), false);
759 
760 finish:
761 	return;
762 }
763 
764 #if PRAGMA_MARK
765 #pragma mark Bootstrap Functions
766 #endif
767 /*********************************************************************
768 * Bootstrap Functions
769 *********************************************************************/
770 static void
771 bootstrapRecordStartupExtensions(void)
772 {
773 	sBootstrapObject.readStartupExtensions();
774 	return;
775 }
776 
777 static void
778 bootstrapLoadSecurityExtensions(void)
779 {
780 	sBootstrapObject.loadSecurityExtensions();
781 	return;
782 }
783 
784