]> git.saurik.com Git - apple/xnu.git/blame - libsa/bootstrap.cpp
xnu-3247.1.106.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@
1c79356b 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.
8f6c56a5 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.
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
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.
8f6c56a5 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>
32}
33
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>
6d2010ae 39#include <IOKit/IOService.h>
b0d623f7
A
40#include <IOKit/IODeviceTreeSupport.h>
41#include <IOKit/IOCatalogue.h>
42
316670eb
A
43#if __x86_64__
44#define KASLR_KEXT_DEBUG 0
45#endif
46
b0d623f7
A
47#if PRAGMA_MARK
48#pragma mark Bootstrap Declarations
49#endif
50/*********************************************************************
51* Bootstrap Declarations
52*
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.
56*
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.
60*
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
63* be linked against.
64*********************************************************************/
65extern "C" {
66 extern void (*record_startup_extensions_function)(void);
67 extern void (*load_security_extensions_function)(void);
68};
1c79356b 69
b0d623f7
A
70static void bootstrapRecordStartupExtensions(void);
71static void bootstrapLoadSecurityExtensions(void);
72
6d2010ae 73
39236c6e
A
74#if NO_KEXTD
75extern "C" bool IORamDiskBSDRoot(void);
76#endif
77
b0d623f7
A
78#if PRAGMA_MARK
79#pragma mark Macros
80#endif
81/*********************************************************************
82* Macros
83*********************************************************************/
84#define CONST_STRLEN(str) (sizeof(str) - 1)
85
86#if PRAGMA_MARK
87#pragma mark Kernel Component Kext Identifiers
88#endif
89/*********************************************************************
90* Kernel Component Kext Identifiers
91*
92* We could have each kernel resource kext automatically "load" as
93* it's created, but it's nicer to have them listed in kextstat in
94* the order of this list. We'll walk through this after setting up
95* all the boot kexts and have them load up.
96*********************************************************************/
97static const char * sKernelComponentNames[] = {
98 // The kexts for these IDs must have a version matching 'osrelease'.
99 "com.apple.kernel",
100 "com.apple.kpi.bsd",
101 "com.apple.kpi.dsep",
102 "com.apple.kpi.iokit",
103 "com.apple.kpi.libkern",
104 "com.apple.kpi.mach",
105 "com.apple.kpi.private",
106 "com.apple.kpi.unsupported",
107 "com.apple.iokit.IONVRAMFamily",
108 "com.apple.driver.AppleNMI",
109 "com.apple.iokit.IOSystemManagementFamily",
110 "com.apple.iokit.ApplePlatformFamily",
b0d623f7
A
111 NULL
112};
1c79356b 113
b0d623f7
A
114#if PRAGMA_MARK
115#pragma mark KLDBootstrap Class
116#endif
117/*********************************************************************
118* KLDBootstrap Class
119*
120* We use a C++ class here so that it can be a friend of OSKext and
121* get at private stuff. We can't hide the class itself, but we can
122* hide the instance through which we invoke the functions.
123*********************************************************************/
1c79356b 124class KLDBootstrap {
b0d623f7
A
125 friend void bootstrapRecordStartupExtensions(void);
126 friend void bootstrapLoadSecurityExtensions(void);
127
128private:
129 void readStartupExtensions(void);
130
131 void readPrelinkedExtensions(
132 kernel_section_t * prelinkInfoSect);
133 void readBooterExtensions(void);
b0d623f7
A
134
135 OSReturn loadKernelComponentKexts(void);
316670eb 136 void loadKernelExternalComponents(void);
b0d623f7
A
137 void readBuiltinPersonalities(void);
138
139 void loadSecurityExtensions(void);
140
1c79356b 141public:
b0d623f7
A
142 KLDBootstrap(void);
143 ~KLDBootstrap(void);
1c79356b
A
144};
145
b0d623f7 146static KLDBootstrap sBootstrapObject;
1c79356b 147
b0d623f7
A
148/*********************************************************************
149* Set the function pointers for the entry points into the bootstrap
150* segment upon C++ static constructor invocation.
151*********************************************************************/
152KLDBootstrap::KLDBootstrap(void)
153{
154 if (this != &sBootstrapObject) {
155 panic("Attempt to access bootstrap segment.");
156 }
157 record_startup_extensions_function = &bootstrapRecordStartupExtensions;
158 load_security_extensions_function = &bootstrapLoadSecurityExtensions;
b0d623f7
A
159}
160
161/*********************************************************************
162* Clear the function pointers for the entry points into the bootstrap
163* segment upon C++ static destructor invocation.
164*********************************************************************/
165KLDBootstrap::~KLDBootstrap(void)
166{
167 if (this != &sBootstrapObject) {
168 panic("Attempt to access bootstrap segment.");
169 }
6d2010ae
A
170
171
b0d623f7
A
172 record_startup_extensions_function = 0;
173 load_security_extensions_function = 0;
174}
1c79356b 175
b0d623f7
A
176/*********************************************************************
177*********************************************************************/
178void
179KLDBootstrap::readStartupExtensions(void)
180{
181 kernel_section_t * prelinkInfoSect = NULL; // do not free
1c79356b 182
b0d623f7
A
183 OSKextLog(/* kext */ NULL,
184 kOSKextLogProgressLevel |
185 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag |
186 kOSKextLogKextBookkeepingFlag,
187 "Reading startup extensions.");
188
189 /* If the prelink info segment has a nonzero size, we are prelinked
190 * and won't have any individual kexts or mkexts to read.
191 * Otherwise, we need to read kexts or the mkext from what the booter
192 * has handed us.
193 */
194 prelinkInfoSect = getsectbyname(kPrelinkInfoSegment, kPrelinkInfoSection);
195 if (prelinkInfoSect->size) {
196 readPrelinkedExtensions(prelinkInfoSect);
197 } else {
198 readBooterExtensions();
199 }
200
201 loadKernelComponentKexts();
316670eb 202 loadKernelExternalComponents();
b0d623f7
A
203 readBuiltinPersonalities();
204 OSKext::sendAllKextPersonalitiesToCatalog();
205
206 return;
207}
208
209/*********************************************************************
210*********************************************************************/
211void
212KLDBootstrap::readPrelinkedExtensions(
213 kernel_section_t * prelinkInfoSect)
214{
215 OSArray * infoDictArray = NULL; // do not release
b0d623f7
A
216 OSObject * parsedXML = NULL; // must release
217 OSDictionary * prelinkInfoDict = NULL; // do not release
218 OSString * errorString = NULL; // must release
219 OSKext * theKernel = NULL; // must release
220
b0d623f7
A
221 kernel_segment_command_t * prelinkTextSegment = NULL; // see code
222 kernel_segment_command_t * prelinkInfoSegment = NULL; // see code
223
224 /* We make some copies of data, but if anything fails we're basically
225 * going to fail the boot, so these won't be cleaned up on error.
226 */
227 void * prelinkData = NULL; // see code
b0d623f7 228 vm_size_t prelinkLength = 0;
6d2010ae 229
b0d623f7
A
230
231 OSDictionary * infoDict = NULL; // do not release
232
233 IORegistryEntry * registryRoot = NULL; // do not release
234 OSNumber * prelinkCountObj = NULL; // must release
235
236 u_int i = 0;
316670eb 237#if NO_KEXTD
39236c6e 238 bool ramDiskBoot;
316670eb 239 bool developerDevice;
39236c6e 240 bool dontLoad;
316670eb 241#endif
b0d623f7
A
242
243 OSKextLog(/* kext */ NULL,
244 kOSKextLogProgressLevel |
245 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
246 "Starting from prelinked kernel.");
247
b0d623f7
A
248 prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
249 if (!prelinkTextSegment) {
250 OSKextLog(/* kext */ NULL,
251 kOSKextLogErrorLevel |
252 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
253 "Can't find prelinked kexts' text segment.");
254 goto finish;
255 }
fe8ab488 256
316670eb
A
257#if KASLR_KEXT_DEBUG
258 unsigned long scratchSize;
259 vm_offset_t scratchAddr;
260
261 IOLog("kaslr: prelinked kernel address info: \n");
262
263 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize);
264 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
265 (unsigned long)scratchAddr,
266 (unsigned long)(scratchAddr + scratchSize),
267 scratchSize);
268
269 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize);
270 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
271 (unsigned long)scratchAddr,
272 (unsigned long)(scratchAddr + scratchSize),
273 scratchSize);
274
275 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize);
276 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
277 (unsigned long)scratchAddr,
278 (unsigned long)(scratchAddr + scratchSize),
279 scratchSize);
280
281 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize);
282 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
283 (unsigned long)scratchAddr,
284 (unsigned long)(scratchAddr + scratchSize),
285 scratchSize);
286
287 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize);
288 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
289 (unsigned long)scratchAddr,
290 (unsigned long)(scratchAddr + scratchSize),
291 scratchSize);
292
293 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize);
294 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
295 (unsigned long)scratchAddr,
296 (unsigned long)(scratchAddr + scratchSize),
297 scratchSize);
298#endif
b0d623f7
A
299
300 prelinkData = (void *) prelinkTextSegment->vmaddr;
301 prelinkLength = prelinkTextSegment->vmsize;
302
b0d623f7
A
303
304 /* Unserialize the info dictionary from the prelink info section.
305 */
306 parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr,
307 &errorString);
308 if (parsedXML) {
309 prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML);
310 }
311 if (!prelinkInfoDict) {
312 const char * errorCString = "(unknown error)";
313
314 if (errorString && errorString->getCStringNoCopy()) {
315 errorCString = errorString->getCStringNoCopy();
316 } else if (parsedXML) {
317 errorCString = "not a dictionary";
318 }
319 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
320 "Error unserializing prelink plist: %s.", errorCString);
321 goto finish;
322 }
323
316670eb 324#if NO_KEXTD
39236c6e 325 /* Check if we should keep developer kexts around.
316670eb
A
326 * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
327 */
316670eb 328 developerDevice = true;
316670eb 329 PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice));
39236c6e
A
330
331 ramDiskBoot = IORamDiskBSDRoot();
316670eb
A
332#endif /* NO_KEXTD */
333
b0d623f7
A
334 infoDictArray = OSDynamicCast(OSArray,
335 prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
336 if (!infoDictArray) {
337 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
338 "The prelinked kernel has no kext info dictionaries");
339 goto finish;
340 }
39236c6e
A
341
342 /* Create dictionary of excluded kexts
343 */
344 OSKext::createExcludeListFromPrelinkInfo(infoDictArray);
b0d623f7 345
39236c6e
A
346 /* Create OSKext objects for each info dictionary.
347 */
b0d623f7
A
348 for (i = 0; i < infoDictArray->getCount(); ++i) {
349 infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i));
350 if (!infoDict) {
351 OSKextLog(/* kext */ NULL,
352 kOSKextLogErrorLevel |
353 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
354 "Can't find info dictionary for prelinked kext #%d.", i);
355 continue;
356 }
357
316670eb 358#if NO_KEXTD
39236c6e
A
359 dontLoad = false;
360
316670eb
A
361 /* If we're not on a developer device, skip and free developer kexts.
362 */
363 if (developerDevice == false) {
364 OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean,
365 infoDict->getObject(kOSBundleDeveloperOnlyKey));
366 if (devOnlyBool == kOSBooleanTrue) {
39236c6e
A
367 dontLoad = true;
368 }
369 }
316670eb 370
39236c6e
A
371 /* Skip and free kexts that are only needed when booted from a ram disk.
372 */
373 if (ramDiskBoot == false) {
374 OSBoolean *ramDiskOnlyBool = OSDynamicCast(OSBoolean,
375 infoDict->getObject(kOSBundleRamDiskOnlyKey));
376 if (ramDiskOnlyBool == kOSBooleanTrue) {
377 dontLoad = true;
378 }
379 }
380
381 if (dontLoad == true) {
382 OSString *bundleID = OSDynamicCast(OSString,
383 infoDict->getObject(kCFBundleIdentifierKey));
384 if (bundleID) {
385 OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
386 "Kext %s not loading.", bundleID->getCStringNoCopy());
387 }
388
389 OSNumber *addressNum = OSDynamicCast(OSNumber,
390 infoDict->getObject(kPrelinkExecutableLoadKey));
391 OSNumber *lengthNum = OSDynamicCast(OSNumber,
392 infoDict->getObject(kPrelinkExecutableSizeKey));
393 if (addressNum && lengthNum) {
394#error Pick the right way to free prelinked data on this arch
316670eb 395 }
39236c6e
A
396
397 infoDictArray->removeObject(i--);
398 continue;
316670eb
A
399 }
400#endif /* NO_KEXTD */
401
b0d623f7
A
402 /* Create the kext for the entry, then release it, because the
403 * kext system keeps them around until explicitly removed.
404 * Any creation/registration failures are already logged for us.
405 */
406 OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict);
407 OSSafeReleaseNULL(newKext);
408 }
409
b0d623f7
A
410 /* Store the number of prelinked kexts in the registry so we can tell
411 * when the system has been started from a prelinked kernel.
412 */
413 registryRoot = IORegistryEntry::getRegistryRoot();
414 assert(registryRoot);
415
416 prelinkCountObj = OSNumber::withNumber(
417 (unsigned long long)infoDictArray->getCount(),
418 8 * sizeof(uint32_t));
419 assert(prelinkCountObj);
420 if (prelinkCountObj) {
421 registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj);
422 }
423
b0d623f7
A
424 OSKextLog(/* kext */ NULL,
425 kOSKextLogProgressLevel |
426 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
427 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
6d2010ae
A
428 "%u prelinked kexts",
429 infoDictArray->getCount());
b0d623f7 430
316670eb
A
431#if CONFIG_KEXT_BASEMENT
432 /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
433 * special VM region during OSKext init time, so we can free the whole
434 * segment now.
b0d623f7
A
435 */
436 ml_static_mfree((vm_offset_t) prelinkData, prelinkLength);
316670eb 437#endif /* __x86_64__ */
b0d623f7 438
b0d623f7
A
439 /* Free the prelink info segment, we're done with it.
440 */
441 prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
442 if (prelinkInfoSegment) {
443 ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
444 (vm_size_t)prelinkInfoSegment->vmsize);
445 }
446
447finish:
448 OSSafeRelease(errorString);
449 OSSafeRelease(parsedXML);
450 OSSafeRelease(theKernel);
451 OSSafeRelease(prelinkCountObj);
452 return;
1c79356b
A
453}
454
b0d623f7
A
455/*********************************************************************
456*********************************************************************/
457#define BOOTER_KEXT_PREFIX "Driver-"
b0d623f7
A
458
459typedef struct _DeviceTreeBuffer {
460 uint32_t paddr;
461 uint32_t length;
462} _DeviceTreeBuffer;
463
464void
465KLDBootstrap::readBooterExtensions(void)
466{
467 IORegistryEntry * booterMemoryMap = NULL; // must release
468 OSDictionary * propertyDict = NULL; // must release
469 OSCollectionIterator * keyIterator = NULL; // must release
470 OSString * deviceTreeName = NULL; // do not release
471
472 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not free
473 char * booterDataPtr = NULL; // do not free
474 OSData * booterData = NULL; // must release
475
476 OSKext * aKext = NULL; // must release
477
478 OSKextLog(/* kext */ NULL,
479 kOSKextLogProgressLevel |
480 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
fe8ab488 481 "Reading startup extensions from booter memory.");
b0d623f7
A
482
483 booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);
484
485 if (!booterMemoryMap) {
486 OSKextLog(/* kext */ NULL,
487 kOSKextLogErrorLevel |
488 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
489 "Can't read booter memory map.");
490 goto finish;
491 }
492
493 propertyDict = booterMemoryMap->dictionaryWithProperties();
494 if (!propertyDict) {
495 OSKextLog(/* kext */ NULL,
496 kOSKextLogErrorLevel |
497 kOSKextLogDirectoryScanFlag,
498 "Can't get property dictionary from memory map.");
499 goto finish;
500 }
501
502 keyIterator = OSCollectionIterator::withCollection(propertyDict);
503 if (!keyIterator) {
504 OSKextLog(/* kext */ NULL,
505 kOSKextLogErrorLevel |
506 kOSKextLogGeneralFlag,
507 "Can't allocate iterator for driver images.");
508 goto finish;
509 }
510
39236c6e
A
511 /* Create dictionary of excluded kexts
512 */
513 OSKext::createExcludeListFromBooterData(propertyDict, keyIterator);
514 keyIterator->reset();
515
b0d623f7
A
516 while ( ( deviceTreeName =
517 OSDynamicCast(OSString, keyIterator->getNextObject() ))) {
518
b0d623f7
A
519 const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
520 OSData * deviceTreeEntry = OSDynamicCast(OSData,
521 propertyDict->getObject(deviceTreeName));
522
523 /* Clear out the booterData from the prior iteration.
524 */
525 OSSafeReleaseNULL(booterData);
526
527 /* If there is no entry for the name, we can't do much with it. */
528 if (!deviceTreeEntry) {
529 continue;
530 }
531
fe8ab488
A
532 /* Make sure it is a kext */
533 if (strncmp(devTreeNameCString,
534 BOOTER_KEXT_PREFIX,
535 CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
b0d623f7
A
536 continue;
537 }
538
539 deviceTreeBuffer = (const _DeviceTreeBuffer *)
540 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
541 if (!deviceTreeBuffer) {
542 /* We can't get to the data, so we can't do anything,
543 * not even free it from physical memory (if it's there).
544 */
545 OSKextLog(/* kext */ NULL,
546 kOSKextLogErrorLevel |
547 kOSKextLogDirectoryScanFlag,
548 "Device tree entry %s has NULL pointer.",
549 devTreeNameCString);
550 goto finish; // xxx - continue, panic?
551 }
552
553 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
554 if (!booterDataPtr) {
555 OSKextLog(/* kext */ NULL,
556 kOSKextLogErrorLevel |
557 kOSKextLogDirectoryScanFlag,
fe8ab488 558 "Can't get virtual address for device tree entry %s.",
b0d623f7
A
559 devTreeNameCString);
560 goto finish;
561 }
562
563 /* Wrap the booter data buffer in an OSData and set a dealloc function
564 * so it will take care of the physical memory when freed. Kexts will
565 * retain the booterData for as long as they need it. Remove the entry
566 * from the booter memory map after this is done.
567 */
568 booterData = OSData::withBytesNoCopy(booterDataPtr,
569 deviceTreeBuffer->length);
570 if (!booterData) {
571 OSKextLog(/* kext */ NULL,
572 kOSKextLogErrorLevel |
573 kOSKextLogGeneralFlag,
574 "Error - Can't allocate OSData wrapper for device tree entry %s.",
575 devTreeNameCString);
576 goto finish;
577 }
578 booterData->setDeallocFunction(osdata_phys_free);
579
fe8ab488
A
580 /* Create the kext for the entry, then release it, because the
581 * kext system keeps them around until explicitly removed.
582 * Any creation/registration failures are already logged for us.
583 */
584 OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData);
585 OSSafeRelease(newKext);
b0d623f7
A
586
587 booterMemoryMap->removeProperty(deviceTreeName);
588
589 } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */
590
591finish:
592
593 OSSafeRelease(booterMemoryMap);
594 OSSafeRelease(propertyDict);
595 OSSafeRelease(keyIterator);
596 OSSafeRelease(booterData);
597 OSSafeRelease(aKext);
598 return;
599}
600
601/*********************************************************************
602*********************************************************************/
b0d623f7
A
603#define COM_APPLE "com.apple."
604
605void
606KLDBootstrap::loadSecurityExtensions(void)
607{
608 OSDictionary * extensionsDict = NULL; // must release
609 OSCollectionIterator * keyIterator = NULL; // must release
610 OSString * bundleID = NULL; // don't release
611 OSKext * theKext = NULL; // don't release
612 OSBoolean * isSecurityKext = NULL; // don't release
613
614 OSKextLog(/* kext */ NULL,
615 kOSKextLogStepLevel |
616 kOSKextLogLoadFlag,
617 "Loading security extensions.");
618
619 extensionsDict = OSKext::copyKexts();
620 if (!extensionsDict) {
621 return;
622 }
623
624 keyIterator = OSCollectionIterator::withCollection(extensionsDict);
625 if (!keyIterator) {
626 OSKextLog(/* kext */ NULL,
627 kOSKextLogErrorLevel |
628 kOSKextLogGeneralFlag,
629 "Failed to allocate iterator for security extensions.");
630 goto finish;
631 }
632
633 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
634
635 const char * bundle_id = bundleID->getCStringNoCopy();
636
637 /* Skip extensions whose bundle IDs don't start with "com.apple.".
638 */
639 if (!bundle_id ||
640 (strncmp(bundle_id, COM_APPLE, CONST_STRLEN(COM_APPLE)) != 0)) {
641
642 continue;
643 }
644
645 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
646 if (!theKext) {
647 continue;
648 }
649
650 isSecurityKext = OSDynamicCast(OSBoolean,
316670eb 651 theKext->getPropertyForHostArch(kAppleSecurityExtensionKey));
b0d623f7
A
652 if (isSecurityKext && isSecurityKext->isTrue()) {
653 OSKextLog(/* kext */ NULL,
654 kOSKextLogStepLevel |
655 kOSKextLogLoadFlag,
656 "Loading security extension %s.", bundleID->getCStringNoCopy());
657 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
658 /* allowDefer */ false);
659 }
660 }
661
662finish:
663 OSSafeRelease(keyIterator);
664 OSSafeRelease(extensionsDict);
665
666 return;
667}
668
669/*********************************************************************
670* We used to require that all listed kernel components load, but
671* nowadays we can get them from userland so we only try to load the
672* ones we have. If an error occurs later, such is life.
673*
674* Note that we look the kexts up first, so we can avoid spurious
675* (in this context, anyhow) log messages about kexts not being found.
676*
677* xxx - do we even need to do this any more? Check if the kernel
678* xxx - compoonents just load in the regular paths
679*********************************************************************/
680OSReturn
681KLDBootstrap::loadKernelComponentKexts(void)
682{
683 OSReturn result = kOSReturnSuccess; // optimistic
684 OSKext * theKext = NULL; // must release
685 const char ** kextIDPtr = NULL; // do not release
686
687 for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
688
689 OSSafeReleaseNULL(theKext);
690 theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr);
691
692 if (theKext) {
693 if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
694 *kextIDPtr, /* allowDefer */ false)) {
695
696 // xxx - check KextBookkeeping, might be redundant
697 OSKextLog(/* kext */ NULL,
698 kOSKextLogErrorLevel |
699 kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
700 "Failed to initialize kernel component %s.", *kextIDPtr);
701 result = kOSReturnError;
702 }
703 }
704 }
705
706 OSSafeRelease(theKext);
707 return result;
708}
709
316670eb
A
710/*********************************************************************
711* Ensure that Kernel External Components are loaded early in boot,
712* before other kext personalities get sent to the IOCatalogue. These
713* kexts are treated specially because they may provide the implementation
714* for kernel-vended KPI, so they must register themselves before
715* general purpose IOKit probing begins.
716*********************************************************************/
717
718#define COM_APPLE_KEC "com.apple.kec."
719
720void
721KLDBootstrap::loadKernelExternalComponents(void)
722{
723 OSDictionary * extensionsDict = NULL; // must release
724 OSCollectionIterator * keyIterator = NULL; // must release
725 OSString * bundleID = NULL; // don't release
726 OSKext * theKext = NULL; // don't release
727 OSBoolean * isKernelExternalComponent = NULL; // don't release
728
729 OSKextLog(/* kext */ NULL,
730 kOSKextLogStepLevel |
731 kOSKextLogLoadFlag,
732 "Loading Kernel External Components.");
733
734 extensionsDict = OSKext::copyKexts();
735 if (!extensionsDict) {
736 return;
737 }
738
739 keyIterator = OSCollectionIterator::withCollection(extensionsDict);
740 if (!keyIterator) {
741 OSKextLog(/* kext */ NULL,
742 kOSKextLogErrorLevel |
743 kOSKextLogGeneralFlag,
744 "Failed to allocate iterator for Kernel External Components.");
745 goto finish;
746 }
747
748 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
749
750 const char * bundle_id = bundleID->getCStringNoCopy();
751
752 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
753 */
754 if (!bundle_id ||
755 (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
756
757 continue;
758 }
759
760 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
761 if (!theKext) {
762 continue;
763 }
764
765 isKernelExternalComponent = OSDynamicCast(OSBoolean,
766 theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
767 if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
768 OSKextLog(/* kext */ NULL,
769 kOSKextLogStepLevel |
770 kOSKextLogLoadFlag,
771 "Loading kernel external component %s.", bundleID->getCStringNoCopy());
772 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
773 /* allowDefer */ false);
774 }
775 }
776
777finish:
778 OSSafeRelease(keyIterator);
779 OSSafeRelease(extensionsDict);
780
781 return;
782}
783
b0d623f7
A
784/*********************************************************************
785 *********************************************************************/
786void
787KLDBootstrap::readBuiltinPersonalities(void)
788{
789 OSObject * parsedXML = NULL; // must release
790 OSArray * builtinExtensions = NULL; // do not release
791 OSArray * allPersonalities = NULL; // must release
792 OSString * errorString = NULL; // must release
793 kernel_section_t * infosect = NULL; // do not free
794 OSCollectionIterator * personalitiesIterator = NULL; // must release
795 unsigned int count, i;
796
797 OSKextLog(/* kext */ NULL,
798 kOSKextLogStepLevel |
799 kOSKextLogLoadFlag,
800 "Reading built-in kernel personalities for I/O Kit drivers.");
1c79356b 801
b0d623f7
A
802 /* Look in the __BUILTIN __info segment for an array of Info.plist
803 * entries. For each one, extract the personalities dictionary, add
804 * it to our array, then push them all (without matching) to
805 * the IOCatalogue. This can be used to augment the personalities
806 * in gIOKernelConfigTables, especially when linking entire kexts into
807 * the mach_kernel image.
0b4e3aa0 808 */
b0d623f7
A
809 infosect = getsectbyname("__BUILTIN", "__info");
810 if (!infosect) {
811 // this isn't fatal
812 goto finish;
813 }
814
815 parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr,
816 &errorString);
817 if (parsedXML) {
818 builtinExtensions = OSDynamicCast(OSArray, parsedXML);
819 }
820 if (!builtinExtensions) {
821 const char * errorCString = "(unknown error)";
822
823 if (errorString && errorString->getCStringNoCopy()) {
824 errorCString = errorString->getCStringNoCopy();
825 } else if (parsedXML) {
826 errorCString = "not an array";
827 }
828 OSKextLog(/* kext */ NULL,
829 kOSKextLogErrorLevel |
830 kOSKextLogLoadFlag,
831 "Error unserializing built-in personalities: %s.", errorCString);
832 goto finish;
833 }
834
835 // estimate 3 personalities per Info.plist/kext
836 count = builtinExtensions->getCount();
837 allPersonalities = OSArray::withCapacity(count * 3);
838
839 for (i = 0; i < count; i++) {
840 OSDictionary * infoDict = NULL; // do not release
841 OSString * moduleName = NULL; // do not release
842 OSDictionary * personalities; // do not release
843 OSString * personalityName; // do not release
844
845 OSSafeReleaseNULL(personalitiesIterator);
846
847 infoDict = OSDynamicCast(OSDictionary,
848 builtinExtensions->getObject(i));
849 if (!infoDict) {
850 continue;
851 }
852
853 moduleName = OSDynamicCast(OSString,
854 infoDict->getObject(kCFBundleIdentifierKey));
855 if (!moduleName) {
856 continue;
857 }
858
859 OSKextLog(/* kext */ NULL,
860 kOSKextLogStepLevel |
861 kOSKextLogLoadFlag,
862 "Adding personalities for built-in driver %s:",
863 moduleName->getCStringNoCopy());
864
865 personalities = OSDynamicCast(OSDictionary,
866 infoDict->getObject("IOKitPersonalities"));
867 if (!personalities) {
868 continue;
869 }
870
871 personalitiesIterator = OSCollectionIterator::withCollection(personalities);
872 if (!personalitiesIterator) {
873 continue; // xxx - well really, what can we do? should we panic?
874 }
875
876 while ((personalityName = OSDynamicCast(OSString,
877 personalitiesIterator->getNextObject()))) {
878
879 OSDictionary * personality = OSDynamicCast(OSDictionary,
880 personalities->getObject(personalityName));
881
882 OSKextLog(/* kext */ NULL,
883 kOSKextLogDetailLevel |
884 kOSKextLogLoadFlag,
885 "Adding built-in driver personality %s.",
886 personalityName->getCStringNoCopy());
887
888 if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
889 personality->setObject(kCFBundleIdentifierKey, moduleName);
890 }
891 allPersonalities->setObject(personality);
892 }
893 }
894
895 gIOCatalogue->addDrivers(allPersonalities, false);
896
897finish:
898 OSSafeRelease(parsedXML);
899 OSSafeRelease(allPersonalities);
900 OSSafeRelease(errorString);
901 OSSafeRelease(personalitiesIterator);
902 return;
903}
904
905#if PRAGMA_MARK
906#pragma mark Bootstrap Functions
907#endif
908/*********************************************************************
909* Bootstrap Functions
910*********************************************************************/
911static void bootstrapRecordStartupExtensions(void)
912{
913 sBootstrapObject.readStartupExtensions();
914 return;
915}
916
917static void bootstrapLoadSecurityExtensions(void)
918{
919 sBootstrapObject.loadSecurityExtensions();
920 return;
1c79356b 921}
6d2010ae 922