]> git.saurik.com Git - apple/xnu.git/blame - libsa/bootstrap.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / libsa / bootstrap.cpp
CommitLineData
1c79356b 1/*
39236c6e 2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
b0d623f7 28extern "C" {
1c79356b 29#include <mach/kmod.h>
b0d623f7
A
30#include <libkern/kernel_mach_header.h>
31#include <libkern/prelink.h>
f427ee49 32#include <libkern/crypto/sha2.h>
b0d623f7
A
33}
34
f427ee49
A
35#define IOKIT_ENABLE_SHARED_PTR
36
b0d623f7
A
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>
6d2010ae 42#include <IOKit/IOService.h>
b0d623f7
A
43#include <IOKit/IODeviceTreeSupport.h>
44#include <IOKit/IOCatalogue.h>
45
316670eb
A
46#if __x86_64__
47#define KASLR_KEXT_DEBUG 0
48#endif
49
b0d623f7
A
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" {
0a7de745
A
69extern void (*record_startup_extensions_function)(void);
70extern void (*load_security_extensions_function)(void);
b0d623f7 71};
1c79356b 72
b0d623f7
A
73static void bootstrapRecordStartupExtensions(void);
74static void bootstrapLoadSecurityExtensions(void);
75
6d2010ae 76
39236c6e
A
77#if NO_KEXTD
78extern "C" bool IORamDiskBSDRoot(void);
79#endif
80
b0d623f7
A
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[] = {
0a7de745
A
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
b0d623f7 116};
1c79356b 117
b0d623f7
A
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*********************************************************************/
1c79356b 128class KLDBootstrap {
0a7de745
A
129 friend void bootstrapRecordStartupExtensions(void);
130 friend void bootstrapLoadSecurityExtensions(void);
b0d623f7
A
131
132private:
0a7de745
A
133 void readStartupExtensions(void);
134
f427ee49 135 void readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type);
0a7de745
A
136 void readBooterExtensions(void);
137
138 OSReturn loadKernelComponentKexts(void);
139 void loadKernelExternalComponents(void);
140 void readBuiltinPersonalities(void);
141
142 void loadSecurityExtensions(void);
143
1c79356b 144public:
0a7de745
A
145 KLDBootstrap(void);
146 ~KLDBootstrap(void);
1c79356b
A
147};
148
cb323159 149LIBKERN_ALWAYS_DESTROY static KLDBootstrap sBootstrapObject;
1c79356b 150
b0d623f7
A
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{
0a7de745
A
157 if (this != &sBootstrapObject) {
158 panic("Attempt to access bootstrap segment.");
159 }
160 record_startup_extensions_function = &bootstrapRecordStartupExtensions;
161 load_security_extensions_function = &bootstrapLoadSecurityExtensions;
b0d623f7
A
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{
0a7de745
A
170 if (this != &sBootstrapObject) {
171 panic("Attempt to access bootstrap segment.");
172 }
6d2010ae
A
173
174
cb323159
A
175 record_startup_extensions_function = NULL;
176 load_security_extensions_function = NULL;
b0d623f7 177}
1c79356b 178
b0d623f7
A
179/*********************************************************************
180*********************************************************************/
181void
182KLDBootstrap::readStartupExtensions(void)
183{
0a7de745
A
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
f427ee49
A
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
0a7de745
A
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 */
f427ee49 203 prelinkInfoSect = getsectbynamefromheader(mh, kPrelinkInfoSegment, kPrelinkInfoSection);
0a7de745 204 if (prelinkInfoSect->size) {
f427ee49 205 readPrelinkedExtensions(mh, KCKindPrimary);
0a7de745
A
206 } else {
207 readBooterExtensions();
208 }
209
f427ee49
A
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
0a7de745
A
216 loadKernelComponentKexts();
217 loadKernelExternalComponents();
218 readBuiltinPersonalities();
f427ee49 219 OSKext::sendAllKextPersonalitiesToCatalog(true);
0a7de745
A
220
221 return;
b0d623f7
A
222}
223
224/*********************************************************************
225*********************************************************************/
226void
f427ee49 227KLDBootstrap::readPrelinkedExtensions(kernel_mach_header_t *mh, kc_kind_t type)
b0d623f7 228{
f427ee49
A
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
0a7de745
A
235
236 OSKextLog(/* kext */ NULL,
237 kOSKextLogProgressLevel |
238 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
239 "Starting from prelinked kernel.");
240
f427ee49
A
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.
0a7de745 246 */
f427ee49
A
247 infoPlistSection = getsectbynamefromheader(mh, kPrelinkInfoSegment, kPrelinkInfoSection);
248 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
0a7de745 249 if (parsedXML) {
f427ee49 250 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
0a7de745 251 }
f427ee49
A
252
253 if (!infoDict) {
254 const char *errorCString = "(unknown error)";
0a7de745
A
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,
f427ee49
A
262 "Error unserializing kext info plist section: %s.", errorCString);
263 return;
0a7de745
A
264 }
265
f427ee49
A
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;
0a7de745 272 }
b0d623f7 273
f427ee49
A
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.
0a7de745 278 */
f427ee49
A
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.");
0a7de745 282 }
f427ee49 283 goto skip_adding_kexts;
0a7de745
A
284 }
285
f427ee49
A
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);
0a7de745 292
f427ee49
A
293 if (!ret) {
294 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
295 "Error loading kext info from prelinked primary KC");
296 return;
0a7de745
A
297 }
298
f427ee49
A
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);
0a7de745
A
311 }
312
f427ee49 313skip_adding_kexts:
316670eb 314#if CONFIG_KEXT_BASEMENT
f427ee49
A
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 */
b0d623f7 334
f427ee49
A
335 /*
336 * Free the prelink info segment, we're done with it.
0a7de745 337 */
f427ee49 338 kernel_segment_command_t *prelinkInfoSegment = NULL;
0a7de745
A
339 prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
340 if (prelinkInfoSegment) {
341 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
342 (vm_size_t)prelinkInfoSegment->vmsize);
343 }
b0d623f7 344
0a7de745 345 return;
1c79356b
A
346}
347
39037602 348
b0d623f7
A
349/*********************************************************************
350*********************************************************************/
351#define BOOTER_KEXT_PREFIX "Driver-"
b0d623f7
A
352
353typedef struct _DeviceTreeBuffer {
0a7de745
A
354 uint32_t paddr;
355 uint32_t length;
b0d623f7
A
356} _DeviceTreeBuffer;
357
358void
359KLDBootstrap::readBooterExtensions(void)
360{
f427ee49
A
361 OSSharedPtr<IORegistryEntry> booterMemoryMap;
362 OSSharedPtr<OSDictionary> propertyDict;
363 OSSharedPtr<OSCollectionIterator> keyIterator;
0a7de745
A
364 OSString * deviceTreeName = NULL;// do not release
365
366 const _DeviceTreeBuffer * deviceTreeBuffer = NULL;// do not free
367 char * booterDataPtr = NULL;// do not free
f427ee49
A
368 OSSharedPtr<OSData> booterData;
369 OSSharedPtr<OSKext> aKext;
0a7de745
A
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
f427ee49 395 keyIterator = OSCollectionIterator::withCollection(propertyDict.get());
0a7de745
A
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 */
5ba3f43e 406#ifndef CONFIG_EMBEDDED
f427ee49 407 OSKext::createExcludeListFromBooterData(propertyDict.get(), keyIterator.get());
5ba3f43e 408#endif
f427ee49 409 // !! reset the iterator, not the pointer
0a7de745
A
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
0a7de745
A
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 */
f427ee49 475 OSSharedPtr<OSKext> newKext = OSKext::withBooterData(deviceTreeName, booterData.get());
0a7de745
A
476
477 booterMemoryMap->removeProperty(deviceTreeName);
478 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
b0d623f7
A
479
480finish:
0a7de745 481 return;
b0d623f7
A
482}
483
484/*********************************************************************
485*********************************************************************/
b0d623f7
A
486#define COM_APPLE "com.apple."
487
488void
489KLDBootstrap::loadSecurityExtensions(void)
490{
f427ee49
A
491 OSSharedPtr<OSDictionary> extensionsDict;
492 OSSharedPtr<OSCollectionIterator> keyIterator;
0a7de745
A
493 OSString * bundleID = NULL;// don't release
494 OSKext * theKext = NULL;// don't release
0a7de745
A
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
f427ee49 506 keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
0a7de745
A
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
cb323159 530 if (kOSBooleanTrue == theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)) {
0a7de745
A
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 }
b0d623f7
A
539
540finish:
0a7de745 541 return;
b0d623f7
A
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{
f427ee49
A
558 OSReturn result = kOSReturnSuccess;// optimistic
559 OSSharedPtr<OSKext> theKext;
560 const char ** kextIDPtr = NULL; // do not release
0a7de745
A
561
562 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
0a7de745
A
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
0a7de745 578 return result;
b0d623f7
A
579}
580
316670eb
A
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{
f427ee49
A
594 OSSharedPtr<OSDictionary> extensionsDict;
595 OSSharedPtr<OSCollectionIterator> keyIterator;
0a7de745
A
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
f427ee49 610 keyIterator = OSCollectionIterator::withCollection(extensionsDict.get());
0a7de745
A
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 }
316670eb
A
645
646finish:
0a7de745 647 return;
316670eb
A
648}
649
b0d623f7 650/*********************************************************************
0a7de745 651*********************************************************************/
b0d623f7
A
652void
653KLDBootstrap::readBuiltinPersonalities(void)
654{
f427ee49 655 OSSharedPtr<OSObject> parsedXML;
0a7de745 656 OSArray * builtinExtensions = NULL;// do not release
f427ee49
A
657 OSSharedPtr<OSArray> allPersonalities;
658 OSSharedPtr<OSString> errorString;
0a7de745 659 kernel_section_t * infosect = NULL;// do not free
f427ee49 660 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
0a7de745
A
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,
f427ee49 682 errorString);
0a7de745 683 if (parsedXML) {
f427ee49 684 builtinExtensions = OSDynamicCast(OSArray, parsedXML.get());
0a7de745
A
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
0a7de745
A
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
b0d623f7
A
751 if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
752 personality->setObject(kCFBundleIdentifierKey, moduleName);
753 }
0a7de745
A
754 allPersonalities->setObject(personality);
755 }
756 }
757
f427ee49 758 gIOCatalogue->addDrivers(allPersonalities.get(), false);
b0d623f7
A
759
760finish:
0a7de745 761 return;
b0d623f7
A
762}
763
764#if PRAGMA_MARK
765#pragma mark Bootstrap Functions
766#endif
767/*********************************************************************
768* Bootstrap Functions
769*********************************************************************/
0a7de745
A
770static void
771bootstrapRecordStartupExtensions(void)
b0d623f7 772{
0a7de745
A
773 sBootstrapObject.readStartupExtensions();
774 return;
b0d623f7
A
775}
776
0a7de745
A
777static void
778bootstrapLoadSecurityExtensions(void)
b0d623f7 779{
0a7de745
A
780 sBootstrapObject.loadSecurityExtensions();
781 return;
1c79356b 782}
6d2010ae 783