From 08978967133c1d0b1d09ef2a01e6054fb0e3a369 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Mon, 11 Jun 2012 13:05:46 +0200 Subject: [PATCH] Inner API for requesting MBR partition table entries. --- libisofs/ecma119.c | 5 ++ libisofs/ecma119.h | 10 ++++ libisofs/libisofs.h | 6 +++ libisofs/messages.c | 4 ++ libisofs/system_area.c | 114 +++++++++++++++++++++++++++++++++++++++-- libisofs/system_area.h | 44 ++++++++++++++++ 6 files changed, 180 insertions(+), 3 deletions(-) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 648bd30..0499579 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->mbr_req_count; i++) + if (t->mbr_req[i] != NULL) + free(t->mbr_req[i]); for (i = 0; (int) i < t->gpt_req_count; i++) if (t->gpt_req[i] != NULL) free(t->gpt_req[i]); @@ -1891,6 +1894,8 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->apm_block_size = 512; for (i = 0; i < ISO_APM_ENTRIES_MAX; i++) target->apm_req[i] = NULL; + for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) + target->mbr_req[i] = NULL; for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++) target->gpt_req[i] = NULL; target->gpt_part_start = 0; diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index f6a4164..36a4319 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -76,6 +76,10 @@ */ #define ISO_APM_ENTRIES_MAX 63 +/* The maximum number of MBR partition table entries. +*/ +#define ISO_MBR_ENTRIES_MAX 4 + /* 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. @@ -815,6 +819,12 @@ struct ecma119_image /* 512 by default. May be changed to 2048 before writer thread starts. */ int apm_block_size; + /* MBR partition table description. To be composed during IsoImageWriter + method ->compute_data_blocks() by calling iso_register_mbr_entry(). + */ + struct iso_mbr_partition_request *mbr_req[ISO_MBR_ENTRIES_MAX]; + int mbr_req_count; + /* GPT description. To be composed during IsoImageWriter method ->compute_data_blocks() by calling iso_register_gpt_entry(). Make sure that the composing writers get registered before the diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 96fd351..84a5a05 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -7251,6 +7251,12 @@ int iso_image_hfsplus_get_blessed(IsoImage *img, IsoNode ***blessed_nodes, /** Overlapping GPT entries requested (FAILURE, HIGH, -386) */ #define ISO_BOOT_GPT_OVERLAP 0xE830FE7E +/** Too many MBR partition entries requested (FAILURE, HIGH, -387) */ +#define ISO_BOOT_TOO_MANY_MBR 0xE830FE7D + +/** Overlapping MBR entries requested (FAILURE, HIGH, -388) */ +#define ISO_BOOT_MBR_OVERLAP 0xE830FE7C + /* Internal developer note: diff --git a/libisofs/messages.c b/libisofs/messages.c index 415db11..8475900 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -482,6 +482,10 @@ const char *iso_error_to_msg(int errcode) return "Too many GPT entries requested"; case ISO_BOOT_GPT_OVERLAP: return "Overlapping GPT entries requested"; + case ISO_BOOT_TOO_MANY_MBR: + return "Too many MBR partition entries requested"; + case ISO_BOOT_MBR_OVERLAP: + return "Overlapping MBR entries requested"; default: return "Unknown error"; } diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 29e0a94..6d2070a 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -750,6 +750,26 @@ int iso_quick_gpt_entry(Ecma119Image *t, } +int iso_quick_mbr_entry(Ecma119Image *t, + uint32_t start_block, uint32_t block_count, + uint8_t type_byte, uint8_t status_byte) +{ + int ret; + struct iso_mbr_partition_request *entry; + + entry = calloc(1, sizeof(struct iso_mbr_partition_request)); + if (entry == NULL) + return ISO_OUT_OF_MEM; + entry->start_block = start_block; + entry->block_count = block_count; + entry->type_byte = type_byte; + entry->status_byte = status_byte; + ret = iso_register_mbr_entry(t, entry, 0); + free(entry); + return ret; +} + + /** * Compare the start_sectors of two iso_apm_partition_request */ @@ -1000,6 +1020,72 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) } +static int iso_write_mbr(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) +{ + int i, ret; + +#ifdef NIX + /* Disabled */ + + /* <<< Dummy mock-up */ + if (t->mbr_req_count <= 0) { + ret = iso_quick_mbr_entry(t, 0, 0, 0xee, 0); + if (ret < 0) + return ret; + ret = iso_quick_mbr_entry(t, 100, 0, 0x0c, 0x80); + if (ret < 0) + return ret; + } +#endif /* NIX */ + + if (t->mbr_req_count <= 0) + return 2; + + /* >>> Sort by start block ? */ + + /* Adjust partition ends */ + for (i = 0; i < t->mbr_req_count; i++) { + if (i > 0) { + if (t->mbr_req[i]->start_block <= t->mbr_req[i - 1]->start_block && + !(t->mbr_req[i]->block_count == 0 && + t->mbr_req[i]->start_block == + t->mbr_req[i - 1]->start_block)) + return ISO_BOOT_MBR_OVERLAP; + if (t->mbr_req[i - 1]->start_block + + t->mbr_req[i - 1]->block_count > t->mbr_req[i]->start_block) + return ISO_BOOT_MBR_OVERLAP; + } + if (t->mbr_req[i]->block_count != 0) + continue; + if (i < t->mbr_req_count - 1) + t->mbr_req[i]->block_count = t->mbr_req[i + 1]->start_block - + t->mbr_req[i]->start_block; + else + t->mbr_req[i]->block_count = img_blocks - + t->mbr_req[i]->start_block; + } + + /* >>> Permutate ? */ + + /* Write partition slots */ + for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) { + memset(buf + 446 + i * 16, 0, 16); + if (i >= t->mbr_req_count) + continue; + if (t->mbr_req[i]->block_count == 0) + continue; + ret = write_mbr_partition_entry(i + 1, (int) t->mbr_req[i]->type_byte, + t->mbr_req[i]->start_block, t->mbr_req[i]->block_count, + t->partition_secs_per_head, t->partition_heads_per_cyl, + buf, 0); + if (ret < 0) + return ret; + buf[446 + i * 16] = t->mbr_req[i]->status_byte; + } + return ISO_SUCCESS; +} + + 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, @@ -1205,9 +1291,6 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) t->gpt_part_start, p_arr_crc); if (ret < 0) return ret; - - /* >>> Memorize GPT copy for backup writer at tail */; - return ISO_SUCCESS; } @@ -1278,6 +1361,12 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) "Cannot set up Apple Partition Map"); return ret; } + ret = iso_write_mbr(t, img_blocks, buf); + if (ret < 0) { + iso_msg_submit(t->image->id, ret, 0, + "Cannot set up MBR partition table"); + return ret; + } ret = iso_write_gpt(t, img_blocks, buf); if (ret < 0) { iso_msg_submit(t->image->id, ret, 0, "Cannot set up GPT"); @@ -1511,6 +1600,24 @@ int iso_register_apm_entry(Ecma119Image *t, } +int iso_register_mbr_entry(Ecma119Image *t, + struct iso_mbr_partition_request *req, int flag) +{ + struct iso_mbr_partition_request *entry; + + if (t->mbr_req_count >= ISO_MBR_ENTRIES_MAX) + return ISO_BOOT_TOO_MANY_MBR; + entry = calloc(1, sizeof(struct iso_mbr_partition_request)); + if (entry == NULL) + return ISO_OUT_OF_MEM; + + memcpy(entry, req, sizeof(struct iso_mbr_partition_request)); + t->mbr_req[t->mbr_req_count] = entry; + t->mbr_req_count++; + return ISO_SUCCESS; +} + + int iso_register_gpt_entry(Ecma119Image *t, struct iso_gpt_partition_request *req, int flag) { @@ -1738,6 +1845,7 @@ static int gpt_tail_writer_compute_data_blocks(IsoImageWriter *writer) t->curblock++; /* The ISO block number after the backup GPT header */ t->gpt_backup_end = t->curblock; + return ISO_SUCCESS; } diff --git a/libisofs/system_area.h b/libisofs/system_area.h index c5c11dc..37c970e 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -65,6 +65,50 @@ int iso_read_mipsel_elf(Ecma119Image *t, int flag); int iso_compute_append_partitions(Ecma119Image *t, int flag); +/* The parameter struct for production of a single MBR partition entry. + See also the description of MBR in doc/boot_sectors.txt. + No sorting and gap filling is done before the System Area gets written. + Requested entries with block_count == 0 get expanded to the start of + the next requested entry resp. to image end, if no entry follows. + start_block of a follwing entry must be at least a high as the sum of + start_block and block_count of the previous entry. + Empty requested entries will be represented as 16 bytes of 0. +*/ +struct iso_mbr_partition_request { + + /* Always given in blocks of 2 KiB */ + uint32_t start_block; + + /* A block count of 0 means that the partition reaches up to the start of + the next one. + */ + uint32_t block_count; + + /* Partition type */ + uint8_t type_byte; + + /* 0x80 = bootable */ + uint8_t status_byte; + + /* >>> Is a permutation of entries needed ? */ + +}; + +/* Copies the content of req and registers it in t.mbr_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_mbr_entry(Ecma119Image *t, + struct iso_mbr_partition_request *req, int flag); + +/* Convenience frontend for iso_register_mbr_entry(). + name and type are 0-terminated strings, which may get silently truncated. +*/ +int iso_quick_mbr_entry(Ecma119Image *t, + uint32_t start_block, uint32_t block_count, + uint8_t type_byte, uint8_t status_byte); + + /* The parameter struct for production of a single Apple Partition Map entry. See also the partial APM description in doc/boot_sectors.txt. The list of entries is stored in Ecma119Image.apm_req.