1/* 2 * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * BLCreateEFIXMLRepresentationForLegacyDevice.c 25 * bless 26 * 27 * Created by Shantonu Sen on 1/24/06. 28 * Copyright 2006-2007 Apple Inc. All Rights Reserved. 29 * 30 */ 31 32#include <CoreFoundation/CoreFoundation.h> 33 34#include <string.h> 35#include <sys/param.h> 36#include <sys/stat.h> 37 38#include "bless.h" 39#include "bless_private.h" 40 41#if SUPPORT_CSM_LEGACY_BOOT 42 43#include <IOKit/IOKitLib.h> 44#include <IOKit/IOCFSerialize.h> 45#include <IOKit/IOBSD.h> 46#include <IOKit/IOKitKeys.h> 47#include <IOKit/storage/IOMedia.h> 48#include <IOKit/usb/IOUSBLib.h> 49#include <IOKit/storage/IOStorageProtocolCharacteristics.h> 50#include <IOKit/storage/IOCDBlockStorageDevice.h> 51 52typedef enum { 53 EfiMemoryMappedIO = 11 54} EFI_MEMORY_TYPE; 55 56#define kDefaultFVAddress (0xffe00000ULL) 57#define kDefaultFVSize (0x1a0000ULL) 58 59 60static int addLegacyTypeForBSDName(BLContextPtr context, 61 mach_port_t masterPort, 62 CFMutableDictionaryRef dict, 63 const char *bsdName); 64 65int BLCreateEFIXMLRepresentationForLegacyDevice(BLContextPtr context, 66 const char *bsdName, 67 CFStringRef *xmlString) 68{ 69 mach_port_t masterPort; 70 kern_return_t kret; 71 int ret; 72 73 CFDataRef xmlData; 74 CFMutableDictionaryRef dict; 75 CFMutableArrayRef array; 76 CFNumberRef number; 77 uint64_t num64; 78 uint32_t num32; 79 uint64_t fvaddr, fvsize, fvaddrend; 80 io_registry_entry_t romNode; 81 82 const UInt8 *xmlBuffer; 83 UInt8 *outBuffer; 84 CFIndex count; 85 86 if(!BLSupportsLegacyMode(context)) { 87 contextprintf(context, kBLLogLevelError, "Legacy mode not supported on this system\n"); 88 return 1; 89 } 90 91 kret = IOMasterPort(MACH_PORT_NULL, &masterPort); 92 if(kret) return 1; 93 94 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 95 96 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 97 &kCFTypeDictionaryKeyCallBacks, 98 &kCFTypeDictionaryValueCallBacks); 99 100 CFDictionaryAddValue(dict, CFSTR("IOEFIDevicePathType"), 101 CFSTR("HardwareMemoryMapped")); 102 103 num64 = EfiMemoryMappedIO; 104 number = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt64Type, &num64); 105 CFDictionaryAddValue(dict, CFSTR("MemoryType"), 106 number); 107 CFRelease(number); 108 109 fvaddr = kDefaultFVAddress; 110 fvsize = kDefaultFVSize; 111 112 romNode = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/rom"); 113 114 if(IO_OBJECT_NULL != romNode) { 115 contextprintf(context, kBLLogLevelVerbose, "Got " kIODeviceTreePlane ":/rom\n"); 116 117 number = IORegistryEntryCreateCFProperty(romNode, 118 CFSTR("fv-main-address"), 119 kCFAllocatorDefault, 0); 120 if(number != NULL 121 && CFGetTypeID(number) == CFNumberGetTypeID()) { 122 123 if(CFNumberGetValue(number, kCFNumberSInt32Type, &num32)) { 124 fvaddr = num32; 125 contextprintf(context, kBLLogLevelVerbose, "Got start address %llx\n", fvaddr); 126 } 127 } 128 if(number) CFRelease(number); 129 130 number = IORegistryEntryCreateCFProperty(romNode, 131 CFSTR("fv-main-size"), 132 kCFAllocatorDefault, 0); 133 if(number != NULL 134 && CFGetTypeID(number) == CFNumberGetTypeID()) { 135 136 if(CFNumberGetValue(number, kCFNumberSInt32Type, &num32)) { 137 fvsize = num32; 138 contextprintf(context, kBLLogLevelVerbose, "Got size %llx\n", fvsize); 139 } 140 } 141 if(number) CFRelease(number); 142 143 IOObjectRelease(romNode); 144 } 145 146 147 fvaddrend = fvaddr + fvsize - 1; 148 149 150 number = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt64Type, &fvaddr); 151 CFDictionaryAddValue(dict, CFSTR("StartingAddress"), 152 number); 153 CFRelease(number); 154 155 number = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt64Type, &fvaddrend); 156 CFDictionaryAddValue(dict, CFSTR("EndingAddress"), 157 number); 158 CFRelease(number); 159 160 CFArrayAppendValue(array, dict); 161 CFRelease(dict); 162 163 164 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 165 &kCFTypeDictionaryKeyCallBacks, 166 &kCFTypeDictionaryValueCallBacks); 167 168 CFDictionaryAddValue(dict, CFSTR("IOEFIDevicePathType"), 169 CFSTR("MediaFirmwareVolumeFilePath")); 170 CFDictionaryAddValue(dict, CFSTR("Guid"), 171 CFSTR("2B0585EB-D8B8-49A9-8B8C-E21B01AEF2B7")); 172 173 CFArrayAppendValue(array, dict); 174 CFRelease(dict); 175 176 177 178 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 179 &kCFTypeDictionaryKeyCallBacks, 180 &kCFTypeDictionaryValueCallBacks); 181 ret = addLegacyTypeForBSDName(context, 182 masterPort, 183 dict, 184 bsdName); 185 if(ret) { 186 CFRelease(dict); 187 CFRelease(array); 188 contextprintf(context, kBLLogLevelError, "Can't determine legacy media type for %s\n", bsdName); 189 return 2; 190 } 191 192 CFArrayAppendValue(array, dict); 193 CFRelease(dict); 194 195 xmlData = IOCFSerialize(array, 0); 196 CFRelease(array); 197 198 if(xmlData == NULL) { 199 contextprintf(context, kBLLogLevelError, "Can't create XML representation\n"); 200 return 2; 201 } 202 203 count = CFDataGetLength(xmlData); 204 xmlBuffer = CFDataGetBytePtr(xmlData); 205 outBuffer = calloc(count+1, sizeof(char)); // terminate 206 207 memcpy(outBuffer, xmlBuffer, count); 208 CFRelease(xmlData); 209 210 *xmlString = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)outBuffer, kCFStringEncodingUTF8); 211 212 free(outBuffer); 213 214 return 0; 215} 216 217static int addLegacyTypeForBSDName(BLContextPtr context, 218 mach_port_t masterPort, 219 CFMutableDictionaryRef dict, 220 const char *bsdName) 221{ 222 io_service_t service = IO_OBJECT_NULL, media; 223 io_iterator_t iter; 224 kern_return_t kret; 225 int spaces = 0; 226 bool foundUSB = false; 227 bool foundCD = false; 228 CFStringRef type; 229 CFDictionaryRef protocolCharacteristics; 230 231 media = IOServiceGetMatchingService(masterPort, 232 IOBSDNameMatching(masterPort, 0, bsdName)); 233 234 if(media == IO_OBJECT_NULL) { 235 contextprintf(context, kBLLogLevelError, "Could not find object for %s\n", bsdName); 236 return 1; 237 } 238 239 240 protocolCharacteristics = IORegistryEntrySearchCFProperty(media, 241 kIOServicePlane, 242 CFSTR(kIOPropertyProtocolCharacteristicsKey), 243 kCFAllocatorDefault, 244 kIORegistryIterateRecursively| 245 kIORegistryIterateParents); 246 247 if(protocolCharacteristics && CFGetTypeID(protocolCharacteristics) == CFDictionaryGetTypeID()) { 248 CFStringRef interconnect = CFDictionaryGetValue(protocolCharacteristics, 249 CFSTR(kIOPropertyPhysicalInterconnectTypeKey)); 250 if(interconnect && CFGetTypeID(interconnect) == CFStringGetTypeID()) { 251 contextprintf(context, kBLLogLevelVerbose, 252 "Found %s interconnect in protocol characteristics\n", 253 BLGetCStringDescription(interconnect)); 254 255 if(CFEqual(interconnect, CFSTR(kIOPropertyPhysicalInterconnectTypeUSB))) { 256 foundUSB = true; 257 } 258 //otherwise assume it's an CD- or HD-class device 259 } 260 261 } 262 263 if(protocolCharacteristics) CFRelease(protocolCharacteristics); 264 265 266 if(!foundUSB) { 267 // try to use the registry topology to see if it's a USB device 268 269 kret = IORegistryEntryCreateIterator (media, kIOServicePlane, 270 kIORegistryIterateRecursively|kIORegistryIterateParents, 271 &iter); 272 273 if(kret) { 274 contextprintf(context, kBLLogLevelError, "Could not get parent iterator for %s\n", bsdName); 275 IOObjectRelease(media); 276 return 2; 277 } 278 279 IOObjectRelease(media); 280 281 while ( (service = IOIteratorNext(iter)) != IO_OBJECT_NULL ) { 282 io_name_t name; 283 284 kret = IORegistryEntryGetNameInPlane(service, kIOServicePlane, name); 285 if(kret) strlcpy(name, "unknown", sizeof name); 286 contextprintf(context, kBLLogLevelVerbose, "%*s%s\n", spaces, "", name); 287 288 if(IOObjectConformsTo(service, kIOUSBInterfaceClassName)) { 289 contextprintf(context, kBLLogLevelVerbose, 290 "Found %s in parent hierarchy\n", kIOUSBInterfaceClassName); 291 foundUSB = true; 292 IOObjectRelease(service); 293 break; 294 } 295 296 if(IOObjectConformsTo(service, kIOCDBlockStorageDeviceClass)) { 297 contextprintf(context, kBLLogLevelVerbose, 298 "Found %s in parent hierarchy\n", kIOCDBlockStorageDeviceClass); 299 foundCD = true; 300 IOObjectRelease(service); 301 break; 302 } 303 304 spaces++; 305 IOObjectRelease(service); 306 } 307 IOObjectRelease(iter); 308 } 309 310 if(foundUSB) { 311 type = CFSTR("USB"); 312 } else if(foundCD) { 313 type = CFSTR("CD"); 314 } else { 315 type = CFSTR("HD"); 316 } 317 318 CFDictionaryAddValue(dict, CFSTR("IOEFIBootOption"), 319 type); 320 321 return 0; 322} 323 324#else /* !SUPPORT_CSM_LEGACY_BOOT */ 325 326int BLCreateEFIXMLRepresentationForLegacyDevice(BLContextPtr context, 327 const char *bsdName, 328 CFStringRef *xmlString) 329{ 330 return 1; 331} 332 333#endif /* !SUPPORT_CSM_LEGACY_BOOT */ 334