/*! @file preboot.c Copyright 2007 VMware Inc. Author: David Elliott */ #include "libsaio.h" #include "preboot.h" static struct preboot_header *spPrebootHeader = NULL; //========================================================================== static int get_ramdisk_info(int biosdev, struct driveInfo *dip) { if(spPrebootHeader == NULL || spPrebootHeader->p_initrd == 0) return -1; bzero(dip, sizeof(*dip)); // Only 1 ramdisk for now if(biosdev != 0x100) return -1; if(spPrebootHeader->p_initrd == 0) return -1; dip->biosdev = biosdev; dip->uses_ebios = TRUE; // dip->no_emulation = FALSE; dip->di.params.phys_sectors = spPrebootHeader->initrd_sectors; dip->valid = TRUE; return 0; } //========================================================================== static int ramdiskReadBytes( int biosdev, unsigned int blkno, unsigned int byteoff, unsigned int byteCount, void * buffer ) { if(spPrebootHeader == NULL || spPrebootHeader->p_initrd == 0) return -1; if(biosdev != 0x100) return -1; void *p_initrd = (void*)spPrebootHeader->p_initrd; bcopy(p_initrd + blkno*512 + byteoff, buffer, byteCount); return 0; } //========================================================================== /*! @function findPrebootHeader Finds the PREBOOT structure and returns a pointer to it if it is valid. It is valid so long as it has the right signature and checksum. It is not guaranteed to contain an initrd. */ static struct preboot_header *findPrebootHeader() { struct preboot_header *pPrebootHeader = (void*)PREBOOT_DATA; if(memcmp(PREBOOT_SIGNATURE, pPrebootHeader->signature, 8) == 0) { uint8_t checksum = checksum8(pPrebootHeader, pPrebootHeader->length); if(checksum != 0) { printf("WARNING: Found bad PREBOOT structure\n"); pPrebootHeader = NULL; } } else pPrebootHeader = NULL; return pPrebootHeader; } //========================================================================== BVRef scanPrebootVolumes() { struct preboot_header *pPrebootHeader = findPrebootHeader(); if(pPrebootHeader == NULL) return NULL; if(pPrebootHeader->p_initrd == 0) return NULL; // We have a header with an initrd.. use it // Install hooks to disk.c code to make the ramdisk available p_get_ramdisk_info = get_ramdisk_info; p_ramdiskReadBytes = ramdiskReadBytes; spPrebootHeader = pPrebootHeader; // Scan the disk for the first volume (hopefully the only volume) // containing extra extensions. int partCount; // unused BVRef ramdiskChain = diskScanBootVolumes(0x100, &partCount); if(ramdiskChain == NULL) { printf("Found ramdisk but no partitions in it!"); // TODO: Check for raw HFS+ image (e.g. no partition map) return NULL; } // We can now access the ramdisk return ramdiskChain; } //========================================================================== BVRef selectPrebootVolume(BVRef ramdiskChain) { if(ramdiskChain == NULL) return NULL; char *path = malloc(4096); BVRef curr; for(curr = ramdiskChain; curr; curr = curr->next) { strcpy(path, "rd(0,"); char partnostr[10]; // no way. if(curr->part_no >= 1000) continue; sprintf(partnostr, "%d",curr->part_no); strcat(path, partnostr); strcat(path, ")/Library/Application Support/DarwinBoot/Extra/"); struct dirstuff *extradir = opendir(path); if(extradir == NULL) printf("Could not find extra dir which is the whole point of a ramdisk\n"); else { // NOTE: Never free'd gPrebootExtraDir = malloc(strlen(path)+1); strcpy(gPrebootExtraDir, path); closedir(extradir); // We found a valid volume.. so stop walking the chain. break; } } free(path); return curr; }