diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 2802654..3bf800e 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -125,6 +125,9 @@ void ecma119_image_free(Ecma119Image *t) for (i = 0; (int) i < t->apm_req_count; i++) if (t->apm_req[i] != NULL) free(t->apm_req[i]); + for (i = 0; (int) i < t->gpt_req_count; i++) + if (t->gpt_req[i] != NULL) + free(t->gpt_req[i]); free(t); } @@ -1881,13 +1884,15 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) if (target->hfsplus_blessed[i] != NULL) iso_node_ref(target->hfsplus_blessed[i]); } + /* Note: Set apm_block_size to 2048, if desired, before pthread_create() + at the end of this function. + Register any Apple Partition Map entries before pthread_create(). + */ target->apm_block_size = 512; for (i = 0; i < ISO_APM_ENTRIES_MAX; i++) target->apm_req[i] = NULL; - /* Set apm_block_size to 2048, if desired, before pthread_create() - at the end of this function. - Register any Apple Partition Map entries before pthread_create(). - */ + for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++) + target->gpt_req[i] = NULL; /* * 2. Based on those options, create needed writers: iso, joliet... diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 2de7d9c..8a03274 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -70,10 +70,18 @@ #endif -/* The maximum number of Apple Partition Map entries. +/* The theoretical maximum number of Apple Partition Map entries in the + System Area of an ISO image: + Block0 plus 63 entries with block size 512 */ #define ISO_APM_ENTRIES_MAX 63 +/* The theoretical maximum number of GPT entries in the System Area of an + ISO image: + MBR plus GPT header block plus 248 GPT entries of 128 bytes each. +*/ +#define ISO_GPT_ENTRIES_MAX 248 + /** * Holds the options for the image generation. @@ -803,6 +811,12 @@ struct ecma119_image /* 512 by default. May be changed to 2048 before writer thread starts. */ int apm_block_size; + /* GPT description. To be composed during IsoImageWriter + method ->compute_data_blocks() by calling iso_register_gpt_entry(). + */ + struct iso_gpt_partition_request *gpt_req[ISO_GPT_ENTRIES_MAX]; + int gpt_req_count; + }; #define BP(a,b) [(b) - (a) + 1] diff --git a/libisofs/image.h b/libisofs/image.h index 945d627..0645430 100644 --- a/libisofs/image.h +++ b/libisofs/image.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 Thomas Schmitt + * Copyright (c) 2009 - 2012 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 509e1bd..24bb4ce 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -7209,6 +7209,12 @@ int iso_image_hfsplus_get_blessed(IsoImage *img, IsoNode ***blessed_nodes, /** Overlapping Apple Partition Map entries requested (FAILURE, HIGH, -384) */ #define ISO_BOOT_APM_OVERLAP 0xE830FE80 +/** Too many GPT entries requested (FAILURE, HIGH, -385) */ +#define ISO_BOOT_TOO_MANY_GPT 0xE830FE7F + +/** Overlapping GPT entries requested (FAILURE, HIGH, -386) */ +#define ISO_BOOT_GPT_OVERLAP 0xE830FE7E + /* Internal developer note: diff --git a/libisofs/make_isohybrid_mbr.c b/libisofs/make_isohybrid_mbr.c index ba094b5..ed0939d 100644 --- a/libisofs/make_isohybrid_mbr.c +++ b/libisofs/make_isohybrid_mbr.c @@ -480,23 +480,7 @@ static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt, } -static void write_gpt_entry(Ecma119Image *t, char *buf, uint8_t type_guid[16], - off_t start_lba, off_t end_lba, uint8_t flags[8], - uint8_t name[72]) -{ - char *wpt = buf; - - memcpy(wpt, type_guid, 16); - wpt += 16; - iso_random_uuid(t, (uint8_t *) wpt); - wpt += 16; - lsb_to_buf(&wpt, start_lba & 0xffffffff, 32, 0); - lsb_to_buf(&wpt, (start_lba >> 32) & 0xffffffff, 32, 0); - lsb_to_buf(&wpt, end_lba & 0xffffffff, 32, 0); - lsb_to_buf(&wpt, (end_lba >> 32) & 0xffffffff, 32, 0); - memcpy(wpt, name, 72); -} - +#ifdef NIX static int write_gpt_array(Ecma119Image *t, char *buf, uint32_t part_start) { @@ -515,6 +499,9 @@ static int write_gpt_array(Ecma119Image *t, char *buf, uint32_t part_start) /* >>> First entry describes overall image , basic_data_uuid start_lba = ; end_lba = ; + + >>> replace write_gpt_entry by iso_quick_gpt_entry + write_gpt_entry(t, buf + 512 * part_start, basic_data_uuid, off_t start_lba, off_t end_lba, uint8_t flags[8], uint8_t name[72]) @@ -530,7 +517,7 @@ static int write_gpt_array(Ecma119Image *t, char *buf, uint32_t part_start) else continue; - /* >>> */; + /* >>> iso_quick_gpt_entry() */ } @@ -539,82 +526,7 @@ static int write_gpt_array(Ecma119Image *t, char *buf, uint32_t part_start) return ISO_SUCCESS; } - -static int write_gpt_header_block(Ecma119Image *t, char *buf, - uint32_t part_start, uint32_t p_arr_crc) -{ - static char *sig = "EFI PART"; - static char revision[4] = {0x00, 0x00, 0x01, 0x00}; - char *wpt; - uint32_t crc; - off_t back_lba; - - memset(buf, 0, 512); - wpt = buf; - - memcpy(wpt, sig, 8); /* no trailing 0 */ - wpt += 8; - memcpy(wpt, revision, 4); - wpt += 4; - lsb_to_buf(&wpt, 92, 32, 0); - - /* CRC will be inserted later */ - wpt += 4; - - /* reserved */ - lsb_to_buf(&wpt, 0, 32, 0); - /* Own LBA low 32 */ - lsb_to_buf(&wpt, 1, 32, 0); - /* Own LBA high 32 */ - lsb_to_buf(&wpt, 0, 32, 0); - - /* Backup LBA is 1 hd block before image end */ - back_lba = t->curblock * 4 - 1; - lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 32, 1); - lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 32, 1); - - /* First usable LBA for partitions (entry array occupies 32 hd blocks) */ - lsb_to_buf(&wpt, part_start + 32, 32, 0); - lsb_to_buf(&wpt, 0, 32, 0); - - /* Last usable LBA for partitions */ - lsb_to_buf(&wpt, (uint32_t) ((back_lba - 32) & 0xffffffff), 32, 1); - lsb_to_buf(&wpt, (uint32_t) ((back_lba - 32) >> 32), 32, 1); - - /* Disk GUID */ - iso_random_uuid(t, (uint8_t *) wpt); - wpt += 16; - - /* Partition entries start */ - lsb_to_buf(&wpt, part_start, 32, 0); - lsb_to_buf(&wpt, 0, 32, 0); - - /* Number of partition entries */ - lsb_to_buf(&wpt, 128, 32, 0); - - /* Size of a partition entry */ - lsb_to_buf(&wpt, 128, 32, 0); - - /* CRC-32 of the partition array */ - lsb_to_buf(&wpt, p_arr_crc, 32, 0); - - - /* <<< Only for a first test */ - if (wpt - buf != 92) { - iso_msgs_submit(0, - "program error : write_gpt_header_block : wpt != 92", - 0, "FATAL", 0); - return ISO_ISOLINUX_CANT_PATCH; - } - - - /* CRC-32 of this header while head_crc is 0 */ - wpt = buf + 16; - crc = iso_crc32_gpt((unsigned char *) buf, wpt - buf, 0); - lsb_to_buf(&wpt, crc, 32, 0); - - return ISO_SUCCESS; -} +#endif /* NIX */ /* @@ -627,7 +539,7 @@ int make_isolinux_mbr(int32_t *img_blocks, Ecma119Image *t, uint32_t id, part, nominal_part_size; off_t hd_img_blocks, hd_boot_lba; char *wpt; - uint32_t boot_lba, mbr_id, p_arr_crc, part_start; + uint32_t boot_lba, mbr_id, p_arr_crc, part_start, max_gpt_entries; int head_count, sector_count, ret; int gpt_count = 0, gpt_idx[128], apm_count = 0, gpt_cursor; /* For generating a weak random number */ @@ -729,9 +641,12 @@ int make_isolinux_mbr(int32_t *img_blocks, Ecma119Image *t, /* >>> ISOHYBRID : write primary GPT and compute p_arr_crc */; part_start = 4 + (apm_count + 1) * 4; + /* >>> compute max_gpt_entries from number of APM */ + max_gpt_entries = 128; /* suffices for 6 payload APM entries */ - ret = write_gpt_header_block(t, (char *) buf + 512, - part_start, p_arr_crc); + ret = iso_write_gpt_header_block(t, (uint32_t) *img_blocks, + buf + 512, max_gpt_entries, + part_start, p_arr_crc); if (ret < 0) return ret; } diff --git a/libisofs/messages.c b/libisofs/messages.c index 1ea9f2a..415db11 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -478,6 +478,10 @@ const char *iso_error_to_msg(int errcode) return "Too many Apple Partition Map entries requested"; case ISO_BOOT_APM_OVERLAP: return "Overlapping Apple Partition Map entries requested"; + case ISO_BOOT_TOO_MANY_GPT: + return "Too many GPT entries requested"; + case ISO_BOOT_GPT_OVERLAP: + return "Overlapping GPT entries requested"; default: return "Unknown error"; } diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 83196e8..23bb118 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -723,16 +723,45 @@ int iso_quick_apm_entry(Ecma119Image *t, } +/* Convenience frontend for iso_register_gpt_entry(). + name has to be already encoded as UTF-16LE. +*/ +int iso_quick_gpt_entry(Ecma119Image *t, + uint32_t start_block, uint32_t block_count, + uint8_t type_guid[16], uint8_t partition_guid[16], + uint64_t flags, uint8_t name[72]) +{ + int ret; + struct iso_gpt_partition_request *entry; + + entry = calloc(1, sizeof(struct iso_gpt_partition_request)); + if (entry == NULL) + return ISO_OUT_OF_MEM; + entry->start_block = start_block; + entry->block_count = block_count; + memcpy(entry->type_guid, type_guid, 16); + memcpy(entry->partition_guid, partition_guid, 16); + entry->flags = flags; + memcpy(entry->name, name, 72); + ret = iso_register_gpt_entry(t, entry, 0); + free(entry); + return ret; +} + + /** * Compare the start_sectors of two iso_apm_partition_request */ static -int cmp_apm_partition_request(const void *f1, const void *f2) +int cmp_partition_request(const void *f1, const void *f2) { - struct iso_apm_partition_request *r1, *r2; + struct iso_partition_request { + uint32_t start_block; + uint32_t block_count; + } *r1, *r2; - r1 = *((struct iso_apm_partition_request **) f1); - r2 = *((struct iso_apm_partition_request **) f2); + r1 = *((struct iso_partition_request **) f1); + r2 = *((struct iso_partition_request **) f2); if (r1->start_block < r2->start_block) return -1; if (r1->start_block > r2->start_block) @@ -740,6 +769,7 @@ int cmp_apm_partition_request(const void *f1, const void *f2) return 0; } + /* @param flag bit0= This is the entry in block 1. Its blocks are already in the desired apm_block_size unit. Set block_fac to 1. */ @@ -842,7 +872,7 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) /* Sort and fill gaps */ qsort(t->apm_req, t->apm_req_count, - sizeof(struct iso_apm_partition_request *), cmp_apm_partition_request); + sizeof(struct iso_apm_partition_request *), cmp_partition_request); /* t->apm_req_count will grow during the loop */ up_to = t->apm_req_count + 1; for (i = 1; i < up_to; i++) { @@ -862,7 +892,7 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) } if (part_end > goal) { iso_msg_submit(t->image->id, ISO_BOOT_APM_OVERLAP, 0, - "Program error: APM partitions %d and %d oberlap by %lu blocks", + "Program error: APM partitions %d and %d overlap by %lu blocks", i - 1, i, part_end - goal); return ISO_BOOT_APM_OVERLAP; } @@ -878,7 +908,7 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) /* Merge list of gap partitions with list of already sorted entries */ qsort(t->apm_req, t->apm_req_count, - sizeof(struct iso_apm_partition_request *), cmp_apm_partition_request); + sizeof(struct iso_apm_partition_request *), cmp_partition_request); /* These are the only APM block sizes which can be processed here */ if (t->apm_block_size > 1536) @@ -914,11 +944,266 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) } +static void iso_write_gpt_entry(Ecma119Image *t, uint8_t *buf, + uint8_t type_guid[16], uint8_t part_uuid[16], + uint64_t start_lba, uint64_t end_lba, + uint64_t flags, uint8_t name[72]) +{ + char *wpt; + int i; + + wpt = (char *) buf; + memcpy(wpt, type_guid, 16); + wpt += 16; + for (i = 0; i < 16; i++) + if (part_uuid[i]) + break; + if (i < 16) { + memcpy(wpt, part_uuid, 16); + } else { + iso_random_uuid(t, (uint8_t *) wpt); + } + wpt += 16; + iso_lsb_to_buf(&wpt, start_lba & 0xffffffff, 4, 0); + iso_lsb_to_buf(&wpt, (start_lba >> 32) & 0xffffffff, 4, 0); + iso_lsb_to_buf(&wpt, end_lba & 0xffffffff, 4, 0); + iso_lsb_to_buf(&wpt, (end_lba >> 32) & 0xffffffff, 4, 0); + iso_lsb_to_buf(&wpt, flags & 0xffffffff, 4, 0); + iso_lsb_to_buf(&wpt, (flags >> 32) & 0xffffffff, 4, 0); + memcpy(wpt, name, 72); +} + + +int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, + uint8_t *buf, uint32_t max_entries, + uint32_t part_start, uint32_t p_arr_crc) +{ + static char *sig = "EFI PART"; + static char revision[4] = {0x00, 0x00, 0x01, 0x00}; + char *wpt; + uint32_t crc; + off_t back_lba; + + memset(buf, 0, 128); + wpt = (char *) buf; + + /* >>> Make signature adjustable */ + memcpy(wpt, sig, 8); /* no trailing 0 */ + wpt += 8; + + memcpy(wpt, revision, 4); + wpt += 4; + iso_lsb_to_buf(&wpt, 92, 4, 0); + + /* CRC will be inserted later */ + wpt += 4; + + /* reserved */ + iso_lsb_to_buf(&wpt, 0, 4, 0); + /* Own LBA low 32 */ + iso_lsb_to_buf(&wpt, 1, 4, 0); + /* Own LBA high 32 */ + iso_lsb_to_buf(&wpt, 0, 4, 0); + + /* Backup LBA is 1 hd block before image end */ + back_lba = img_blocks * 4 - 1; + iso_lsb_to_buf(&wpt, (uint32_t) (back_lba & 0xffffffff), 4, 1); + iso_lsb_to_buf(&wpt, (uint32_t) (back_lba >> 32), 4, 1); + + /* First usable LBA for partitions (4 entries per hd block) */ + iso_lsb_to_buf(&wpt, part_start + max_entries / 4, 4, 0); + iso_lsb_to_buf(&wpt, 0, 4, 0); + + /* Last usable LBA for partitions */ + iso_lsb_to_buf(&wpt, + (uint32_t) ((back_lba - max_entries / 4) & 0xffffffff), 4, 1); + iso_lsb_to_buf(&wpt, + (uint32_t) ((back_lba - max_entries / 4) >> 32), 4, 1); + + /* Disk GUID */ + /* >>> Make adjustable */ + iso_random_uuid(t, (uint8_t *) wpt); + wpt += 16; + + /* Partition entries start */ + iso_lsb_to_buf(&wpt, part_start, 4, 0); + iso_lsb_to_buf(&wpt, 0, 4, 0); + + /* Number of partition entries */ + iso_lsb_to_buf(&wpt, max_entries, 4, 0); + + /* Size of a partition entry */ + iso_lsb_to_buf(&wpt, 128, 4, 0); + + /* CRC-32 of the partition array */ + iso_lsb_to_buf(&wpt, p_arr_crc, 4, 0); + + + /* <<< Only for a first test */ + if (wpt - (char *) buf != 92) { + iso_msgs_submit(0, + "program error : write_gpt_header_block : wpt != 92", + 0, "FATAL", 0); + return ISO_ISOLINUX_CANT_PATCH; + } + + /* CRC-32 of this header while head_crc is 0 */ + crc = iso_crc32_gpt((unsigned char *) buf, 128, 0); + wpt = ((char *) buf) + 16; + iso_lsb_to_buf(&wpt, crc, 4, 0); + + return ISO_SUCCESS; +} + + +/* Only for up to 36 characters ISO-8859-1 (or ASCII) input */ +static void poor_man_s_utf_16le(uint8_t gap_name[72]) +{ + int i; + + for (i = strlen((char *) gap_name) - 1; i >= 0; i--) { + gap_name[2 * i] = gap_name[i]; + gap_name[2 * i + 1] = 0; + } +} + + +/* + >>> Need to memorize GPT copy for backup writer at tail +*/ +static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, + uint8_t *buf, uint32_t part_start) +{ + static uint8_t basic_data_uuid[16] = { + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 + }; + + uint32_t p_arr_crc = 0, max_entries, part_end, goal; + uint64_t start_lba, end_lba; + int ret, i, gap_counter = 0, up_to; + struct iso_gpt_partition_request *req; + uint8_t gpt_name[72]; + static uint8_t zero_uuid[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1; + +#ifndef NIX + /* >>> Disable */ + + /* <<< ts B20526 : Dummy mock-up */ + if (t->gpt_req_count <= 0) { + + /* <<< ??? Move to system_area.h and publish as macro ? + Or to make_isohybrid_mbr.c ? + */ + static uint8_t hfs_uuid[16] = { + 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, + 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac + }; + + memset(gpt_name, 0, 72); + gpt_name[0] = 'T'; gpt_name[2] = '1'; + strcpy((char *) gpt_name, "GPT Test 1"); + poor_man_s_utf_16le(gpt_name); + /* + ret = iso_quick_gpt_entry(t, 16, 20, hfs_uuid, zero_uuid, + gpt_flags, gpt_name); + / * >>> Caution: Size 90 causes intentional partition overlap error * / + ret = iso_quick_gpt_entry(t, 30, 90, hfs_uuid, zero_uuid, + gpt_flags, gpt_name); + */ + ret = iso_quick_gpt_entry(t, 30, 40, hfs_uuid, zero_uuid, + gpt_flags, gpt_name); + if (ret < 0) + return ret; + strcpy((char *) gpt_name, "GPT Test 2"); + poor_man_s_utf_16le(gpt_name); + ret = iso_quick_gpt_entry(t, 110, 60, basic_data_uuid, zero_uuid, + gpt_flags, gpt_name); + if (ret < 0) + return ret; + } +#endif /* NIX */ + + + if (t->gpt_req_count == 0) + return 2; + + /* Maximum number of GPT entries of 128 bytes until ISO PVD is reached */ + if (part_start >= 64) + return ISO_ASSERT_FAILURE; /* miscomputation of part_start */ + max_entries = (64 - part_start) * 4; + + /* Sort and fill gaps */ + qsort(t->gpt_req, t->gpt_req_count, + sizeof(struct iso_gpt_partition_request *), cmp_partition_request); + /* t->gpt_req_count will grow during the loop */ + up_to = t->gpt_req_count + 1; + for (i = 0; i < up_to; i++) { + if (i < up_to - 1) + goal = t->gpt_req[i]->start_block; + else + goal = img_blocks; + if (i == 0) { + if (goal <= 16) + continue; + part_end = 16; + } else { + part_end = t->gpt_req[i - 1]->start_block + + t->gpt_req[i - 1]->block_count; + } + if (part_end > goal) { + iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0, + "Program error: GPT partitions %d and %d overlap by %lu blocks", + i - 1, i, part_end - goal); + return ISO_BOOT_GPT_OVERLAP; + } + if (part_end < goal) { + memset(gpt_name, 0, 72); + sprintf((char *) gpt_name, "Gap%d", gap_counter); + poor_man_s_utf_16le(gpt_name); + gap_counter++; + ret = iso_quick_gpt_entry(t, part_end, goal - part_end, + basic_data_uuid, zero_uuid, + gpt_flags, gpt_name); + if (ret < 0) + return ret; + } + } + /* Merge list of gap partitions with list of already sorted entries */ + qsort(t->gpt_req, t->gpt_req_count, + sizeof(struct iso_gpt_partition_request *), cmp_partition_request); + + if ((int) max_entries < t->gpt_req_count) + return ISO_BOOT_TOO_MANY_GPT; + + /* Write the GPT entries to buf */ + for (i = 0; i < t->gpt_req_count; i++) { + req = t->gpt_req[i]; + start_lba = ((uint64_t) req->start_block) * 4; + end_lba = ((uint64_t) start_lba) + req->block_count * 4 - 1; + iso_write_gpt_entry(t, buf + 512 * part_start + 128 * i, + req->type_guid, req->partition_guid, + start_lba, end_lba, req->flags, req->name); + } + for (; i < (int) max_entries; i++) + memset(buf + 512 * part_start + 128 * i, 0, 128); + + p_arr_crc = iso_crc32_gpt((unsigned char *) buf + 512 * part_start, + 128 * max_entries, 0); + ret = iso_write_gpt_header_block(t, img_blocks, buf + 512, max_entries, + part_start, p_arr_crc); + if (ret < 0) + return ret; + return ISO_SUCCESS; +} + + int iso_write_system_area(Ecma119Image *t, uint8_t *buf) { int ret, int_img_blocks, sa_type, i, will_append = 0; int first_partition = 1, last_partition = 4; - uint32_t img_blocks; + uint32_t img_blocks, gpt_part_start; if ((t == NULL) || (buf == NULL)) { return ISO_NULL_POINTER; @@ -963,21 +1248,42 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) } /* If APM entries were submitted to iso_register_apm_entry(), then they - get sprinkled over the system area before any other data get inserted. - Note that Block0 of the APM is not written but is in the responsibility - of the MBR template. Its block size MUST match t->apm_block_size. + get sprinkled over the system area after the system area template was + loaded and before any other data get inserted. + Note that if APM and MBR get combined, then the first 8 bytes of the MBR + template must be replaceable by: + {0x45, 0x52, 0x08 0x00, 0xeb, 0x02, 0xff, 0xff} >>> ts B20526 >>> This does not care for eventual image enlargements in last minute. >>> A sa_type, that does this, will have to adjust the last APM entry >>> if exactness matters. */ + if (t->gpt_req_count > 0 && + t->apm_block_size != 2048 && t->apm_req_count > 0) { + t->apm_block_size = 2048; + iso_msgs_submit(0, + "GPT and APM requested. Had to force APM Block size to 2048.", + 0, "DEBUG", 0); + } ret = iso_write_apm(t, img_blocks, buf); if (ret < 0) { iso_msg_submit(t->image->id, ret, 0, "Cannot set up Apple Partition Map"); return ret; } + gpt_part_start = 0; + if (t->apm_req_count > 0) + gpt_part_start = (t->apm_req_count + 1) * (t->apm_block_size / 512); + if (gpt_part_start < 2) + gpt_part_start = 2; + else if (gpt_part_start >= 64) + return ISO_BOOT_TOO_MANY_GPT; + ret = iso_write_gpt(t, img_blocks, buf, gpt_part_start); + if (ret < 0) { + iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT"); + return ret; + } if (sa_type == 0 && (t->system_area_options & 1)) { /* Write GRUB protective msdos label, i.e. a simple partition table */ @@ -1205,6 +1511,24 @@ int iso_register_apm_entry(Ecma119Image *t, return ISO_SUCCESS; } + +int iso_register_gpt_entry(Ecma119Image *t, + struct iso_gpt_partition_request *req, int flag) +{ + struct iso_gpt_partition_request *entry; + + if (t->gpt_req_count >= ISO_GPT_ENTRIES_MAX) + return ISO_BOOT_TOO_MANY_GPT; + entry = calloc(1, sizeof(struct iso_gpt_partition_request)); + if (entry == NULL) + return ISO_OUT_OF_MEM; + + memcpy(entry, req, sizeof(struct iso_gpt_partition_request)); + t->gpt_req[t->gpt_req_count] = entry; + t->gpt_req_count++; + return ISO_SUCCESS; +} + #ifdef Libisofs_with_uuid_generatE static void swap_uuid(void *u_pt) diff --git a/libisofs/system_area.h b/libisofs/system_area.h index c5b5be3..3b5cbe9 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -126,4 +126,68 @@ void iso_random_uuid(Ecma119Image *t, uint8_t uuid[16]); void iso_random_8byte(Ecma119Image *t, uint8_t result[8]); +/* The parameter struct for production of a single GPT entry. + See also the partial GPT description in doc/boot_sectors.txt. + The list of entries is stored in Ecma119Image.gpt_req. + The GPT header block at byte 0x200 will get produced automatically. + The GPT entries will be stored after the Apple Partition Map, if such + gets generated too. Both partition descriptions must fit into the 32 KiB + of the ISO 9660 System Area. + + GPT can be combined with APM only if (Ecma119Image.apm_block_size > 512). + Otherwise, block 1 of APM and GPT header block would collide. + So Ecma119Image.apm_block_size is set automatically to 2048 if at least + one GPT entry is requested. (One could try 1024 ...). +*/ +struct iso_gpt_partition_request { + + /* Always given in blocks of 2 KiB. + Written to the ISO image in blocks of 512. + */ + uint32_t start_block; + uint32_t block_count; + + /* The registered GUID which defines the partition type */ + uint8_t type_guid[16]; + + /* An individual GUID which shall be unique to the partition. + If the caller submits 0...0 then a (weak) random uuid will be generated. + */ + uint8_t partition_guid[16]; + + /* bit0= "System Partition" Do not alter, + bit2= Legacy BIOS bootable (MBR partition type 0x80) + bit60= read-only + */ + uint64_t flags; + + /* Fill with text encoded as UTF-16LE. + All 72 bytes get copied to the system area. + Take care to pad up short strings by 0. + */ + uint8_t name[72]; +}; + +/* Copies the content of req and registers it in t.gpt_req[]. + I.e. after the call the submitted storage of req can be disposed or re-used. + Submit 0 as value flag. +*/ +int iso_register_gpt_entry(Ecma119Image *t, + struct iso_gpt_partition_request *req, int flag); + +/* Convenience frontend for iso_register_gpt_entry(). + name has to be already encoded as UTF-16LE. +*/ +int iso_quick_gpt_entry(Ecma119Image *t, + uint32_t start_block, uint32_t block_count, + uint8_t type_guid[16], uint8_t partition_guid[16], + uint64_t flags, uint8_t name[72]); + + +/* Internal helper that will be used by system_area.c and make_isohybrid_mbr.c +*/ +int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, + uint8_t *buf, uint32_t max_entries, + uint32_t part_start, uint32_t p_arr_crc); + #endif /* SYSTEM_AREA_H_ */ diff --git a/libisofs/util.c b/libisofs/util.c index 3176a82..df5273b 100644 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -1355,6 +1355,18 @@ void iso_bb(uint8_t *buf, uint32_t num, int bytes) iso_msb(buf+bytes, num, bytes); } +/* An alternative to iso_lsb() which advances the write pointer +*/ +int iso_lsb_to_buf(char **wpt, uint32_t value, int bytes, int flag) +{ + int b, bits; + + bits = bytes * 8; + for (b = 0; b < bits; b += 8) + *((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff; + return (1); +} + uint32_t iso_read_lsb(const uint8_t *buf, int bytes) { int i; diff --git a/libisofs/util.h b/libisofs/util.h index 987344c..473ae6b 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -232,6 +232,10 @@ void iso_lsb(uint8_t *buf, uint32_t num, int bytes); void iso_msb(uint8_t *buf, uint32_t num, int bytes); void iso_bb(uint8_t *buf, uint32_t num, int bytes); +/* An alternative to iso_lsb() which advances the write pointer +*/ +int iso_lsb_to_buf(char **wpt, uint32_t value, int bytes, int flag); + uint32_t iso_read_lsb(const uint8_t *buf, int bytes); uint32_t iso_read_msb(const uint8_t *buf, int bytes);