Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:frispete:tools
syslinux
0001-openSUSE-specific-EFI-booting-implementati...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-openSUSE-specific-EFI-booting-implementation.patch of Package syslinux
From f0276260ddc6092dec9485f4c0fd12e14cad7ac2 Mon Sep 17 00:00:00 2001 From: v-fox <virtuousfox@gmail.com> Date: Mon, 26 Oct 2015 09:40:01 +0500 Subject: [PATCH] openSUSE-specific EFI booting implementation --- utils/isohybrid.c | 349 ++++++++++++++++++++++++++++++++++-------------------- utils/isohybrid.h | 2 +- 2 files changed, 224 insertions(+), 127 deletions(-) Index: b/utils/isohybrid.c =================================================================== --- a/utils/isohybrid.c +++ b/utils/isohybrid.c @@ -49,14 +49,19 @@ unsigned int padding = 0; uuid_t disk_uuid, part_uuid, iso_uuid; uint8_t mode = 0; -enum { VERBOSE = 1 , EFI = 2 , MAC = 4}; +enum { VERBOSE = 1 , EFI = 2 , MAC = 4, MODE_GPT = 8 , MODE_MBR = 0x10 }; + +/* partition numbers (1 based) */ +int part_data = 0; +int part_efi = 0; +int part_mac = 0; /* user options */ uint16_t head = 64; /* 1 <= head <= 256 */ uint8_t sector = 32; /* 1 <= sector <= 63 */ uint8_t entry = 0; /* partition number: 1 <= entry <= 4 */ -uint8_t offset = 0; /* partition offset: 0 <= offset <= 64 */ +uint32_t offset = 0; /* partition offset: 0 <= offset <= 0xFFFFFFFF(4294967296) */ uint16_t type = 0x17; /* partition type: 0 <= type <= 255 */ uint32_t id = 0; /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */ @@ -67,10 +72,13 @@ char mbr_template_path[1024] = {0}; /* uint16_t ve[16]; uint32_t catoffset = 0; -uint32_t c = 0, cc = 0, cs = 0; +uint32_t c = 0; uint32_t psize = 0, isosize = 0; +off_t iso_size = 0; +off_t iso_filesize = 0; + /* boot catalogue parameters */ uint32_t de_lba = 0; uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0; @@ -234,12 +242,14 @@ printh(void) printf(FMT, " -h <X>", "Number of geometry heads (default 64)"); printf(FMT, " -s <X>", "Number of geometry sectors (default 32)"); printf(FMT, " -e --entry", "Specify partition entry number (1-4)"); - printf(FMT, " -o --offset", "Specify partition offset (default 0)"); + printf(FMT, " -o --offset", "Specify partition offset (in 512 byte units, default 0)"); printf(FMT, " -t --type", "Specify partition type (default 0x17)"); printf(FMT, " -i --id", "Specify MBR ID (default random)"); printf(FMT, " -u --uefi", "Build EFI bootable image"); printf(FMT, " -m --mac", "Add AFP table support"); printf(FMT, " -b --mbr <PATH>", "Load MBR from PATH"); + printf(FMT, " --gpt", "Force GPT"); + printf(FMT, " --mbr", "Force MBR"); printf("\n"); printf(FMT, " --forcehd0", "Assume we are loaded as disk ID 0"); @@ -269,6 +279,8 @@ check_option(int argc, char *argv[]) { "offset", required_argument, NULL, 'o' }, { "type", required_argument, NULL, 't' }, { "id", required_argument, NULL, 'i' }, + { "gpt", no_argument, NULL, 1001 }, + { "mbr", no_argument, NULL, 1002 }, { "forcehd0", no_argument, NULL, 'f' }, { "ctrlhd0", no_argument, NULL, 'c' }, @@ -311,8 +323,8 @@ check_option(int argc, char *argv[]) case 'o': offset = strtoul(optarg, &err, 0); - if (*err || offset > 64) - errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg); + if (*err) + errx(1, "invalid offset: `%s', 0 <= offset <= 0xFFFFFFFF", optarg); break; case 't': @@ -341,14 +353,10 @@ check_option(int argc, char *argv[]) case 'u': mode |= EFI; - if (entry) - errx(1, "setting an entry is unsupported with EFI or Mac"); break; case 'm': mode |= MAC; - if (entry) - errx(1, "setting an entry is unsupported with EFI or Mac"); break; case 'b': @@ -361,6 +369,14 @@ check_option(int argc, char *argv[]) mode |= VERBOSE; break; + case 1001: + mode |= MODE_GPT; + break; + + case 1002: + mode |= MODE_MBR; + break; + case 'V': printf("%s version %s\n", prog, VERSION); exit(0); @@ -476,7 +492,7 @@ check_banner(const uint8_t *buf) int check_catalogue(const uint8_t *buf) { - int i = 0; + int i, cs; for (i = 0, cs = 0; i < 16; i++) { @@ -598,15 +614,24 @@ read_mbr_template(char *path, uint8_t *m fclose(fp); } +uint32_t ofs2chs(uint32_t ofs) +{ + unsigned c, h, s; + + s = (ofs % sector) + 1; + h = (ofs / sector) % head; + c = ofs / (sector * head); + if(c > 1023) c = 1023; + + return ((c & 0xff) << 24) + ((s + ((c >> 8) << 6)) << 16) + (h << 8); +} int initialise_mbr(uint8_t *mbr) { int i = 0; - uint32_t tmp = 0; - uint8_t ptype = 0, *rbm = mbr; - uint8_t bhead = 0, bsect = 0, bcyle = 0; - uint8_t ehead = 0, esect = 0, ecyle = 0; + uint32_t tmp = 0, chs; + uint8_t *rbm = mbr; #ifndef ISOHYBRID_C_STANDALONE extern unsigned char isohdpfx[][MBRSIZE]; @@ -628,16 +653,16 @@ initialise_mbr(uint8_t *mbr) } - if (mode & MAC) { - memcpy(mbr, afp_header, sizeof(afp_header)); - } - if (!entry) entry = 1; if (mode & EFI) type = 0; + if (mode & MAC) { + memcpy(mbr, afp_header, sizeof(afp_header)); + } + mbr += MBRSIZE; /* offset 432 */ tmp = lendian_int(de_lba * 4); @@ -656,50 +681,64 @@ initialise_mbr(uint8_t *mbr) mbr[1] = '\0'; mbr += 2; /* offset 446 */ - ptype = type; - psize = c * head * sector - offset; - - bhead = (offset / sector) % head; - bsect = (offset % sector) + 1; - bcyle = offset / (head * sector); + for (i = 1; i <= 4; i++, mbr += 16) + { + memset(mbr, 0, 16); - bsect += (bcyle & 0x300) >> 2; - bcyle &= 0xFF; + if (!(mode & MODE_MBR)) { + /* write protective mbr */ + if(i == 1 && (mode & MODE_GPT)) { + chs = ofs2chs(1); + mbr[1] = chs >> 8; + mbr[2] = chs >> 16; + mbr[3] = chs >> 24; + mbr[4] = 0xee; + chs = ofs2chs(iso_filesize/512 - 1); + mbr[5] = chs >> 8; + mbr[6] = chs >> 16; + mbr[7] = chs >> 24; - ehead = head - 1; - esect = sector + (((cc - 1) & 0x300) >> 2); - ecyle = (cc - 1) & 0xFF; + tmp = lendian_int(1); + memcpy(&mbr[8], &tmp, sizeof(tmp)); - for (i = 1; i <= 4; i++) - { - memset(mbr, 0, 16); - if (i == entry) + tmp = lendian_int(iso_filesize/512 - 1); + memcpy(&mbr[12], &tmp, sizeof(tmp)); + } + + continue; + } + + if (i == part_data) { - mbr[0] = 0x80; - mbr[1] = bhead; - mbr[2] = bsect; - mbr[3] = bcyle; - mbr[4] = ptype; - mbr[5] = ehead; - mbr[6] = esect; - mbr[7] = ecyle; + chs = ofs2chs(offset); + mbr[0] = 0x80; + mbr[1] = chs >> 8; + mbr[2] = chs >> 16; + mbr[3] = chs >> 24; + chs = ofs2chs(c * head * sector - 1); + mbr[4] = type; + mbr[5] = chs >> 8; + mbr[6] = chs >> 16; + mbr[7] = chs >> 24; tmp = lendian_int(offset); memcpy(&mbr[8], &tmp, sizeof(tmp)); - tmp = lendian_int(psize); + tmp = lendian_int(c * head * sector - offset); memcpy(&mbr[12], &tmp, sizeof(tmp)); } - if (i == 2 && (mode & EFI)) + + if (i == part_efi) { - mbr[0] = 0x0; - mbr[1] = 0xfe; - mbr[2] = 0xff; - mbr[3] = 0xff; + chs = ofs2chs(efi_lba * 4); + mbr[1] = chs >> 8; + mbr[2] = chs >> 16; + mbr[3] = chs >> 24; + chs = ofs2chs(efi_lba * 4 + efi_count - 1); mbr[4] = 0xef; - mbr[5] = 0xfe; - mbr[6] = 0xff; - mbr[7] = 0xff; + mbr[5] = chs >> 8; + mbr[6] = chs >> 16; + mbr[7] = chs >> 24; tmp = lendian_int(efi_lba * 4); memcpy(&mbr[8], &tmp, sizeof(tmp)); @@ -707,9 +746,9 @@ initialise_mbr(uint8_t *mbr) tmp = lendian_int(efi_count); memcpy(&mbr[12], &tmp, sizeof(tmp)); } - if (i == 3 && (mode & MAC)) + + if (i == part_mac) { - mbr[0] = 0x0; mbr[1] = 0xfe; mbr[2] = 0xff; mbr[3] = 0xff; @@ -722,9 +761,8 @@ initialise_mbr(uint8_t *mbr) memcpy(&mbr[8], &tmp, sizeof(tmp)); tmp = lendian_int(mac_count); - memcpy(&mbr[12], &tmp, sizeof(tmp)); - } - mbr += 16; + memcpy(&mbr[12], &tmp, sizeof(tmp)); + } } mbr[0] = 0x55; mbr[1] = 0xAA; @@ -802,12 +840,28 @@ ascii_to_utf16le(uint16_t *dst, const ch } void +set_gpt_part_name(struct gpt_part_header *part, const char *name) +{ + unsigned u, len = strlen(name); + + if (len > sizeof part->name / sizeof *part->name) + len = sizeof part->name / sizeof *part->name; + + // utf16le, actually + for (u = 0; u < len; u++) + part->name[u] = *name++; +} + +void initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary) { struct gpt_header *header = (struct gpt_header *)gpt; struct gpt_part_header *part; int hole = 0; int gptsize = 128 / 4 + 2; + int i; + + if(!(mode & MODE_GPT)) return; if (mac_lba) { /* 2048 bytes per partition, plus round to 2048 boundary */ @@ -848,40 +902,34 @@ initialise_gpt(uint8_t *gpt, uint32_t cu reverse_uuid(iso_uuid); } - memcpy(part->partGUID, iso_uuid, sizeof(uuid_t)); - memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t)); - part->firstLBA = lendian_64(0); - part->lastLBA = lendian_64(psize - 1); - ascii_to_utf16le(part->name, "ISOHybrid ISO"); - - gpt += sizeof(struct gpt_part_header); - part++; - - memcpy(part->partGUID, part_uuid, sizeof(uuid_t)); - memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t)); - part->firstLBA = lendian_64(efi_lba * 4); - part->lastLBA = lendian_64(part->firstLBA + efi_count - 1); - ascii_to_utf16le(part->name, "ISOHybrid"); - - gpt += sizeof(struct gpt_part_header); - - if (mac_lba) { - gpt += sizeof(struct gpt_part_header); - - part++; + for(i = 1; i <= 4; i++, part++) { + if(i == part_data) { + memcpy(part->partGUID, iso_uuid, sizeof(uuid_t)); + memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t)); + part->firstLBA = lendian_64(offset); + part->lastLBA = lendian_64(iso_size/512 - 1); + set_gpt_part_name(part, "ISOHybrid ISO"); + } - memcpy(part->partGUID, part_uuid, sizeof(uuid_t)); - memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t)); - part->firstLBA = lendian_64(mac_lba * 4); - part->lastLBA = lendian_64(part->firstLBA + mac_count - 1); - ascii_to_utf16le(part->name, "ISOHybrid"); + if(i == part_efi) { + memcpy(part->partGUID, part_uuid, sizeof(uuid_t)); + memcpy(part->partTypeGUID, efi_system_partition, sizeof(uuid_t)); + part->firstLBA = lendian_64(efi_lba * 4); + part->lastLBA = lendian_64(part->firstLBA + efi_count - 1); + set_gpt_part_name(part, "ISOHybrid"); + } - part--; + if (i == part_mac) { + memcpy(part->partGUID, part_uuid, sizeof(uuid_t)); + memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t)); + part->firstLBA = lendian_64(mac_lba * 4); + part->lastLBA = lendian_64(part->firstLBA + mac_count - 1); + set_gpt_part_name(part, "ISOHybrid"); + } } - part--; - header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part, + header->partitionEntriesCRC = lendian_int (chksum_crc32(gpt, header->numParts * header->sizeOfPartitionEntries)); header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header, @@ -948,8 +996,10 @@ main(int argc, char *argv[]) FILE *fp = NULL; uint8_t *buf = NULL, *bufz = NULL; int cylsize = 0, frac = 0; + unsigned padding = 0; size_t orig_gpt_size, free_space, gpt_size; struct iso_primary_descriptor descriptor; + struct stat isostat; prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]); i = check_option(argc, argv); @@ -962,8 +1012,19 @@ main(int argc, char *argv[]) return 1; } - if ((mode & EFI) && offset) - errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]); + if (!(mode & (MODE_MBR | MODE_GPT))) { + mode |= MODE_MBR; + } + + if ((mode & EFI) && !offset) type = 0; + + part_data = 1; + if(mode & EFI) part_efi = 2; + if(mode & MAC) part_mac = 3; + + if(entry) { + if(entry != part_efi && entry != part_mac) part_data = entry; + } srand(time(NULL) << (getppid() << getpid())); @@ -1014,12 +1075,30 @@ main(int argc, char *argv[]) if (!read_efi_section(buf)) { buf += 32; if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) { - offset = 0; + if(efi_count < 2) { + unsigned char bpb[512]; + + if (fseek(fp, (efi_lba * 2048), SEEK_SET)) { + err(1, "%s: seek error - 3", argv[0]); + } + + if (fread(bpb, 1, sizeof bpb, fp) != sizeof bpb) { + err(1, "%s", argv[0]); + } + + if((bpb[511] << 8) + bpb[510] == 0xaa55) { + unsigned s = bpb[19] + (bpb[20] << 8); + if(!s) s = bpb[32] + (bpb[33] << 8) + (bpb[34] << 16) + (bpb[35] << 24); + if(s) efi_count = s; + } + } } else { errx(1, "%s: invalid efi catalogue", argv[0]); } } else { - errx(1, "%s: unable to find efi image", argv[0]); + fprintf(stderr, "%s: warning: unable to find efi image\n", argv[0]); + mode &= ~EFI; + part_efi = 0; } } @@ -1052,27 +1131,55 @@ main(int argc, char *argv[]) "signature. Note that isolinux-debug.bin does not support " \ "hybrid booting", argv[0]); + if (offset && efi_lba && offset > efi_lba * 4) + { + part_efi = 1; + part_data = 2; + if (part_mac) + { + part_mac = 2; + part_data = 3; + } + } + if (stat(argv[0], &isostat)) err(1, "%s", argv[0]); - isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size); - free_space = isostat.st_size - isosize; + iso_size = (off_t) lendian_int(descriptor.size) * lendian_short(descriptor.block_size); + free_space = isostat.st_size - iso_size; cylsize = head * sector * 512; frac = isostat.st_size % cylsize; padding = (frac > 0) ? cylsize - frac : 0; if (mode & VERBOSE) - printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding); + printf("imgsize: %zu, padding: %d\n", (size_t)iso_filesize, padding); - cc = c = ( isostat.st_size + padding) / cylsize; + c = (isostat.st_size + padding) / cylsize; if (c > 1024) { warnx("Warning: more than 1024 cylinders: %d", c); warnx("Not all BIOSes will be able to boot this device"); - cc = 1024; } + /* 512 byte header, 128 entries of 128 bytes */ + orig_gpt_size = gpt_size = 512 + (128 * 128); + + /* Leave space for the APM if necessary */ + if (mac_lba) + gpt_size += (4 * 2048); + + /* + * We need to ensure that we have enough space for the secondary GPT. + * Unlike the primary, this doesn't need a hole for the APM. We still + * want to be 1MB aligned so just bump the padding by a megabyte. + */ + if ((mode & MODE_GPT) && free_space < orig_gpt_size && padding < orig_gpt_size) { + padding += 1024 * 1024; + } + + iso_filesize = isostat.st_size + padding; + if (!id) { if (fseeko(fp, (off_t) 440, SEEK_SET)) @@ -1094,6 +1201,16 @@ main(int argc, char *argv[]) buf = bufz; memset(buf, 0, BUFSIZE); + + if (fseek(fp, 0, SEEK_SET)) + err(1, "%s: seek error - 5", argv[0]); + + /* clean up first 16 blocks */ + for (i = 0; i < 16; i++) { + if (fwrite(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE) + err(1, "%s: write error - 1", argv[0]); + } + i = initialise_mbr(buf); if (mode & VERBOSE) @@ -1105,42 +1222,22 @@ main(int argc, char *argv[]) if (fwrite(buf, sizeof(char), i, fp) != (size_t)i) err(1, "%s: write error - 1", argv[0]); - if (efi_lba) { + if (mode & MODE_GPT) { + /* always write primary gpt, if only to cleanup old data */ + reverse_uuid(efi_system_partition); reverse_uuid(basic_partition); reverse_uuid(hfs_partition); - /* 512 byte header, 128 entries of 128 bytes */ - orig_gpt_size = gpt_size = 512 + (128 * 128); - - /* Leave space for the APM if necessary */ - if (mac_lba) - gpt_size += (4 * 2048); - buf = calloc(gpt_size, sizeof(char)); memset(buf, 0, gpt_size); /* - * We need to ensure that we have enough space for the secondary GPT. - * Unlike the primary, this doesn't need a hole for the APM. We still - * want to be 1MB aligned so just bump the padding by a megabyte. - */ - if (free_space < orig_gpt_size && padding < orig_gpt_size) { - padding += 1024 * 1024; - } - - /* - * Determine the size of the ISO filesystem. This will define the size - * of the partition that covers it. - */ - psize = isosize / 512; - - /* * Primary GPT starts at sector 1, secondary GPT starts at 1 sector * before the end of the image */ - initialise_gpt(buf, 1, (isostat.st_size + padding - 512) / 512, 1); + initialise_gpt(buf, 1, iso_filesize / 512 - 1, 1); - if (fseeko(fp, (off_t) 512, SEEK_SET)) + if (fseek(fp, 512, SEEK_SET)) err(1, "%s: seek error - 6", argv[0]); if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size) @@ -1166,17 +1263,17 @@ main(int argc, char *argv[]) if (fsync(fileno(fp))) err(1, "%s: could not synchronise", argv[0]); - if (ftruncate(fileno(fp), isostat.st_size + padding)) + if (ftruncate(fileno(fp), iso_filesize)) err(1, "%s: could not add padding bytes", argv[0]); } - if (efi_lba) { + if (mode & MODE_GPT) { buf = realloc(buf, orig_gpt_size); memset(buf, 0, orig_gpt_size); buf += orig_gpt_size - sizeof(struct gpt_header); - initialise_gpt(buf, (isostat.st_size + padding - 512) / 512, 1, 0); + initialise_gpt(buf, iso_filesize / 512 - 1, 1, 0); /* Shift back far enough to write the 128 GPT entries */ buf -= 128 * sizeof(struct gpt_part_header); @@ -1186,7 +1283,7 @@ main(int argc, char *argv[]) * end of the image */ - if (fseeko(fp, (isostat.st_size + padding) - orig_gpt_size, SEEK_SET)) + if (fseek(fp, iso_filesize - orig_gpt_size, SEEK_SET)) err(1, "%s: seek error - 8", argv[0]); if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size) Index: b/utils/isohybrid.h =================================================================== --- a/utils/isohybrid.h +++ b/utils/isohybrid.h @@ -20,7 +20,7 @@ * */ -#define VERSION "0.12" +#define VERSION "0.12.1" #define BUFSIZE 2048 #define MBRSIZE 432
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor