X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552..04b8595b18b1b41ac7a206e4b3d51a635f8413d7:/iokit/bsddev/IOKitBSDInit.cpp?ds=inline diff --git a/iokit/bsddev/IOKitBSDInit.cpp b/iokit/bsddev/IOKitBSDInit.cpp index c125eaeae..9b08bb834 100644 --- a/iokit/bsddev/IOKitBSDInit.cpp +++ b/iokit/bsddev/IOKitBSDInit.cpp @@ -1,52 +1,128 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2011 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include #include #include +#include #include #include #include -#include - extern "C" { #include #include +#include +#include // how long to wait for matching root device, secs -#define ROOTDEVICETIMEOUT 60 +#if DEBUG +#define ROOTDEVICETIMEOUT 120 +#else +#define ROOTDEVICETIMEOUT 60 +#endif +extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys); +extern dev_t mdevlookup(int devid); +extern void mdevremoveall(void); +extern void di_root_ramfile(IORegistryEntry * entry); kern_return_t IOKitBSDInit( void ) { - IOLog("IOKitBSDInit\n"); - IOService::publishResource("IOBSD"); - + return( kIOReturnSuccess ); } +void +IOServicePublishResource( const char * property, boolean_t value ) +{ + if ( value) + IOService::publishResource( property, kOSBooleanTrue ); + else + IOService::getResourceService()->removeProperty( property ); +} + +boolean_t +IOServiceWaitForMatchingResource( const char * property, uint64_t timeout ) +{ + OSDictionary * dict = 0; + IOService * match = 0; + boolean_t found = false; + + do { + + dict = IOService::resourceMatching( property ); + if( !dict) + continue; + match = IOService::waitForMatchingService( dict, timeout ); + if ( match) + found = true; + + } while( false ); + + if( dict) + dict->release(); + if( match) + match->release(); + + return( found ); +} + +boolean_t +IOCatalogueMatchingDriversPresent( const char * property ) +{ + OSDictionary * dict = 0; + OSOrderedSet * set = 0; + SInt32 generationCount = 0; + boolean_t found = false; + + do { + + dict = OSDictionary::withCapacity(1); + if( !dict) + continue; + dict->setObject( property, kOSBooleanTrue ); + set = gIOCatalogue->findDrivers( dict, &generationCount ); + if ( set && (set->getCount() > 0)) + found = true; + + } while( false ); + + if( dict) + dict->release(); + if( set) + set->release(); + + return( found ); +} + OSDictionary * IOBSDNameMatching( const char * name ) { OSDictionary * dict; @@ -75,81 +151,9 @@ OSDictionary * IOBSDNameMatching( const char * name ) return( 0 ); } -OSDictionary * IOCDMatching( const char * name ) +OSDictionary * IOUUIDMatching( void ) { - OSDictionary * dict; - const OSSymbol * str; - - dict = IOService::serviceMatching( "IOMedia" ); - if( dict == 0 ) { - IOLog("Unable to find IOMedia\n"); - return 0; - } - - str = OSSymbol::withCString( "CD_ROM_Mode_1" ); - if( str == 0 ) { - dict->release(); - return 0; - } - - dict->setObject( "Content", (OSObject *)str ); - str->release(); - return( dict ); -} - -OSDictionary * IONetworkMatching( const char * path, - char * buf, int maxLen ) -{ - OSDictionary * matching = 0; - OSDictionary * dict; - OSString * str; - char * comp; - const char * skip; - int len; - - do { - - len = strlen( kIODeviceTreePlane ":" ); - maxLen -= len; - if( maxLen < 0) - continue; - - strcpy( buf, kIODeviceTreePlane ":" ); - comp = buf + len; - - // remove parameters following ':' from the path - skip = strchr( path, ':'); - if( !skip) - continue; - - len = skip - path; - maxLen -= len; - if( maxLen < 0) - continue; - strncpy( comp, path, len ); - comp[ len ] = 0; - - matching = IOService::serviceMatching( "IONetworkInterface" ); - if( !matching) - continue; - dict = IOService::addLocation( matching ); - if( !dict) - continue; - - str = OSString::withCString( buf ); - if( !str) - continue; - dict->setObject( kIOPathMatchKey, str ); - str->release(); - - return( matching ); - - } while( false ); - - if( matching) - matching->release(); - - return( 0 ); + return IOService::resourceMatching( "boot-uuid-media" ); } OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) @@ -157,7 +161,8 @@ OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) OSDictionary * matching; OSDictionary * propDict = 0; const OSSymbol * str = 0; - + char networkType[128]; + do { matching = IOService::serviceMatching( "IONetworkInterface" ); if ( matching == 0 ) @@ -175,6 +180,18 @@ OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) str->release(); str = 0; + // see if we're contrained to netroot off of specific network type + if(PE_parse_boot_argn( "network-type", networkType, 128 )) + { + str = OSSymbol::withCString( networkType ); + if(str) + { + propDict->setObject( "IONetworkRootType", str); + str->release(); + str = 0; + } + } + if ( matching->setObject( gIOPropertyMatchKey, (OSObject *) propDict ) != true ) continue; @@ -246,85 +263,53 @@ static bool IORegisterNetworkInterface( IOService * netif ) return ( netif->getProperty( kIOBSDNameKey ) != 0 ); } -OSDictionary * IODiskMatching( const char * path, char * buf, int maxLen ) +OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) { - const char * look; - const char * alias; - char * comp; - long unit = -1; - long partition = -1; - char c; - - // scan the tail of the path for "@unit:partition" - do { - // Have to get the full path to the controller - an alias may - // tell us next to nothing, like "hd:8" - alias = IORegistryEntry::dealiasPath( &path, gIODTPlane ); - - look = path + strlen( path); - c = ':'; - while( look != path) { - if( *(--look) == c) { - if( c == ':') { - partition = strtol( look + 1, 0, 0 ); - c = '@'; - } else if( c == '@') { - unit = strtol( look + 1, 0, 16 ); - c = '/'; - } else if( c == '/') { - c = 0; - break; - } - } + OSDictionary * matching = NULL; + OSString * str; + char * comp; + int len; - if( alias && (look == path)) { - path = alias; - look = path + strlen( path); - alias = 0; - } - } - if( c || unit == -1 || partition == -1) - continue; + do { - maxLen -= strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" ); - maxLen -= ( alias ? strlen( alias ) : 0 ) + (look - path); - maxLen -= strlen( "/@hhhhhhhh:dddddddddd';}" ); + len = strlen( kIODeviceTreePlane ":" ); + maxLen -= len; + if( maxLen <= 0) + continue; - if( maxLen > 0) { - sprintf( buf, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" ); - comp = buf + strlen( buf ); + strlcpy( buf, kIODeviceTreePlane ":", len + 1 ); + comp = buf + len; - if( alias) { - strcpy( comp, alias ); - comp += strlen( alias ); - } + len = strlen( path ); + maxLen -= len; + if( maxLen <= 0) + continue; + strlcpy( comp, path, len + 1 ); - if ( (look - path)) { - strncpy( comp, path, look - path); - comp += look - path; - } + matching = OSDictionary::withCapacity( 1 ); + if( !matching) + continue; - sprintf( comp, "/@%lx:%ld';}", unit, partition ); - } else - continue; + str = OSString::withCString( buf ); + if( !str) + continue; + matching->setObject( kIOPathMatchKey, str ); + str->release(); - return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) ); + return( matching ); } while( false ); + if( matching) + matching->release(); + return( 0 ); } -OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) -{ - /* need to look up path, get device type, - call matching help based on device type */ - - return( IODiskMatching( path, buf, maxLen )); - -} +static int didRam = 0; +enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; -kern_return_t IOFindBSDRoot( char * rootName, +kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize, dev_t * root, u_int32_t * oflags ) { mach_timespec_t t; @@ -336,16 +321,19 @@ kern_return_t IOFindBSDRoot( char * rootName, OSData * data = 0; UInt32 flags = 0; - int minor, major; + int mnr, mjr; + const char * mediaProperty = 0; char * rdBootVar; - enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; char * str; const char * look = 0; int len; - bool forceNet = false; bool debugInfoPrintedOnce = false; + const char * uuidStr = NULL; static int mountAttempts = 0; + + int xchar, dchar; + if( mountAttempts++) IOSleep( 5 * 1000 ); @@ -355,50 +343,93 @@ kern_return_t IOFindBSDRoot( char * rootName, return( kIOReturnNoMemory ); rdBootVar = str + kMaxPathBuf; - if (!PE_parse_boot_arg("rd", rdBootVar ) - && !PE_parse_boot_arg("rootdev", rdBootVar )) + if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) + && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) rdBootVar[0] = 0; do { - if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { - data = (OSData *) regEntry->getProperty( "rootpath" ); - regEntry->release(); - if( data) - continue; - } - if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) { - data = (OSData *) regEntry->getProperty( "boot-file" ); + if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { + di_root_ramfile(regEntry); + data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" )); + if (data) { + matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy())); + if (matching) { + continue; + } + } + + data = (OSData *) regEntry->getProperty( "boot-uuid" ); + if( data) { + uuidStr = (const char*)data->getBytesNoCopy(); + OSString *uuidString = OSString::withCString( uuidStr ); + + // match the boot-args boot-uuid processing below + if( uuidString) { + IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr); + IOService::publishResource( "boot-uuid", uuidString ); + uuidString->release(); + matching = IOUUIDMatching(); + mediaProperty = "boot-uuid-media"; + regEntry->release(); + continue; + } else { + uuidStr = NULL; + } + } regEntry->release(); - if( data) - continue; } } while( false ); - if( data) - look = (const char *) data->getBytesNoCopy(); - - if( rdBootVar[0] == '*') { - look = rdBootVar + 1; - forceNet = false; - } else { - if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) { - forceNet = (0 != regEntry->getProperty( "net-boot" )); - regEntry->release(); +// +// See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device. +// It will become /dev/mdx, where x is 0-f. +// + + if(!didRam) { /* Have we already build this ram disk? */ + didRam = 1; /* Remember we did this */ + if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */ + data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */ + if(data) { /* We found one */ + uintptr_t *ramdParms; + ramdParms = (uintptr_t *)data->getBytesNoCopy(); /* Point to the ram disk base and size */ + (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */ + } + regEntry->release(); /* Toss the entry */ + } + } + +// +// Now check if we are trying to root on a memory device +// + + if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { + dchar = xchar = rdBootVar[2]; /* Get the actual device */ + if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */ + else { + xchar = xchar & ~' '; /* Fold to upper case */ + if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */ + xchar = (xchar & 0xF) + 9; /* Convert the hex digit */ + dchar = dchar | ' '; /* Fold to lower case */ + } + else xchar = -1; /* Show bogus */ + } + if(xchar >= 0) { /* Do we have a valid memory device name? */ + *root = mdevlookup(xchar); /* Find the device number */ + if(*root >= 0) { /* Did we find one? */ + + rootName[0] = 'm'; /* Build root name */ + rootName[1] = 'd'; /* Build root name */ + rootName[2] = dchar; /* Build root name */ + rootName[3] = 0; /* Build root name */ + IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root)); + *oflags = 0; /* Show that this is not network */ + goto iofrootx; /* Join common exit... */ + } + panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */ + } } - } - - if( look) { - // from OpenFirmware path - IOLog("From path: \"%s\", ", look); - - if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) ) { - matching = IONetworkMatching( look, str, kMaxPathBuf ); - } else { - matching = IODiskMatching( look, str, kMaxPathBuf ); - } - } - if( (!matching) && rdBootVar[0] ) { + if( (!matching) && rdBootVar[0] ) { // by BSD name look = rdBootVar; if( look[0] == '*') @@ -406,24 +437,48 @@ kern_return_t IOFindBSDRoot( char * rootName, if ( strncmp( look, "en", strlen( "en" )) == 0 ) { matching = IONetworkNamePrefixMatching( "en" ); - } else if ( strncmp( look, "cdrom", strlen( "cdrom" )) == 0 ) { - matching = IOCDMatching( look ); + } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) { + char *uuid; + OSString *uuidString; + + uuid = (char *)IOMalloc( kMaxBootVar ); + + if ( uuid ) { + if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) { + panic( "rd=uuid but no boot-uuid= specified" ); + } + uuidString = OSString::withCString( uuid ); + if ( uuidString ) { + IOService::publishResource( "boot-uuid", uuidString ); + uuidString->release(); + IOLog( "\nWaiting for boot volume with UUID %s\n", uuid ); + matching = IOUUIDMatching(); + mediaProperty = "boot-uuid-media"; + } + IOFree( uuid, kMaxBootVar ); + } } else { matching = IOBSDNameMatching( look ); } } if( !matching) { - OSString * astring; - // any UFS + OSString * astring; + // Match any HFS media + matching = IOService::serviceMatching( "IOMedia" ); - astring = OSString::withCStringNoCopy("Apple_UFS"); + astring = OSString::withCStringNoCopy("Apple_HFS"); if ( astring ) { matching->setObject("Content", astring); astring->release(); } } + if( gIOKitDebug & kIOWaitQuietBeforeRoot ) { + IOLog( "Waiting for matching to complete\n" ); + IOService::getPlatform()->waitQuiet(); + } + if( true && matching) { OSSerialize * s = OSSerialize::withCapacity( 5 ); @@ -459,8 +514,12 @@ kern_return_t IOFindBSDRoot( char * rootName, } while( !service); matching->release(); - major = 0; - minor = 0; + if ( service && mediaProperty ) { + service = (IOService *)service->getProperty(mediaProperty); + } + + mjr = 0; + mnr = 0; // If the IOService we matched to is a subclass of IONetworkInterface, // then make sure it has been registered with BSD and has a BSD name @@ -481,13 +540,13 @@ kern_return_t IOFindBSDRoot( char * rootName, iostr = (OSString *) service->getProperty( kIOBSDNameKey ); if( iostr) - strcpy( rootName, iostr->getCStringNoCopy() ); + strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize ); off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); if( off) - major = off->unsigned32BitValue(); + mjr = off->unsigned32BitValue(); off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); if( off) - minor = off->unsigned32BitValue(); + mnr = off->unsigned32BitValue(); if( service->metaCast( "IONetworkInterface" )) flags |= 1; @@ -495,21 +554,22 @@ kern_return_t IOFindBSDRoot( char * rootName, } else { IOLog( "Wait for root failed\n" ); - strcpy( rootName, "en0"); + strlcpy( rootName, "en0", rootNameSize ); flags |= 1; } IOLog( "BSD root: %s", rootName ); - if( major) - IOLog(", major %d, minor %d\n", major, minor ); + if( mjr) + IOLog(", major %d, minor %d\n", mjr, mnr ); else IOLog("\n"); - *root = makedev( major, minor ); + *root = makedev( mjr, mnr ); *oflags = flags; IOFree( str, kMaxPathBuf + kMaxBootVar ); +iofrootx: if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) { IOService::getPlatform()->waitQuiet(); @@ -528,6 +588,22 @@ kern_return_t IOFindBSDRoot( char * rootName, return( kIOReturnSuccess ); } +bool IORamDiskBSDRoot(void) +{ + char rdBootVar[kMaxBootVar]; + if (PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) + || PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) { + if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { + return true; + } + } + return false; +} + +void IOSecureBSDRoot(const char * rootName) +{ +} + void * IOBSDRegistryEntryForDeviceTree(char * path) { @@ -559,4 +635,131 @@ IOBSDRegistryEntryGetData(void * entry, char * property_name, return (NULL); } +kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout ) +{ + IOService * resources; + OSString * string; + + resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 ); + if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT; + + string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey ); + if ( string == 0 ) return KERN_NOT_SUPPORTED; + + uuid_parse( string->getCStringNoCopy( ), uuid ); + + return KERN_SUCCESS; +} + +kern_return_t IOBSDGetPlatformSerialNumber( char *serial_number_str, u_int32_t len ) +{ + OSDictionary * platform_dict; + IOService *platform; + OSString * string; + + if (len < 1) { + return 0; + } + serial_number_str[0] = '\0'; + + platform_dict = IOService::serviceMatching( "IOPlatformExpertDevice" ); + if (platform_dict == NULL) { + return KERN_NOT_SUPPORTED; + } + + platform = IOService::waitForService( platform_dict ); + if (platform) { + string = ( OSString * ) platform->getProperty( kIOPlatformSerialNumberKey ); + if ( string == 0 ) { + return KERN_NOT_SUPPORTED; + } else { + strlcpy( serial_number_str, string->getCStringNoCopy( ), len ); + } + } + + return KERN_SUCCESS; +} + +void IOBSDIterateMediaWithContent(const char *content_uuid_cstring, int (*func)(const char *bsd_dev_name, const char *uuid_str, void *arg), void *arg) +{ + OSDictionary *dictionary; + OSString *content_uuid_string; + + dictionary = IOService::serviceMatching( "IOMedia" ); + if( dictionary ) { + content_uuid_string = OSString::withCString( content_uuid_cstring ); + if( content_uuid_string ) { + IOService *service; + OSIterator *iter; + + dictionary->setObject( "Content", content_uuid_string ); + dictionary->retain(); + + iter = IOService::getMatchingServices(dictionary); + while (iter && (service = (IOService *)iter->getNextObject())) { + if( service ) { + OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); + OSString *uuidstr = (OSString *) service->getProperty( "UUID" ); + const char *uuid; + + if( iostr) { + if (uuidstr) { + uuid = uuidstr->getCStringNoCopy(); + } else { + uuid = "00000000-0000-0000-0000-000000000000"; + } + + // call the callback + if (func && func(iostr->getCStringNoCopy(), uuid, arg) == 0) { + break; + } + } + } + } + if (iter) + iter->release(); + + content_uuid_string->release(); + } + dictionary->release(); + } +} + + +int IOBSDIsMediaEjectable( const char *cdev_name ) +{ + int ret = 0; + OSDictionary *dictionary; + OSString *dev_name; + + if (strncmp(cdev_name, "/dev/", 5) == 0) { + cdev_name += 5; + } + + dictionary = IOService::serviceMatching( "IOMedia" ); + if( dictionary ) { + dev_name = OSString::withCString( cdev_name ); + if( dev_name ) { + IOService *service; + mach_timespec_t tv = { 5, 0 }; // wait up to "timeout" seconds for the device + + dictionary->setObject( kIOBSDNameKey, dev_name ); + dictionary->retain(); + service = IOService::waitForService( dictionary, &tv ); + if( service ) { + OSBoolean *ejectable = (OSBoolean *) service->getProperty( "Ejectable" ); + + if( ejectable ) { + ret = (int)ejectable->getValue(); + } + + } + dev_name->release(); + } + dictionary->release(); + } + + return ret; +} + } /* extern "C" */