diff --git a/doc/boot_sectors.txt b/doc/boot_sectors.txt index d22f376..b1503ea 100644 --- a/doc/boot_sectors.txt +++ b/doc/boot_sectors.txt @@ -895,7 +895,7 @@ Sources: Mail conversations with Vladimir Serbinenko. -PReP boots via a MBR partition containing only raw ELF and having type 0x42. +PReP boots via a MBR partition containing only raw ELF and having type 0x41. ------------------------------------------------------------------------------ @@ -1006,16 +1006,16 @@ firmware. It disobeys some of the prescriptions in the previous chapter. 446 - 461 | mbr_entry1 | Partition table entry 1 describing the size of | | the ISO image plus the backup GPT, padded up to | | the next full MiB. - 462 - 477 | mbr_entry2 | Entry 2 describing the UEFI VFAT boot image. + 462 - 477 | mbr_entry2 | Entry 2 describing the EFI VFAT boot image. 478 - 493 | mbr_entry3 | Entry 3 describing the HFS+ boot image. | | 512 - 1023 | gpt_head | GPT header describing the GPT partition array. 1024 - 2047 | unused | 2048 - 4095 | apm_entry1 | APM entry 1 describing APM entries 1 to 3. - 4096 - 6143 | apm_entry2 | APM entry 2 describing the UEFI VFAT boot image. + 4096 - 6143 | apm_entry2 | APM entry 2 describing the EFI VFAT boot image. 6144 - 8195 | apm_entry3 | APM entry 3 describing the HFS+ boot image. 8192 - 8319 | gpt_entry1 | GPT partition entry 1 for the ISO image size. - 8320 - 8447 | gpt_entry2 | GPT partition entry 2 for UEFI VFAT boot image, + 8320 - 8447 | gpt_entry2 | GPT partition entry 2 for EFI VFAT boot image, 8448 - 8575 | gpt_entry3 | GPT partition entry 3 for the HFS+ boot image. 8576 - 24575 | gtp_empty | Empty GPT partition entries 4 to 128. 24576 - 32767 | unused | @@ -1376,7 +1376,7 @@ System Area may contain simultaneously: MBR Partitions: 0xee from 0 to PREP-1, protective partition, announcing presence of GPT - 0x42 from PREP to HFAT-1, PreP partition + 0x41 from PREP to HFAT-1, PreP partition 0x0c from HFAT to END-1, FAT partition, bootable bit on 0x00 Empty partition diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 15bc355..3ed7514 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1918,12 +1918,17 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) iso_node_ref(target->hfsplus_blessed[i]); } target->apm_block_size = 512; + target->apm_req_count = 0; + target->apm_req_flags = 0; 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; + target->mbr_req_count = 0; for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++) target->gpt_req[i] = NULL; + target->gpt_req_count = 0; + target->gpt_req_flags = 0; target->gpt_part_start = 0; target->gpt_backup_end = 0; target->gpt_backup_size = 0; diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index e1daeaa..16752af 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -828,6 +828,8 @@ struct ecma119_image int apm_req_count; /* 512 by default. May be changed to 2048 before writer thread starts. */ int apm_block_size; + /* bit1= Do not fill gaps in Apple Partition Map */ + int apm_req_flags; /* MBR partition table description. To be composed during IsoImageWriter method ->compute_data_blocks() by calling iso_register_mbr_entry(). @@ -845,6 +847,8 @@ struct ecma119_image */ struct iso_gpt_partition_request *gpt_req[ISO_GPT_ENTRIES_MAX]; int gpt_req_count; + /* bit0= GPT partitions may overlap */ + int gpt_req_flags; char *efi_boot_partition; uint32_t efi_boot_part_size; diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 5c70968..c6422c7 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -3424,47 +3424,52 @@ int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag); * @param options * bitmask style flag. The following values are defined: * - * bit 0 -> 1 to patch the boot info table of the boot image. - * 1 does the same as mkisofs option -boot-info-table. - * Needed for ISOLINUX or GRUB boot images with platform ID 0. - * The table is located at byte 8 of the boot image file. - * Its size is 56 bytes. - * The original boot image file on disk will not be modified. + * bit0= Patch the boot info table of the boot image. + * This does the same as mkisofs option -boot-info-table. + * Needed for ISOLINUX or GRUB boot images with platform ID 0. + * The table is located at byte 8 of the boot image file. + * Its size is 56 bytes. + * The original boot image file on disk will not be modified. * - * One may use el_torito_seems_boot_info_table() for a - * qualified guess whether a boot info table is present in - * the boot image. If the result is 1 then it should get bit0 - * set if its content gets copied to a new LBA. + * One may use el_torito_seems_boot_info_table() for a + * qualified guess whether a boot info table is present in + * the boot image. If the result is 1 then it should get bit0 + * set if its content gets copied to a new LBA. * - * bit 1 -> 1 to generate a ISOLINUX isohybrid image with MBR. - * ---------------------------------------------------------- - * @deprecated since 31 Mar 2010: - * The author of syslinux, H. Peter Anvin requested that this - * feature shall not be used any more. He intends to cease - * support for the MBR template that is included in libisofs. - * ---------------------------------------------------------- - * A hybrid image is a boot image that boots from either - * CD/DVD media or from disk-like media, e.g. USB stick. - * For that you need isolinux.bin from SYSLINUX 3.72 or later. - * IMPORTANT: The application has to take care that the image - * on media gets padded up to the next full MB. - >>> unless a GPT gets created - - * >>> *** Under construction. *** Do not use yet: - * >>> bit2-7= Mentioning in isohybrid GPT - * >>> 0= do not mention in GPT - * >>> 1= mention as EFI partition - * >>> @since 1.2.4 - * >>> 2= Mention as HFS+ partition - * >>> @since 1.2.4 - * >>> Primary GPT and backup GPT get written if at least one - * >>> ElToritoBootImage shall be mentioned - * >>> bit8= Mention in isohybrid Apple partition map - * >>> APM get written if at least one ElToritoBootImage shall be - * >>> mentioned. The ISOLINUX MBR must look suitable or else an error - * >>> event will happen at image generation time. - * >>> @since 1.2.4 - + * bit1= Generate a ISOLINUX isohybrid image with MBR. + * ---------------------------------------------------------- + * @deprecated since 31 Mar 2010: + * The author of syslinux, H. Peter Anvin requested that this + * feature shall not be used any more. He intends to cease + * support for the MBR template that is included in libisofs. + * ---------------------------------------------------------- + * A hybrid image is a boot image that boots from either + * CD/DVD media or from disk-like media, e.g. USB stick. + * For that you need isolinux.bin from SYSLINUX 3.72 or later. + * IMPORTANT: The application has to take care that the image + * on media gets padded up to the next full MB. + * Under seiveral circumstances it might get aligned + * automatically. But there is no warranty. + * bit2-7= Mentioning in isohybrid GPT + * 0= Do not mention in GPT + * 1= Mention as Basic Data partition. + * This cannot be combined with GPT partitions as of + * iso_write_opts_set_efi_bootp() + * >>> ts B20620 : and not with iso_write_opts_set_hfsplus() + * >>> if it produces GPT entries + * @since 1.2.4 + * 2= Mention as HFS+ partition. + * This cannot be combined with HFS+ production by + * iso_write_opts_set_hfsplus(). + * @since 1.2.4 + * Primary GPT and backup GPT get written if at least one + * ElToritoBootImage shall be mentioned + * @since 1.2.4 + * bit8= Mention in isohybrid Apple partition map + * APM get written if at least one ElToritoBootImage shall be + * mentioned. The ISOLINUX MBR must look suitable or else an error + * event will happen at image generation time. + * @since 1.2.4 * @param flag * Reserved for future usage, set to 0. * @return diff --git a/libisofs/make_isohybrid_mbr.c b/libisofs/make_isohybrid_mbr.c index 454d3ca..52691d6 100644 --- a/libisofs/make_isohybrid_mbr.c +++ b/libisofs/make_isohybrid_mbr.c @@ -358,7 +358,10 @@ Main: */ -/* >>> ISOHYBRID : mention the new stuff learned from mjg and isohybrid.c */ +/* The new stuff about GPT and APM which was learned from Matthew Garret + and isohybrid.c is described in doc/boot_sectord.txt chapter + "SYSLINUX isohybrid for MBR, UEFI and x86-Mac" +*/ static @@ -385,11 +388,29 @@ int lba512chs_to_buf(char **wpt, off_t lba, int head_count, int sector_count) } -/* Find out whether GPT and APM are desired */ -static int assess_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], - int *apm_count) +/* Find out whether GPT and APM are desired + flag bit0 = register APM and GPT requests in Ecma119Image +*/ +int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], + int *apm_count, int flag) { - int i, ilx_opts; + int i, ilx_opts, j, ret; + uint32_t block_count; + 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 uint8_t basic_data_uuid[16] = { + 0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44, + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 + }; + static uint8_t hfs_uuid[16] = { + 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, + 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac + }; + uint8_t *uuid; + static uint64_t gpt_flags = (((uint64_t) 1) << 60) | 1; + + *gpt_count = 0; + *apm_count = 0; for (i = 0; i < t->catalog->num_bootimages; i++) { ilx_opts = t->catalog->bootimages[i]->isolinux_options; @@ -397,15 +418,57 @@ static int assess_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], if (*gpt_count < 128) gpt_idx[*gpt_count]= i; (*gpt_count)++; + if ((flag & 1) && t->bootsrc[i] != NULL) { + /* Register GPT entry */ + memset(gpt_name, 0, 72); + sprintf((char *) gpt_name, "ISOHybrid%d", *gpt_count); + iso_ascii_utf_16le(gpt_name); + if (((ilx_opts >> 2) & 63) == 2) + uuid = hfs_uuid; + else + uuid = basic_data_uuid; + block_count = 0; + for (j = 0; j < t->bootsrc[i]->nsections; j++) + block_count += t->bootsrc[i]->sections[j].size / 2048; + ret = iso_quick_gpt_entry( + t, t->bootsrc[i]->sections[0].block, + block_count, uuid, zero_uuid, gpt_flags, + (uint8_t *) gpt_name); + if (ret < 0) + return ret; + } } - if (ilx_opts & 256) + if (ilx_opts & 256) { (*apm_count)++; + if ((flag & 1) && t->bootsrc[i] != NULL) { + /* Register APM entry */ + block_count = 0; + for (j = 0; j < t->bootsrc[i]->nsections; j++) + block_count += t->bootsrc[i]->sections[j].size / 2048; + ret = iso_quick_apm_entry(t, t->bootsrc[i]->sections[0].block, + block_count, "EFI", "Apple_HFS"); + if (ret < 0) + return ret; + /* Prevent gap filling */ + t->apm_req_flags |= 2; + t->apm_block_size = 2048; + } + } } - if (*apm_count > 6) { - iso_msgs_submit(0, - "Too many entries desired for Apple Partition Map. (max 6)", - 0, "FAILURE", 0); - return ISO_BOOT_TOO_MANY_APM; + if ((flag & 1) && *gpt_count > 0) { + /* Register overall GPT partition */ + memset(gpt_name, 0, 72); + sprintf((char *) gpt_name, "ISOHybrid"); + iso_ascii_utf_16le(gpt_name); + /* Let it be open ended. iso_write_gpt() will truncate it as needed. */ + block_count = 0xffffffff; + ret = iso_quick_gpt_entry(t, (uint32_t) 0, block_count, + basic_data_uuid, zero_uuid, gpt_flags, + (uint8_t *) gpt_name); + if (ret < 0) + return ret; + /* Remove ban on GPT overlapping */ + t->gpt_req_flags |= 1; } return ISO_SUCCESS; } @@ -432,6 +495,12 @@ static int insert_apm_head(uint8_t *buf, int apm_count) for (i = 0; i < 32; i++) if(buf[i] != apm_mbr_start[i]) break; + if (i < 32) { + /* Maybe it is already patched by apm_head ? */ + for (i = 0; i < 32; i++) + if(buf[i] != apm_head[i]) + break; + } if (i < 32) { iso_msgs_submit(0, "MBR template file seems not prepared for Apple Partition Map.", @@ -445,7 +514,7 @@ static int insert_apm_head(uint8_t *buf, int apm_count) } -/* Describe the first three GPT boot images as MBR partitions */ +/* Describe GPT boot images as MBR partitions */ static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt, int gpt_idx[128], int *gpt_cursor) { @@ -480,55 +549,6 @@ static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt, } -#ifdef NIX - -static int write_gpt_array(Ecma119Image *t, char *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 - }; - static uint8_t hfs_uuid[16] = { - 0x00, 0x53, 0x46, 0x48, 0x00, 0x00, 0xaa, 0x11, - 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac - }; - uint8_t *uuid; - int i, ilx_opts; - off_t start_lba, end_lba; - - /* >>> 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]) - */; - - /* >>> Each marked boot image gets its entry */; - for (i= 0; i < t->catalog->num_bootimages; i++) { - ilx_opts= (t->catalog->bootimages[i]->isolinux_options >> 2) & 63; - if (ilx_opts == 1) - uuid = basic_data_uuid; - else if (ilx_opts == 1) - uuid = hfs_uuid; - else - continue; - - /* >>> iso_quick_gpt_entry() */ - - } - - /* >>> */; - - return ISO_SUCCESS; -} - -#endif /* NIX */ - - /* * @param flag bit0= make own random MBR Id from current time */ @@ -539,7 +559,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 = 0, part_start, max_gpt_entries; + uint32_t boot_lba, mbr_id; int head_count, sector_count, ret; int gpt_count = 0, gpt_idx[128], apm_count = 0, gpt_cursor; /* For generating a weak random number */ @@ -553,25 +573,22 @@ int make_isolinux_mbr(int32_t *img_blocks, Ecma119Image *t, head_count = t->partition_heads_per_cyl; sector_count = t->partition_secs_per_head; - ret = assess_gpt_apm(t, &gpt_count, gpt_idx, &apm_count); - if (ret < 0) - return ret; - ret = insert_apm_head(buf, apm_count); + ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0); if (ret < 0) return ret; + /* The rest of APM has already been written by iso_write_apm(). + But the isohybrid APM head differs from the hfsplus_writer APM head. + */ + ret = insert_apm_head(buf, apm_count); + if (ret < 0) + return ret; /* Padding of image_size to a multiple of sector_count*head_count happens already at compute time and is implemented by an appropriate increase of Ecma119Image->tail_blocks. */ - if (gpt_count) { - - /* >>> ISOHYBRID : need to make sure that backup GPT fits into tail */; - - } - wpt = (char *) buf + 432; /* write qword boot_lba # Offset 432 @@ -636,27 +653,6 @@ int make_isolinux_mbr(int32_t *img_blocks, Ecma119Image *t, */ lsb_to_buf(&wpt, 0xaa55, 16, 0); - if (gpt_count) { - - /* >>> 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 = 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; - } - - if (apm_count) { - - /* >>> ISOHYBRID : write APM entry blocks (2K) */; - - } - return(1); } diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 50addc6..f6019c2 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -58,6 +58,13 @@ int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t, int part_offset, int part_number, int fs_type, uint8_t *buf, int flag); +/* Find out whether GPT and APM are desired by isohybrid + flag bit0 = register APM and GPT requests in Ecma119Image +*/ +int assess_isohybrid_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], + int *apm_count, int flag); + + static int precompute_gpt(Ecma119Image *t); @@ -804,6 +811,12 @@ int cmp_partition_request(const void *f1, const void *f2) return -1; if (r1->start_block > r2->start_block) return 1; + + /* In case of overlapping the largest partition shall be first */ + if (r1->block_count > r2->block_count) + return -1; + if (r1->block_count < r2->block_count) + return 1; return 0; } @@ -919,7 +932,11 @@ static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) "Program error: APM partitions %d and %d overlap by %lu blocks", i - 1, i, part_end - goal); return ISO_BOOT_APM_OVERLAP; - } + } + + if (t->apm_req_flags & 2) /* Do not fill gaps */ + continue; + if (part_end < goal || i == up_to - 1) { /* Always add a final entry */ sprintf(gap_name, "Gap%d", gap_counter); gap_counter++; @@ -931,8 +948,9 @@ static int fill_apm_gaps(Ecma119Image *t, uint32_t img_blocks) } /* 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_partition_request); + if (!(t->apm_req_flags & 2)) /* No gaps were filled */ + qsort(t->apm_req, t->apm_req_count, + sizeof(struct iso_apm_partition_request *), cmp_partition_request); return 1; } @@ -968,7 +986,10 @@ static int rectify_apm(Ecma119Image *t) } -static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) +/* flag bit0= do not write Block0 +*/ +static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf, + int flag) { int i, ret; /* This is a micro mick-up of an APM Block0 @@ -1001,15 +1022,18 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) if (t->apm_req_count <= 0) return 2; - /* Adjust last partition to img_size. This size was not known when the - number of APM partitions was determined. - */ - t->apm_req[t->apm_req_count - 1]->block_count = - img_blocks - t->apm_req[t->apm_req_count - 1]->start_block; - /* If it is still empty, remove it */ - if(t->apm_req[t->apm_req_count - 1]->block_count == 0) { - free(t->apm_req[t->apm_req_count - 1]); - t->apm_req_count--; + if (!(t->apm_req_flags & 2)) { + /* Gaps have been filled. Care for the final one */ + /* Adjust last partition to img_size. This size was not known when the + number of APM partitions was determined. + */ + t->apm_req[t->apm_req_count - 1]->block_count = + img_blocks - t->apm_req[t->apm_req_count - 1]->start_block; + /* If it is still empty, remove it */ + if(t->apm_req[t->apm_req_count - 1]->block_count == 0) { + free(t->apm_req[t->apm_req_count - 1]); + t->apm_req_count--; + } } /* If block size is larger than 512, then not all 63 entries will fit */ @@ -1020,10 +1044,14 @@ static int iso_write_apm(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) t->apm_req[0]->start_block = 1; t->apm_req[0]->block_count = t->apm_req_count; - /* Write APM block 0. Very sparse, not to overwrite much of possible MBR.*/ - memcpy(buf, block0_template, 8); - buf[2]= (t->apm_block_size >> 8) & 0xff; - buf[3]= 0; + if (!(flag & 1)) { + /* Write APM block 0. Very sparse, not to overwrite much of + possible MBR. + */ + memcpy(buf, block0_template, 8); + buf[2]= (t->apm_block_size >> 8) & 0xff; + buf[3]= 0; + } /* Write APM Block 1 to t->apm_req_count */ for (i = 0; i < t->apm_req_count; i++) { @@ -1217,7 +1245,7 @@ int iso_write_gpt_header_block(Ecma119Image *t, uint32_t img_blocks, /* Only for up to 36 characters ISO-8859-1 (or ASCII) input */ -static void poor_man_s_utf_16le(uint8_t gap_name[72]) +void iso_ascii_utf_16le(uint8_t gap_name[72]) { int i; @@ -1235,7 +1263,7 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 }; - uint32_t p_arr_crc = 0, part_end, goal; + uint32_t p_arr_crc = 0, part_end, goal, next_end; uint64_t start_lba, end_lba; int ret, i, gap_counter = 0, up_to; struct iso_gpt_partition_request *req; @@ -1251,29 +1279,35 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) 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; + goal = 0; + part_end = 0; for (i = 0; i < up_to; i++) { - if (i < up_to - 1) + if (i < up_to - 1) { goal = t->gpt_req[i]->start_block; - else + } else { goal = img_blocks; + } if (i == 0) { if (goal <= 16) continue; - part_end = 16; + next_end = 16; } else { - part_end = t->gpt_req[i - 1]->start_block + + next_end = t->gpt_req[i - 1]->start_block + t->gpt_req[i - 1]->block_count; } + if (next_end > part_end) + part_end = next_end; if (part_end > goal) { - iso_msg_submit(t->image->id, ISO_BOOT_GPT_OVERLAP, 0, + if (!(t->gpt_req_flags & 1)) { + 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) { + i - 1, i, part_end - goal); + return ISO_BOOT_GPT_OVERLAP; + } + } else if (part_end < goal) { memset(gpt_name, 0, 72); sprintf((char *) gpt_name, "Gap%d", gap_counter); - poor_man_s_utf_16le(gpt_name); + iso_ascii_utf_16le(gpt_name); gap_counter++; ret = iso_quick_gpt_entry(t, part_end, goal - part_end, basic_data_uuid, zero_uuid, @@ -1293,7 +1327,10 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *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; + end_lba = ((uint64_t) req->start_block) + req->block_count; + if (end_lba > t->gpt_backup_end - t->gpt_backup_size) + end_lba = t->gpt_backup_end - t->gpt_backup_size; + end_lba = end_lba * 4 - 1; iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i, req->type_guid, req->partition_guid, start_lba, end_lba, req->flags, req->name); @@ -1314,8 +1351,9 @@ static int iso_write_gpt(Ecma119Image *t, uint32_t img_blocks, uint8_t *buf) 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; + int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0; + int first_partition = 1, last_partition = 4, apm_flag, part_type; + int gpt_count = 0, gpt_idx[128], apm_count = 0; uint32_t img_blocks; if ((t == NULL) || (buf == NULL)) { @@ -1372,7 +1410,27 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) >>> A sa_type, that does this, will have to adjust the last APM entry >>> if exactness matters. */ - ret = iso_write_apm(t, img_blocks, buf); + + apm_flag = 0; + if (sa_type == 0 && (t->system_area_options & 3) == 2) { + do_isohybrid = 1; + + /* >>> Coordinate with partprepend writer */ + /* <<< provisory trap */ + if (t->mbr_req_count > 0) + return ISO_BOOT_MBR_OVERLAP; + + /* If own APM is desired, set flag bit0 to prevent writing of Block0 + which would interfere with the own Block0 of isohybrid. + */ + ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0); + if (ret < 0) + return ret; + if (apm_count > 0) + apm_flag |= 1; + } + + ret = iso_write_apm(t, img_blocks, buf, apm_flag); if (ret < 0) { iso_msg_submit(t->image->id, ret, 0, "Cannot set up Apple Partition Map"); @@ -1401,7 +1459,7 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) if (ret != ISO_SUCCESS) /* error should never happen */ return ISO_ASSERT_FAILURE; } - } else if(sa_type == 0 && (t->system_area_options & 2)) { + } else if (do_isohybrid) { /* Patch externally provided system area as isohybrid MBR */ if (t->catalog == NULL || t->system_area_data == NULL) { /* isohybrid makes only sense together with ISOLINUX boot image @@ -1410,20 +1468,17 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) return ISO_ISOLINUX_CANT_PATCH; } - /* >>> ISOHYBRID : need option to set fs_type of MBR partition 1 - (here it is 0x17) */; + if (gpt_count > 0 || apm_count > 0) + part_type = 0x00; + else + part_type = 0x17; /* >>> ??? Why is partition_offset 0 here ? It gets adjusted later by iso_offset_partition_start() Would it harm to give the real offset here ? */; - /* >>> Coordinate with partprepend writer */ - /* <<< provisory trap */ - if (t->mbr_req_count > 0) - return ISO_BOOT_MBR_OVERLAP; - - ret = make_isolinux_mbr(&img_blocks, t, 0, 1, 0x17, buf, 1); + ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf, 1); if (ret != 1) return ret; } else if (sa_type == 1) { @@ -1799,15 +1854,41 @@ void iso_random_8byte(Ecma119Image *t, uint8_t result[8]) } -/* Probably already called by tail writer */ +/* Probably already called by tail_writer_compute_data_blocks via + iso_align_isohybrid +*/ static int precompute_gpt(Ecma119Image *t) { uint32_t gpt_part_start; - int ret; + int ret, sa_type; + int gpt_count, gpt_idx[128], apm_count; /* Avoid repetition by gpt_tail_writer_compute_data_blocks */ t->gpt_is_computed = 1; + + /* Assess APM and GPT requests of isohybrid */ + sa_type = (t->system_area_options >> 2) & 0x3f; + if (sa_type == 0 && (t->system_area_options & 3) == 2) { + + /* >>> ISOHYBRID : + Shall isohybrid be combinable with other APM and GPT requesters ? + */; + /* <<< provisorily: Not compatible */ + ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0); + if (ret < 0) + return ret; + if (t->gpt_req_count > 0 && gpt_count > 0) + return ISO_BOOT_GPT_OVERLAP; + if (t->apm_req_count > 0 && apm_count > 0) + return ISO_BOOT_APM_OVERLAP; + /* Register the GPT and APM partition entries */ + ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 1); + if (ret < 0) + return ret; + } + + /* Rectify APM requests early in order to learn the size of GPT. iso_write_apm() relies on this being already done here. So perform even if no GPT is required. @@ -1841,7 +1922,7 @@ static int precompute_gpt(Ecma119Image *t) 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); + iso_ascii_utf_16le(gpt_name); /* ret = iso_quick_gpt_entry(t, 16, 20, hfs_uuid, zero_uuid, gpt_flags, gpt_name); @@ -1854,7 +1935,7 @@ static int precompute_gpt(Ecma119Image *t) if (ret < 0) return ret; strcpy((char *) gpt_name, "GPT Test 2"); - poor_man_s_utf_16le(gpt_name); + iso_ascii_utf_16le(gpt_name); ret = iso_quick_gpt_entry(t, 110, 60, basic_data_uuid, zero_uuid, gpt_flags, gpt_name); if (ret < 0) @@ -2058,7 +2139,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) } memset(gpt_name, 0, 72); strcpy((char *) gpt_name, "EFI boot partition"); - poor_man_s_utf_16le(gpt_name); + iso_ascii_utf_16le(gpt_name); ret = iso_quick_gpt_entry(t, t->curblock, t->efi_boot_part_size, efi_sys_uuid, zero_uuid, gpt_flags, gpt_name); if (ret < 0) @@ -2091,7 +2172,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer) return ret; } if (t->prep_part_size > 0) { - ret = iso_quick_mbr_entry(t, t->curblock, t->prep_part_size, 0x42, 0); + ret = iso_quick_mbr_entry(t, t->curblock, t->prep_part_size, 0x41, 0); if (ret < 0) return ret; t->curblock += t->prep_part_size; diff --git a/libisofs/system_area.h b/libisofs/system_area.h index 6dee105..38345cc 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -117,6 +117,8 @@ int iso_quick_mbr_entry(Ecma119Image *t, to the final size of the partition map. If no such entry is requested, then it will be prepended automatically with name "Apple" and type "Apple_partition_map". + The requested entries will get sorted and gaps will be filled by more + entries. */ struct iso_apm_partition_request { @@ -174,10 +176,14 @@ void iso_random_8byte(Ecma119Image *t, uint8_t result[8]); 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 requested entries will get sorted and gaps will be filled by more + entries. Overlapping partitions are allowed only if + (Ecma119Image.gpt_req_flags & 1). + The block_count will be truncated to the image size before the GPT backup. + 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 @@ -242,5 +248,7 @@ int partprepend_writer_create(Ecma119Image *target); */ int gpt_tail_writer_create(Ecma119Image *target); +/* Only for up to 36 characters ISO-8859-1 (or ASCII) input */ +void iso_ascii_utf_16le(uint8_t gap_name[72]); #endif /* SYSTEM_AREA_H_ */