BLElToritoFindUEFI.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/paths.h>
#include <errno.h>
#include <ctype.h>
#include <mach/mach.h>
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_init.h>
#include <CoreFoundation/CoreFoundation.h>
#include <syslog.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFSerialize.h>
#include <IOKit/storage/IODVDMedia.h>
#include "bless.h"
#include "bless_private.h"
typedef struct
{
UInt8 volume_descriptor_type; char ident[5]; UInt8 volume_descriptor_version;
UInt8 unused1;
char system_id [32];
char volume_id [32];
UInt8 unused2 [8];
UInt32 volume_space_size_LE; UInt32 volume_space_size_BE;
UInt8 other [1960];
} __attribute__((packed)) ISO9660_PRIMARY_VOLUME_DESCRIPTOR;
typedef struct
{
UInt8 type;
char ident [5];
UInt8 version;
char system_id [32];
char unused1 [32];
UInt32 bootcat_ptr;
} __attribute__((packed)) EL_TORITO_BOOT_VOLUME_DESCRIPTOR;
typedef struct {
UInt8 id; UInt8 arch; unsigned : 16; char creator_id [24]; UInt16 checksum; UInt8 key55; UInt8 keyAA; } __attribute__((packed)) EL_TORITO_VALIDATION_ENTRY;
typedef struct {
UInt8 boot_indicator; UInt8 boot_media; UInt16 load_segment; UInt8 system_type; UInt8 : 8; UInt16 blockcount; UInt32 lba; UInt8 : 8; } __attribute__((packed)) EL_TORITO_INITIAL_DEFAULT_ENTRY;
typedef struct
{
UInt8 header_indicator; UInt8 platform_id; UInt16 sections_count; char section_id [28]; } __attribute__((packed)) EL_TORITO_SECTION_HEADER_ENTRY;
typedef struct
{
UInt8 boot_indicator; UInt8 boot_media; UInt16 load_segment; UInt8 system_type; UInt8 unused1; UInt16 sector_count; UInt32 load_rba; UInt8 selection_criteria_type; UInt8 selection_criteria [19]; } __attribute__((packed)) EL_TORITO_SECTION_SECTION_ENTRY;
typedef struct
{
UInt8 extension_indicator; UInt8 bits; UInt8 other[30]; } __attribute__((packed)) EL_TORITO_SECTION_EXTENSION_ENTRY;
static void contextprintfhexdump16bytes (BLContextPtr inContext, int inLogLevel, char* inHeaderStr, uint8_t* inBytes)
{
int i;
contextprintf (inContext, inLogLevel, "%s", inHeaderStr);
for (i = 0; i <= 15; i++) {
contextprintf (inContext, inLogLevel, "%02x ", inBytes[i]);
}
contextprintf (inContext, inLogLevel, "| ");
for (i = 0; i <= 15; i++) {
contextprintf (inContext, inLogLevel, "%c", inBytes[i]);
}
contextprintf (inContext, inLogLevel, "\n");
}
static void findMSDOSRegion (BLContextPtr inContext, const char* inBSDName, bool* outFoundIt, uint32_t* outOffsetBlocks, uint32_t* outSizeBlocks)
{
bool foundIt = false;
int fd = -1;
char devPath [256];
uint8_t buf2048 [2500];
int sectionEntryIteratorForCurrentHeader = 0;
#define TESTMODE 0
#if TESTMODE
char tbuf [2500];
contextprintf (inContext, kBLLogLevelVerbose, "******** TESTING, WRITING TO STAGING AREA THEN READING AS IF IT WERE A PRETEND DISC.. *******\n");
sprintf (devPath, "/tmp/testFindMSDOSRegion");
fd = open (devPath, O_RDWR | O_CREAT);
if (-1 == fd)
{
contextprintf (inContext, kBLLogLevelVerbose, "unable to open, errno=%d\n", errno);
goto Exit;
}
contextprintf (inContext, kBLLogLevelVerbose, "opened pretend DVD for read/write\n");
bzero (tbuf, 2048);
tbuf[0] = 0x01;
strcpy (&(tbuf[1]), "CD001");
tbuf[80]=0x33; tbuf[81]=0x22; tbuf[82]=0x11; tbuf[83]=0x00;
pwrite (fd, tbuf, 2048, 2048*16);
bzero (tbuf, 2048);
tbuf[0] = 0x00;
strcpy (&(tbuf[1]), "CD001");
tbuf[71]=0x20; tbuf[72]=0x00; tbuf[73]=0x00; tbuf[74]=0x00; pwrite (fd, tbuf, 2048, 2048*17);
bzero (tbuf, 2048);
int en=0;
tbuf[en+0] = 0x01;
tbuf[en+0x1e]=0x55; tbuf[en+0x1f]=0xaa;
en += 32;
tbuf[en+0] = 0x88;
tbuf[en+0x08]=0x40; tbuf[en+0x09]=0x00; tbuf[en+0x0a]=0x00; tbuf[en+0x0b]=0x00;
en +=32;
tbuf[en+0]=0x90;
tbuf[en+1]=0x33;
tbuf[en+2]=0;
en += 32;
tbuf[en+0]=0x90;
tbuf[en+1]=0x34;
tbuf[en+2]=2;
en += 32;
tbuf[en+0]=0x00;
tbuf[en+1]=0x20; tbuf[en+0x08]=0x40; tbuf[en+0x09]=0x30; tbuf[en+0x0a]=0x00; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x44;
tbuf[en+1]=0x20;
en += 32;
tbuf[en+0]=0x44;
tbuf[en+1]=0x00;
en += 32;
tbuf[en+0]=0x00;
tbuf[en+1]=0x20; tbuf[en+0x08]=0x40; tbuf[en+0x09]=0x30; tbuf[en+0x0a]=0x20; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x44;
tbuf[en+1]=0x00;
en += 32;
tbuf[en+0]=0x90;
tbuf[en+1]=0x35;
tbuf[en+2]=3;
en += 32;
tbuf[en+0]=0x00;
tbuf[en+1]=0x00; tbuf[en+0x08]=0x41; tbuf[en+0x09]=0x30; tbuf[en+0x0a]=0x20; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x88;
tbuf[en+1]=0x00; tbuf[en+0x08]=0x42; tbuf[en+0x09]=0x30; tbuf[en+0x0a]=0x20; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x88;
tbuf[en+1]=0x00; tbuf[en+0x08]=0x43; tbuf[en+0x09]=0x30; tbuf[en+0x0a]=0x20; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x90;
tbuf[en+1]=0xEF;
tbuf[en+2]=2;
en += 32;
tbuf[en+0]=0x00;
tbuf[en+1]=0x00; tbuf[en+0x08]=0x42; tbuf[en+0x09]=0x30; tbuf[en+0x0a]=0x20; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x88;
tbuf[en+1]=0x00; tbuf[en+0x08]=0x45; tbuf[en+0x09]=0x35; tbuf[en+0x0a]=0x25; tbuf[en+0x0b]=0x00;
en += 32;
tbuf[en+0]=0x91;
tbuf[en+1]=0xEF;
tbuf[en+2]=1;
tbuf[en+0]=0x88;
tbuf[en+1]=0x00; tbuf[en+0x08]=0x95; tbuf[en+0x09]=0x95; tbuf[en+0x0a]=0x25; tbuf[en+0x0b]=0x00;
pwrite (fd, tbuf, 2048, 2048*32);
close (fd);
contextprintf (inContext, kBLLogLevelVerbose, "closed pretend DVD for read/write\n");
#endif
contextprintf (inContext, kBLLogLevelVerbose, "******** PARSING STARTS on %s *******\n", inBSDName);
#if TESTMODE
sprintf (devPath, "/tmp/testFindMSDOSRegion");
#else
sprintf (devPath, "/dev/r%s", inBSDName);
#endif
fd = open (devPath, O_RDONLY | O_SHLOCK);
if (-1 == fd)
{
contextprintf (inContext, kBLLogLevelVerbose, "unable to open, errno=%d\n", errno);
goto Exit;
}
contextprintf (inContext, kBLLogLevelVerbose, "opened DVD for shared reading\n");
#if TESTMODE
bzero (buf2048, 2048);
pread (fd, buf2048, 1*2048, 0);
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, "disc[0*2048] ", buf2048);
#endif
bzero (buf2048, 2048);
pread (fd, buf2048, 1*2048, 16*2048);
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, "disc[16*2048] ", buf2048);
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, "buf2048[16*2048 + 80] ", &(buf2048[80]));
ISO9660_PRIMARY_VOLUME_DESCRIPTOR * vd = (ISO9660_PRIMARY_VOLUME_DESCRIPTOR *) buf2048;
if ((0 == memcmp (vd->ident, "CD001", sizeof (vd->ident))) && (1 == vd->volume_descriptor_type) ) {
contextprintf (inContext, kBLLogLevelVerbose, "Primary Volume Descriptor confirmed\n");
} else {
contextprintf (inContext, kBLLogLevelVerbose, "Primary Volume Descriptor not found\n");
goto Exit;
}
uint32_t volumeSpaceSize = OSSwapLittleToHostInt32(vd->volume_space_size_LE);
contextprintf (inContext, kBLLogLevelVerbose, " .volumeSpaceSize=(in 2048-blocks)=0x%08x\n", volumeSpaceSize);
bzero (buf2048, 2048);
pread (fd, buf2048, 1*2048, 17*2048);
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, "\n\ndisc[17*2048] ", buf2048);
EL_TORITO_BOOT_VOLUME_DESCRIPTOR * bvd = (EL_TORITO_BOOT_VOLUME_DESCRIPTOR *) buf2048;
pread (fd, buf2048, 1*2048, 17*2048);
contextprintf (inContext, kBLLogLevelVerbose, "got putative EL_TORITO_BOOT_VOLUME_DESCRIPTOR:\n");
contextprintf (inContext, kBLLogLevelVerbose, " (Boot Record Volume Descriptor)\n");
contextprintf (inContext, kBLLogLevelVerbose, " .type=%d=0x%02x\n", bvd->type, bvd->type);
contextprintf (inContext, kBLLogLevelVerbose, " .ident=%.5s\n", bvd->ident);
contextprintf (inContext, kBLLogLevelVerbose, " .version=%d=0x%02x\n", bvd->version, bvd->version);
contextprintf (inContext, kBLLogLevelVerbose, " .system_id=%.31s\n", bvd->system_id);
contextprintf (inContext, kBLLogLevelVerbose, " .unused1=%.31s\n", bvd->unused1);
contextprintf (inContext, kBLLogLevelVerbose, " .bootcat_ptr=HE0x%08x=LE0x%08x=LE%d\n", (int) bvd->bootcat_ptr, OSSwapLittleToHostInt32 (bvd->bootcat_ptr), OSSwapLittleToHostInt32 (bvd->bootcat_ptr));
if ((0 == memcmp (bvd->ident, "CD001", sizeof (bvd->ident))) && (0 == bvd->type) && (0 != OSSwapLittleToHostInt32 (bvd->bootcat_ptr))) { contextprintf (inContext, kBLLogLevelVerbose, "Boot Record Volume Descriptor (El Torito header) confirmed\n");
} else {
contextprintf (inContext, kBLLogLevelVerbose, "Boot Record Volume Descriptor (El Torito header) not found\n");
goto Exit;
}
int firstSectorOfBootCatalog = OSSwapLittleToHostInt32 (bvd->bootcat_ptr);
contextprintf (inContext, kBLLogLevelVerbose, "firstSectorOfBootCatalog (in 2048-sectors) = %d = 0x%08x\n", firstSectorOfBootCatalog, firstSectorOfBootCatalog);
int ret;
bzero (buf2048, 2048);
ret = pread (fd, buf2048, 1*2048, firstSectorOfBootCatalog*2048);
contextprintf (inContext, kBLLogLevelVerbose, "\n\npread 2048-buff of Entries; ret=%d\n", ret);
uint8_t entryBuf [32];
int entryNum = 0;
bzero (entryBuf, 32);
memcpy (entryBuf, &(buf2048[entryNum*32]), 32);
contextprintf (inContext, kBLLogLevelVerbose, "\n\nVALIDATION ENTRY\n");
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, " ", entryBuf);
EL_TORITO_VALIDATION_ENTRY * ve = (EL_TORITO_VALIDATION_ENTRY *) entryBuf;
contextprintf (inContext, kBLLogLevelVerbose, "got putative EL_TORITO_VALIDATION_ENTRY:\n");
contextprintf (inContext, kBLLogLevelVerbose, " .headerid=%d=0x%02x\n", ve->id, ve->id);
contextprintf (inContext, kBLLogLevelVerbose, " .arch=%d=0x%02x\n", ve->arch, ve->arch);
contextprintf (inContext, kBLLogLevelVerbose, " .creatorid=%.24s\n", ve->creator_id);
contextprintf (inContext, kBLLogLevelVerbose, " .checksum=%d=0x%04x\n", ve->checksum, ve->checksum);
contextprintf (inContext, kBLLogLevelVerbose, " .key55=%d=0x%02x\n", ve->key55, ve->key55);
contextprintf (inContext, kBLLogLevelVerbose, " .keyAA=%d=0x%02x\n", ve->keyAA, ve->keyAA);
if ((1 == ve->id) &&
(0x55 == ve->key55) &&
(0xaa == ve->keyAA))
{
contextprintf (inContext, kBLLogLevelVerbose, "Validation Entry confirmed\n");
} else {
contextprintf (inContext, kBLLogLevelVerbose, "Validation Entry not found\n");
goto Exit;
}
entryNum++;
bzero (entryBuf, 32);
memcpy (entryBuf, &(buf2048[entryNum*32]), 32);
contextprintf (inContext, kBLLogLevelVerbose, "\n\nINITIAL/DEFAULT ENTRY\n");
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, " ", entryBuf);
EL_TORITO_INITIAL_DEFAULT_ENTRY * de = (EL_TORITO_INITIAL_DEFAULT_ENTRY *) entryBuf;
contextprintf (inContext, kBLLogLevelVerbose, "got putative EL_TORITO_INITIAL_DEFAULT_ENTRY:\n");
contextprintf (inContext, kBLLogLevelVerbose, " .bootindicator=%d=0x%02x\n", de->boot_indicator, de->boot_indicator);
contextprintf (inContext, kBLLogLevelVerbose, " .bootmedia=%d=0x%02x\n", de->boot_media, de->boot_media);
contextprintf (inContext, kBLLogLevelVerbose, " .loadsegment=%d=0x%04x\n", de->load_segment, de->load_segment);
contextprintf (inContext, kBLLogLevelVerbose, " .systemtype=%d=0x%02x\n", de->system_type, de->system_type);
contextprintf (inContext, kBLLogLevelVerbose, " .blockcount=%d=0x%04x\n", de->blockcount, de->blockcount);
contextprintf (inContext, kBLLogLevelVerbose, " .lba=%d=0x%08x\n", (int) de->lba, (int) de->lba);
entryNum++;
while (1)
{
bzero (entryBuf, 32);
memcpy (entryBuf, &(buf2048[entryNum*32]), 32);
contextprintf (inContext, kBLLogLevelVerbose, "\n\nSECTION HEADER ENTRY\n");
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, " ", entryBuf);
EL_TORITO_SECTION_HEADER_ENTRY * he = (EL_TORITO_SECTION_HEADER_ENTRY *) entryBuf;
contextprintf (inContext, kBLLogLevelVerbose, "got putative EL_TORITO_SECTION_HEADER_ENTRY:\n");
contextprintf (inContext, kBLLogLevelVerbose, " .headerindicator=%d=0x%02x\n", he->header_indicator, he->header_indicator);
contextprintf (inContext, kBLLogLevelVerbose, " .platformid=%d=0x%02x\n", he->platform_id, he->platform_id);
contextprintf (inContext, kBLLogLevelVerbose, " .sectionscount=%d=0x%04x\n", he->sections_count, he->sections_count);
contextprintf (inContext, kBLLogLevelVerbose, " .sectionid=%.28s\n", he->section_id);
if ((he->header_indicator != 0x90) && (he->header_indicator != 0x91))
{
contextprintf (inContext, kBLLogLevelVerbose, "invalid Section Header; stopping\n");
goto Exit;
}
bool isFinalHeader = (0x91 == he->header_indicator);
contextprintf (inContext, kBLLogLevelVerbose, "isFinalHeader=%d\n", isFinalHeader);
bool isEFIPlatformHeader = (0xef == he->platform_id);
contextprintf (inContext, kBLLogLevelVerbose, "isEFIPlatformHeader=%d\n", isEFIPlatformHeader);
UInt16 sectionEntriesForCurrentHeader = OSSwapLittleToHostInt16 (he->sections_count);
contextprintf (inContext, kBLLogLevelVerbose, "sectionEntriesForCurrentHeader=%d\n", sectionEntriesForCurrentHeader);
entryNum++;
if (entryNum > 63) goto TooManyEntries;
if (0 == sectionEntriesForCurrentHeader) goto DoneSectionEntriesForCurrentHeader;
sectionEntryIteratorForCurrentHeader = 0;
while (1)
{
contextprintf (inContext, kBLLogLevelVerbose, "processing section.section entry #%d for current header\n", sectionEntryIteratorForCurrentHeader);
bzero (entryBuf, 32);
memcpy (entryBuf, &(buf2048[entryNum*32]), 32);
contextprintf (inContext, kBLLogLevelVerbose, "\n\nSECTION SECTION ENTRY\n");
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, " ", entryBuf);
EL_TORITO_SECTION_SECTION_ENTRY * se = (EL_TORITO_SECTION_SECTION_ENTRY *) entryBuf;
contextprintf (inContext, kBLLogLevelVerbose, "got putative EL_TORITO_SECTION_SECTION_ENTRY:\n");
contextprintf (inContext, kBLLogLevelVerbose, " .boot_indicator=(0x88=bootable)=%d=0x%02x\n", se->boot_indicator, se->boot_indicator);
contextprintf (inContext, kBLLogLevelVerbose, " .boot_media (b5=ContinuationEntriesFollow)=0x%02x\n", se->boot_media);
contextprintf (inContext, kBLLogLevelVerbose, " .load_rba=HE%d=HE0x%08x=LE%d=LE0x%08x\n", (int) se->load_rba, (int) se->load_rba, OSSwapLittleToHostInt32(se->load_rba), OSSwapLittleToHostInt32(se->load_rba));
bool bootableSectionEntry = (0x88 == se->boot_indicator);
contextprintf (inContext, kBLLogLevelVerbose, "isBootableSectionEntry=%d\n", bootableSectionEntry);
bool sectionEntryHasExtensions = (0 != ((se->boot_media) & 0x20));
contextprintf (inContext, kBLLogLevelVerbose, "sectionEntryHasExtensions=%d\n", sectionEntryHasExtensions);
if (isEFIPlatformHeader && bootableSectionEntry)
{
*outSizeBlocks = volumeSpaceSize - OSSwapLittleToHostInt32 (se->load_rba); *outOffsetBlocks = OSSwapLittleToHostInt32 (se->load_rba); foundIt = true;
goto StopSearch;
}
if (isFinalHeader)
{
goto StopSearch;
}
entryNum++;
if (entryNum > 63) goto TooManyEntries;
if (sectionEntryHasExtensions)
{
while (1)
{
bzero (entryBuf, 32);
memcpy (entryBuf, &(buf2048[entryNum*32]), 32);
contextprintf (inContext, kBLLogLevelVerbose, "\n\nSECTION EXTENSION ENTRY\n");
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, " ", entryBuf);
EL_TORITO_SECTION_EXTENSION_ENTRY * see = (EL_TORITO_SECTION_EXTENSION_ENTRY *) entryBuf;
contextprintf (inContext, kBLLogLevelVerbose, "got putative EL_TORITO_SECTION_EXTENSION_ENTRY:\n");
contextprintf (inContext, kBLLogLevelVerbose, " .extension_indicator=(0x44=valid)=%d=0x%02x\n", see->extension_indicator, see->extension_indicator);
contextprintf (inContext, kBLLogLevelVerbose, " .bits(b5=ContinuationEntriesFollow)=%d\n", see->bits);
bool extensionsEntryHasMoreExtensions = (0 != ((see->bits) & 0x20));
contextprintf (inContext, kBLLogLevelVerbose, "extensionsEntryaHasMoreExtensions=%d\n", extensionsEntryHasMoreExtensions);
entryNum++;
if (entryNum > 63) goto TooManyEntries;
if (false == extensionsEntryHasMoreExtensions)
{
break;
}
}
}
sectionEntryIteratorForCurrentHeader++;
if (sectionEntryIteratorForCurrentHeader >= sectionEntriesForCurrentHeader)
{
contextprintf (inContext, kBLLogLevelVerbose, "no more sections for this section header\n");
break;
}
}
DoneSectionEntriesForCurrentHeader:;
}
StopSearch:;
if (false == foundIt)
{
contextprintf (inContext, kBLLogLevelVerbose, "Section Header Entry with EFI as a PlatformID not found.\n");
goto Exit;
}
#if TESTMODE
bzero (buf2048, 2048);
uint32_t byteOff = (*outOffsetBlocks)*2048;
pread (fd, buf2048, 1*2048, byteOff);
contextprintfhexdump16bytes (inContext, kBLLogLevelVerbose, "\n\n disc[%d x 2048=(%d)] ", buf2048);
#endif
goto Exit;
TooManyEntries:;
contextprintf (inContext, kBLLogLevelVerbose, "More than 32 entries in the 2048-sector = the BootingCatalog sector.\n");
goto Exit;
Exit:;
if (-1 != fd) close (fd);
contextprintf (inContext, kBLLogLevelVerbose, "Closed DVD; FoundTheMSDOSRegion=%d\n", foundIt);
*outFoundIt = foundIt;
}
static bool isPreBootEnvironmentUEFIWindowsBootCapable (BLContextPtr inContext)
{
bool ret = false;
io_registry_entry_t optionsNode = IO_OBJECT_NULL;
CFTypeRef featureMaskDataRef = NULL;
bool featureMaskExists = false;
uint32_t featureMaskValue = 0;
CFTypeRef featureFlagsDataRef = NULL;
bool featureFlagsExists = false;
uint32_t featureFlagsValue = 0;
bool hasNVRAM_UEFIWindowsBootCapable = false;
const uint32_t kWindowsUEFIBootSupport = 0x20000000;
optionsNode = IORegistryEntryFromPath (kIOMasterPortDefault, kIODeviceTreePlane ":/options");
if (IO_OBJECT_NULL == optionsNode) goto Exit;
featureMaskDataRef = IORegistryEntryCreateCFProperty (optionsNode,
CFSTR("4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:FirmwareFeaturesMask"),
kCFAllocatorDefault,
0);
if (NULL != featureMaskDataRef)
{
if ((CFGetTypeID (featureMaskDataRef) == CFDataGetTypeID ()) &&
(CFDataGetLength (featureMaskDataRef) == sizeof (uint32_t)))
{
const UInt8 * bytes = CFDataGetBytePtr (featureMaskDataRef);
featureMaskValue = CFSwapInt32LittleToHost (*(uint32_t *)bytes);
featureMaskExists = true;
contextprintf (inContext, kBLLogLevelVerbose, "found ioreg \"FirmwareFeaturesMask\"; featureMaskValue=0x%08X\n", featureMaskValue);
}
else
{
contextprintf (inContext, kBLLogLevelVerbose, "ioreg \"FirmwareFeaturesMask\" has unexpected type\n");
}
CFRelease (featureMaskDataRef);
}
else
{
contextprintf (inContext, kBLLogLevelVerbose, "did not find ioreg \"FirmwareFeaturesMask\"\n");
}
featureFlagsDataRef = IORegistryEntryCreateCFProperty (optionsNode,
CFSTR("4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:FirmwareFeatures"),
kCFAllocatorDefault,
0);
if (NULL != featureFlagsDataRef)
{
if ((CFGetTypeID (featureFlagsDataRef) == CFDataGetTypeID ()) &&
(CFDataGetLength (featureFlagsDataRef) == sizeof (uint32_t)))
{
const UInt8 * bytes = CFDataGetBytePtr (featureFlagsDataRef);
featureFlagsValue = CFSwapInt32LittleToHost (*(uint32_t *)bytes);
featureFlagsExists = true;
contextprintf (inContext, kBLLogLevelVerbose, "found ioreg \"FirmwareFeatures\"; featureFlagsValue=0x%08X\n", featureFlagsValue);
}
else
{
contextprintf (inContext, kBLLogLevelVerbose, "ioreg \"FirmwareFeatures\" has unexpected type\n");
}
CFRelease (featureFlagsDataRef);
}
else
{
contextprintf (inContext, kBLLogLevelVerbose, "did not find ioreg \"FirmwareFeatures\"\n");
}
if (featureMaskExists && (0 != (featureMaskValue & kWindowsUEFIBootSupport)) &&
featureFlagsExists && (0 != (featureFlagsValue & kWindowsUEFIBootSupport)))
{
ret = true;
goto Exit;
}
CFMutableDictionaryRef matchForAppleEFINVRAMNode = IOServiceMatching ("AppleEFINVRAM");
io_service_t appleEFINVRAMNode = IOServiceGetMatchingService (kIOMasterPortDefault, matchForAppleEFINVRAMNode);
if (0 != appleEFINVRAMNode)
{
CFDataRef prop = IORegistryEntryCreateCFProperty (appleEFINVRAMNode, CFSTR("UEFIWindowsBootCapable"), kCFAllocatorDefault, 0);
if (NULL != prop)
{
CFIndex propLen = CFDataGetLength (prop);
if (1 == propLen)
{
const uint8_t * propDataPtr = CFDataGetBytePtr (prop);
if ((0x31 == propDataPtr[0]) || (0x01 == propDataPtr[0]))
hasNVRAM_UEFIWindowsBootCapable = true;
}
CFRelease (prop);
}
}
if (hasNVRAM_UEFIWindowsBootCapable)
{
contextprintf (inContext, kBLLogLevelVerbose, "NVRAM variable \"UEFIWindowsBootCapable\" is set\n");
ret = true;
goto Exit;
}
Exit:;
contextprintf (inContext, kBLLogLevelVerbose, "isPreBootEnvironmentUEFIWindowsBootCapable=%d\n", ret);
return ret;
}
bool isDVDWithElToritoWithUEFIBootableOS (BLContextPtr inContext, const char* inDevBSD, int* outBootEntry, int* outPartitionStart, int* outPartitionSize)
{
bool ret = false;
CFMutableDictionaryRef match;
io_service_t media;
bool foundMSDOSRegion = false;
uint32_t msdosRegionInThisBootEntry = 0;
uint32_t msdosRegionOffset = 0;
uint32_t msdosRegionSize = 0;
if (false == isPreBootEnvironmentUEFIWindowsBootCapable (inContext))
{
contextprintf (inContext, kBLLogLevelVerbose, "preboot environment is not UEFI boot capable\n");
goto Exit;
}
match = IOBSDNameMatching (kIOMasterPortDefault, 0, inDevBSD);
media = IOServiceGetMatchingService (kIOMasterPortDefault, match);
if (false == IOObjectConformsTo (media, kIODVDMediaClass))
{
contextprintf (inContext, kBLLogLevelVerbose, "given BSD is not a DVD disc medium\n");
goto Exit;
}
findMSDOSRegion (inContext, inDevBSD, &foundMSDOSRegion, &msdosRegionOffset, &msdosRegionSize);
if (false == foundMSDOSRegion)
{
contextprintf (inContext, kBLLogLevelVerbose, "given disc does not have ElTorito + Bootable image\n");
goto Exit;
}
msdosRegionInThisBootEntry = 1;
ret = true;
Exit:;
*outBootEntry = msdosRegionInThisBootEntry;
*outPartitionStart = msdosRegionOffset;
*outPartitionSize = msdosRegionSize;
contextprintf (inContext, kBLLogLevelVerbose, "isDVDWithElToritoWithUEFIBootableOS=%d\n", ret);
return ret;
}