]> git.saurik.com Git - apple/xnu.git/blame_incremental - libsa/bootstrap.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libsa / bootstrap.cpp
... / ...
CommitLineData
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 */
28extern "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*********************************************************************/
68extern "C" {
69extern void (*record_startup_extensions_function)(void);
70extern void (*load_security_extensions_function)(void);
71};
72
73static void bootstrapRecordStartupExtensions(void);
74static void bootstrapLoadSecurityExtensions(void);
75
76
77#if NO_KEXTD
78extern "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*********************************************************************/
100static 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*********************************************************************/
128class KLDBootstrap {
129 friend void bootstrapRecordStartupExtensions(void);
130 friend void bootstrapLoadSecurityExtensions(void);
131
132private:
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
144public:
145 KLDBootstrap(void);
146 ~KLDBootstrap(void);
147};
148
149LIBKERN_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*********************************************************************/
155KLDBootstrap::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*********************************************************************/
168KLDBootstrap::~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*********************************************************************/
181void
182KLDBootstrap::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*********************************************************************/
226void
227KLDBootstrap::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
313skip_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
353typedef struct _DeviceTreeBuffer {
354 uint32_t paddr;
355 uint32_t length;
356} _DeviceTreeBuffer;
357
358void
359KLDBootstrap::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
480finish:
481 return;
482}
483
484/*********************************************************************
485*********************************************************************/
486#define COM_APPLE "com.apple."
487
488void
489KLDBootstrap::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
540finish:
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*********************************************************************/
555OSReturn
556KLDBootstrap::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
591void
592KLDBootstrap::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
646finish:
647 return;
648}
649
650/*********************************************************************
651*********************************************************************/
652void
653KLDBootstrap::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
760finish:
761 return;
762}
763
764#if PRAGMA_MARK
765#pragma mark Bootstrap Functions
766#endif
767/*********************************************************************
768* Bootstrap Functions
769*********************************************************************/
770static void
771bootstrapRecordStartupExtensions(void)
772{
773 sBootstrapObject.readStartupExtensions();
774 return;
775}
776
777static void
778bootstrapLoadSecurityExtensions(void)
779{
780 sBootstrapObject.loadSecurityExtensions();
781 return;
782}
783