]> git.saurik.com Git - apple/xnu.git/blame - libsa/bootstrap.cpp
xnu-2050.22.13.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
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
b0d623f7
A
74#if PRAGMA_MARK
75#pragma mark Macros
76#endif
77/*********************************************************************
78* Macros
79*********************************************************************/
80#define CONST_STRLEN(str) (sizeof(str) - 1)
81
82#if PRAGMA_MARK
83#pragma mark Kernel Component Kext Identifiers
84#endif
85/*********************************************************************
86* Kernel Component Kext Identifiers
87*
88* We could have each kernel resource kext automatically "load" as
89* it's created, but it's nicer to have them listed in kextstat in
90* the order of this list. We'll walk through this after setting up
91* all the boot kexts and have them load up.
92*********************************************************************/
93static const char * sKernelComponentNames[] = {
94 // The kexts for these IDs must have a version matching 'osrelease'.
95 "com.apple.kernel",
96 "com.apple.kpi.bsd",
97 "com.apple.kpi.dsep",
98 "com.apple.kpi.iokit",
99 "com.apple.kpi.libkern",
100 "com.apple.kpi.mach",
101 "com.apple.kpi.private",
102 "com.apple.kpi.unsupported",
103 "com.apple.iokit.IONVRAMFamily",
104 "com.apple.driver.AppleNMI",
105 "com.apple.iokit.IOSystemManagementFamily",
106 "com.apple.iokit.ApplePlatformFamily",
b0d623f7
A
107 NULL
108};
1c79356b 109
b0d623f7
A
110#if PRAGMA_MARK
111#pragma mark KLDBootstrap Class
112#endif
113/*********************************************************************
114* KLDBootstrap Class
115*
116* We use a C++ class here so that it can be a friend of OSKext and
117* get at private stuff. We can't hide the class itself, but we can
118* hide the instance through which we invoke the functions.
119*********************************************************************/
1c79356b 120class KLDBootstrap {
b0d623f7
A
121 friend void bootstrapRecordStartupExtensions(void);
122 friend void bootstrapLoadSecurityExtensions(void);
123
124private:
125 void readStartupExtensions(void);
126
127 void readPrelinkedExtensions(
128 kernel_section_t * prelinkInfoSect);
129 void readBooterExtensions(void);
130 OSReturn readMkextExtensions(
131 OSString * deviceTreeName,
132 OSData * deviceTreeData);
133
134 OSReturn loadKernelComponentKexts(void);
316670eb 135 void loadKernelExternalComponents(void);
b0d623f7
A
136 void readBuiltinPersonalities(void);
137
138 void loadSecurityExtensions(void);
139
1c79356b 140public:
b0d623f7
A
141 KLDBootstrap(void);
142 ~KLDBootstrap(void);
1c79356b
A
143};
144
b0d623f7 145static KLDBootstrap sBootstrapObject;
1c79356b 146
b0d623f7
A
147/*********************************************************************
148* Set the function pointers for the entry points into the bootstrap
149* segment upon C++ static constructor invocation.
150*********************************************************************/
151KLDBootstrap::KLDBootstrap(void)
152{
153 if (this != &sBootstrapObject) {
154 panic("Attempt to access bootstrap segment.");
155 }
156 record_startup_extensions_function = &bootstrapRecordStartupExtensions;
157 load_security_extensions_function = &bootstrapLoadSecurityExtensions;
b0d623f7
A
158}
159
160/*********************************************************************
161* Clear the function pointers for the entry points into the bootstrap
162* segment upon C++ static destructor invocation.
163*********************************************************************/
164KLDBootstrap::~KLDBootstrap(void)
165{
166 if (this != &sBootstrapObject) {
167 panic("Attempt to access bootstrap segment.");
168 }
6d2010ae
A
169
170
b0d623f7
A
171 record_startup_extensions_function = 0;
172 load_security_extensions_function = 0;
173}
1c79356b 174
b0d623f7
A
175/*********************************************************************
176*********************************************************************/
177void
178KLDBootstrap::readStartupExtensions(void)
179{
180 kernel_section_t * prelinkInfoSect = NULL; // do not free
1c79356b 181
b0d623f7
A
182 OSKextLog(/* kext */ NULL,
183 kOSKextLogProgressLevel |
184 kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag |
185 kOSKextLogKextBookkeepingFlag,
186 "Reading startup extensions.");
187
188 /* If the prelink info segment has a nonzero size, we are prelinked
189 * and won't have any individual kexts or mkexts to read.
190 * Otherwise, we need to read kexts or the mkext from what the booter
191 * has handed us.
192 */
193 prelinkInfoSect = getsectbyname(kPrelinkInfoSegment, kPrelinkInfoSection);
194 if (prelinkInfoSect->size) {
195 readPrelinkedExtensions(prelinkInfoSect);
196 } else {
197 readBooterExtensions();
198 }
199
200 loadKernelComponentKexts();
316670eb 201 loadKernelExternalComponents();
b0d623f7
A
202 readBuiltinPersonalities();
203 OSKext::sendAllKextPersonalitiesToCatalog();
204
205 return;
206}
207
208/*********************************************************************
209*********************************************************************/
210void
211KLDBootstrap::readPrelinkedExtensions(
212 kernel_section_t * prelinkInfoSect)
213{
214 OSArray * infoDictArray = NULL; // do not release
b0d623f7
A
215 OSObject * parsedXML = NULL; // must release
216 OSDictionary * prelinkInfoDict = NULL; // do not release
217 OSString * errorString = NULL; // must release
218 OSKext * theKernel = NULL; // must release
219
b0d623f7
A
220 kernel_segment_command_t * prelinkTextSegment = NULL; // see code
221 kernel_segment_command_t * prelinkInfoSegment = NULL; // see code
222
223 /* We make some copies of data, but if anything fails we're basically
224 * going to fail the boot, so these won't be cleaned up on error.
225 */
226 void * prelinkData = NULL; // see code
b0d623f7 227 vm_size_t prelinkLength = 0;
6d2010ae 228
316670eb 229#if __i386__
b0d623f7 230 vm_map_offset_t prelinkDataMapOffset = 0;
6d2010ae 231 void * prelinkCopy = NULL; // see code
b0d623f7 232 kern_return_t mem_result = KERN_SUCCESS;
6d2010ae 233#endif
b0d623f7
A
234
235 OSDictionary * infoDict = NULL; // do not release
236
237 IORegistryEntry * registryRoot = NULL; // do not release
238 OSNumber * prelinkCountObj = NULL; // must release
239
240 u_int i = 0;
316670eb
A
241#if NO_KEXTD
242 bool developerDevice;
243#endif
b0d623f7
A
244
245 OSKextLog(/* kext */ NULL,
246 kOSKextLogProgressLevel |
247 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
248 "Starting from prelinked kernel.");
249
b0d623f7
A
250 prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
251 if (!prelinkTextSegment) {
252 OSKextLog(/* kext */ NULL,
253 kOSKextLogErrorLevel |
254 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
255 "Can't find prelinked kexts' text segment.");
256 goto finish;
257 }
316670eb
A
258
259#if KASLR_KEXT_DEBUG
260 unsigned long scratchSize;
261 vm_offset_t scratchAddr;
262
263 IOLog("kaslr: prelinked kernel address info: \n");
264
265 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize);
266 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n",
267 (unsigned long)scratchAddr,
268 (unsigned long)(scratchAddr + scratchSize),
269 scratchSize);
270
271 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize);
272 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n",
273 (unsigned long)scratchAddr,
274 (unsigned long)(scratchAddr + scratchSize),
275 scratchSize);
276
277 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize);
278 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n",
279 (unsigned long)scratchAddr,
280 (unsigned long)(scratchAddr + scratchSize),
281 scratchSize);
282
283 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize);
284 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n",
285 (unsigned long)scratchAddr,
286 (unsigned long)(scratchAddr + scratchSize),
287 scratchSize);
288
289 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize);
290 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n",
291 (unsigned long)scratchAddr,
292 (unsigned long)(scratchAddr + scratchSize),
293 scratchSize);
294
295 scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize);
296 IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n",
297 (unsigned long)scratchAddr,
298 (unsigned long)(scratchAddr + scratchSize),
299 scratchSize);
300#endif
b0d623f7
A
301
302 prelinkData = (void *) prelinkTextSegment->vmaddr;
303 prelinkLength = prelinkTextSegment->vmsize;
304
316670eb 305#if __i386__
b0d623f7
A
306 /* To enable paging and write/execute protections on the kext
307 * executables, we need to copy them out of the booter-created
308 * memory, reallocate that space with VM, then prelinkCopy them back in.
316670eb
A
309 *
310 * This isn't necessary on x86_64 because kexts have their own VM
311 * region for that architecture.
312 *
313 * XXX: arm's pmap implementation doesn't seem to let us do this.
b0d623f7
A
314 */
315
316 mem_result = kmem_alloc(kernel_map, (vm_offset_t *)&prelinkCopy,
317 prelinkLength);
318 if (mem_result != KERN_SUCCESS) {
319 OSKextLog(/* kext */ NULL,
320 kOSKextLogErrorLevel |
321 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
322 "Can't copy prelinked kexts' text for VM reassign.");
323 goto finish;
324 }
325
326 /* Copy it out.
327 */
328 memcpy(prelinkCopy, prelinkData, prelinkLength);
329
330 /* Dump the booter memory.
331 */
332 ml_static_mfree((vm_offset_t)prelinkData, prelinkLength);
333
334 /* Set up the VM region.
335 */
336 prelinkDataMapOffset = (vm_map_offset_t)(uintptr_t)prelinkData;
337 mem_result = vm_map_enter_mem_object(
338 kernel_map,
339 &prelinkDataMapOffset,
340 prelinkLength, /* mask */ 0,
341 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
342 (ipc_port_t)NULL,
343 (vm_object_offset_t) 0,
344 /* copy */ FALSE,
345 /* cur_protection */ VM_PROT_ALL,
346 /* max_protection */ VM_PROT_ALL,
347 /* inheritance */ VM_INHERIT_DEFAULT);
348 if ((mem_result != KERN_SUCCESS) ||
349 (prelinkTextSegment->vmaddr != prelinkDataMapOffset))
350 {
351 OSKextLog(/* kext */ NULL,
352 kOSKextLogErrorLevel |
353 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
354 "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).",
355 (unsigned long long) prelinkDataMapOffset, prelinkLength, mem_result);
356 goto finish;
357 }
358 prelinkData = (void *)(uintptr_t)prelinkDataMapOffset;
359
360 /* And copy it back.
361 */
362 memcpy(prelinkData, prelinkCopy, prelinkLength);
363
364 kmem_free(kernel_map, (vm_offset_t)prelinkCopy, prelinkLength);
316670eb 365#endif /* __i386__ */
b0d623f7
A
366
367 /* Unserialize the info dictionary from the prelink info section.
368 */
369 parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr,
370 &errorString);
371 if (parsedXML) {
372 prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML);
373 }
374 if (!prelinkInfoDict) {
375 const char * errorCString = "(unknown error)";
376
377 if (errorString && errorString->getCStringNoCopy()) {
378 errorCString = errorString->getCStringNoCopy();
379 } else if (parsedXML) {
380 errorCString = "not a dictionary";
381 }
382 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
383 "Error unserializing prelink plist: %s.", errorCString);
384 goto finish;
385 }
386
316670eb
A
387#if NO_KEXTD
388 /* Check if we should keep developer kexts around. Default:
389 * Release: No
390 * Development: Yes
391 * Debug : Yes
392 * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
393 */
394#if DEVELOPMENT
395 developerDevice = true;
396#else
397 developerDevice = false;
398#endif
399
400 PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice));
401#endif /* NO_KEXTD */
402
b0d623f7
A
403 infoDictArray = OSDynamicCast(OSArray,
404 prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
405 if (!infoDictArray) {
406 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
407 "The prelinked kernel has no kext info dictionaries");
408 goto finish;
409 }
410
411 /* Create OSKext objects for each info dictionary.
412 */
413 for (i = 0; i < infoDictArray->getCount(); ++i) {
414 infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i));
415 if (!infoDict) {
416 OSKextLog(/* kext */ NULL,
417 kOSKextLogErrorLevel |
418 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
419 "Can't find info dictionary for prelinked kext #%d.", i);
420 continue;
421 }
422
316670eb
A
423#if NO_KEXTD
424 /* If we're not on a developer device, skip and free developer kexts.
425 */
426 if (developerDevice == false) {
427 OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean,
428 infoDict->getObject(kOSBundleDeveloperOnlyKey));
429 if (devOnlyBool == kOSBooleanTrue) {
430 OSString *bundleID = OSDynamicCast(OSString,
431 infoDict->getObject(kCFBundleIdentifierKey));
432 if (bundleID) {
433 OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
434 "Kext %s not loading on non-dev device.", bundleID->getCStringNoCopy());
435 }
436
437 OSNumber *addressNum = OSDynamicCast(OSNumber,
438 infoDict->getObject(kPrelinkExecutableLoadKey));
439 OSNumber *lengthNum = OSDynamicCast(OSNumber,
440 infoDict->getObject(kPrelinkExecutableSizeKey));
441 if (addressNum && lengthNum) {
442#error Pick the right way to free prelinked data on this arch
443 }
444
445 infoDictArray->removeObject(i--);
446 continue;
447 }
448 }
449#endif /* NO_KEXTD */
450
b0d623f7
A
451 /* Create the kext for the entry, then release it, because the
452 * kext system keeps them around until explicitly removed.
453 * Any creation/registration failures are already logged for us.
454 */
455 OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict);
456 OSSafeReleaseNULL(newKext);
457 }
458
b0d623f7
A
459 /* Store the number of prelinked kexts in the registry so we can tell
460 * when the system has been started from a prelinked kernel.
461 */
462 registryRoot = IORegistryEntry::getRegistryRoot();
463 assert(registryRoot);
464
465 prelinkCountObj = OSNumber::withNumber(
466 (unsigned long long)infoDictArray->getCount(),
467 8 * sizeof(uint32_t));
468 assert(prelinkCountObj);
469 if (prelinkCountObj) {
470 registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj);
471 }
472
b0d623f7
A
473 OSKextLog(/* kext */ NULL,
474 kOSKextLogProgressLevel |
475 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
476 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
6d2010ae
A
477 "%u prelinked kexts",
478 infoDictArray->getCount());
b0d623f7 479
316670eb
A
480#if CONFIG_KEXT_BASEMENT
481 /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own
482 * special VM region during OSKext init time, so we can free the whole
483 * segment now.
b0d623f7
A
484 */
485 ml_static_mfree((vm_offset_t) prelinkData, prelinkLength);
316670eb 486#endif /* __x86_64__ */
b0d623f7 487
b0d623f7
A
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
496finish:
497 OSSafeRelease(errorString);
498 OSSafeRelease(parsedXML);
499 OSSafeRelease(theKernel);
500 OSSafeRelease(prelinkCountObj);
501 return;
1c79356b
A
502}
503
b0d623f7
A
504/*********************************************************************
505*********************************************************************/
506#define BOOTER_KEXT_PREFIX "Driver-"
507#define BOOTER_MKEXT_PREFIX "DriversPackage-"
508
509typedef struct _DeviceTreeBuffer {
510 uint32_t paddr;
511 uint32_t length;
512} _DeviceTreeBuffer;
513
514void
515KLDBootstrap::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
649finish:
650
651 OSSafeRelease(booterMemoryMap);
652 OSSafeRelease(propertyDict);
653 OSSafeRelease(keyIterator);
654 OSSafeRelease(booterData);
655 OSSafeRelease(aKext);
656 return;
657}
658
659/*********************************************************************
660*********************************************************************/
661OSReturn
662KLDBootstrap::readMkextExtensions(
663 OSString * deviceTreeName,
664 OSData * booterData)
665{
666 OSReturn result = kOSReturnError;
1c79356b 667
b0d623f7
A
668 uint32_t checksum;
669 IORegistryEntry * registryRoot = NULL; // do not release
670 OSData * checksumObj = NULL; // must release
1c79356b 671
b0d623f7
A
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
0b4e3aa0 681 */
b0d623f7
A
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
706void
707KLDBootstrap::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,
316670eb 752 theKext->getPropertyForHostArch(kAppleSecurityExtensionKey));
b0d623f7
A
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
763finish:
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*********************************************************************/
781OSReturn
782KLDBootstrap::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
316670eb
A
811/*********************************************************************
812* Ensure that Kernel External Components are loaded early in boot,
813* before other kext personalities get sent to the IOCatalogue. These
814* kexts are treated specially because they may provide the implementation
815* for kernel-vended KPI, so they must register themselves before
816* general purpose IOKit probing begins.
817*********************************************************************/
818
819#define COM_APPLE_KEC "com.apple.kec."
820
821void
822KLDBootstrap::loadKernelExternalComponents(void)
823{
824 OSDictionary * extensionsDict = NULL; // must release
825 OSCollectionIterator * keyIterator = NULL; // must release
826 OSString * bundleID = NULL; // don't release
827 OSKext * theKext = NULL; // don't release
828 OSBoolean * isKernelExternalComponent = NULL; // don't release
829
830 OSKextLog(/* kext */ NULL,
831 kOSKextLogStepLevel |
832 kOSKextLogLoadFlag,
833 "Loading Kernel External Components.");
834
835 extensionsDict = OSKext::copyKexts();
836 if (!extensionsDict) {
837 return;
838 }
839
840 keyIterator = OSCollectionIterator::withCollection(extensionsDict);
841 if (!keyIterator) {
842 OSKextLog(/* kext */ NULL,
843 kOSKextLogErrorLevel |
844 kOSKextLogGeneralFlag,
845 "Failed to allocate iterator for Kernel External Components.");
846 goto finish;
847 }
848
849 while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
850
851 const char * bundle_id = bundleID->getCStringNoCopy();
852
853 /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
854 */
855 if (!bundle_id ||
856 (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {
857
858 continue;
859 }
860
861 theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
862 if (!theKext) {
863 continue;
864 }
865
866 isKernelExternalComponent = OSDynamicCast(OSBoolean,
867 theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
868 if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
869 OSKextLog(/* kext */ NULL,
870 kOSKextLogStepLevel |
871 kOSKextLogLoadFlag,
872 "Loading kernel external component %s.", bundleID->getCStringNoCopy());
873 OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
874 /* allowDefer */ false);
875 }
876 }
877
878finish:
879 OSSafeRelease(keyIterator);
880 OSSafeRelease(extensionsDict);
881
882 return;
883}
884
b0d623f7
A
885/*********************************************************************
886 *********************************************************************/
887void
888KLDBootstrap::readBuiltinPersonalities(void)
889{
890 OSObject * parsedXML = NULL; // must release
891 OSArray * builtinExtensions = NULL; // do not release
892 OSArray * allPersonalities = NULL; // must release
893 OSString * errorString = NULL; // must release
894 kernel_section_t * infosect = NULL; // do not free
895 OSCollectionIterator * personalitiesIterator = NULL; // must release
896 unsigned int count, i;
897
898 OSKextLog(/* kext */ NULL,
899 kOSKextLogStepLevel |
900 kOSKextLogLoadFlag,
901 "Reading built-in kernel personalities for I/O Kit drivers.");
1c79356b 902
b0d623f7
A
903 /* Look in the __BUILTIN __info segment for an array of Info.plist
904 * entries. For each one, extract the personalities dictionary, add
905 * it to our array, then push them all (without matching) to
906 * the IOCatalogue. This can be used to augment the personalities
907 * in gIOKernelConfigTables, especially when linking entire kexts into
908 * the mach_kernel image.
0b4e3aa0 909 */
b0d623f7
A
910 infosect = getsectbyname("__BUILTIN", "__info");
911 if (!infosect) {
912 // this isn't fatal
913 goto finish;
914 }
915
916 parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr,
917 &errorString);
918 if (parsedXML) {
919 builtinExtensions = OSDynamicCast(OSArray, parsedXML);
920 }
921 if (!builtinExtensions) {
922 const char * errorCString = "(unknown error)";
923
924 if (errorString && errorString->getCStringNoCopy()) {
925 errorCString = errorString->getCStringNoCopy();
926 } else if (parsedXML) {
927 errorCString = "not an array";
928 }
929 OSKextLog(/* kext */ NULL,
930 kOSKextLogErrorLevel |
931 kOSKextLogLoadFlag,
932 "Error unserializing built-in personalities: %s.", errorCString);
933 goto finish;
934 }
935
936 // estimate 3 personalities per Info.plist/kext
937 count = builtinExtensions->getCount();
938 allPersonalities = OSArray::withCapacity(count * 3);
939
940 for (i = 0; i < count; i++) {
941 OSDictionary * infoDict = NULL; // do not release
942 OSString * moduleName = NULL; // do not release
943 OSDictionary * personalities; // do not release
944 OSString * personalityName; // do not release
945
946 OSSafeReleaseNULL(personalitiesIterator);
947
948 infoDict = OSDynamicCast(OSDictionary,
949 builtinExtensions->getObject(i));
950 if (!infoDict) {
951 continue;
952 }
953
954 moduleName = OSDynamicCast(OSString,
955 infoDict->getObject(kCFBundleIdentifierKey));
956 if (!moduleName) {
957 continue;
958 }
959
960 OSKextLog(/* kext */ NULL,
961 kOSKextLogStepLevel |
962 kOSKextLogLoadFlag,
963 "Adding personalities for built-in driver %s:",
964 moduleName->getCStringNoCopy());
965
966 personalities = OSDynamicCast(OSDictionary,
967 infoDict->getObject("IOKitPersonalities"));
968 if (!personalities) {
969 continue;
970 }
971
972 personalitiesIterator = OSCollectionIterator::withCollection(personalities);
973 if (!personalitiesIterator) {
974 continue; // xxx - well really, what can we do? should we panic?
975 }
976
977 while ((personalityName = OSDynamicCast(OSString,
978 personalitiesIterator->getNextObject()))) {
979
980 OSDictionary * personality = OSDynamicCast(OSDictionary,
981 personalities->getObject(personalityName));
982
983 OSKextLog(/* kext */ NULL,
984 kOSKextLogDetailLevel |
985 kOSKextLogLoadFlag,
986 "Adding built-in driver personality %s.",
987 personalityName->getCStringNoCopy());
988
989 if (personality && !personality->getObject(kCFBundleIdentifierKey)) {
990 personality->setObject(kCFBundleIdentifierKey, moduleName);
991 }
992 allPersonalities->setObject(personality);
993 }
994 }
995
996 gIOCatalogue->addDrivers(allPersonalities, false);
997
998finish:
999 OSSafeRelease(parsedXML);
1000 OSSafeRelease(allPersonalities);
1001 OSSafeRelease(errorString);
1002 OSSafeRelease(personalitiesIterator);
1003 return;
1004}
1005
1006#if PRAGMA_MARK
1007#pragma mark Bootstrap Functions
1008#endif
1009/*********************************************************************
1010* Bootstrap Functions
1011*********************************************************************/
1012static void bootstrapRecordStartupExtensions(void)
1013{
1014 sBootstrapObject.readStartupExtensions();
1015 return;
1016}
1017
1018static void bootstrapLoadSecurityExtensions(void)
1019{
1020 sBootstrapObject.loadSecurityExtensions();
1021 return;
1c79356b 1022}
6d2010ae 1023