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