The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libsa/bootstrap.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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         OSKext::setPrelinkedPersonalities(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 }

Cache object: bb5b51c4b467e860ea6e45004e11970b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.