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