New option bits 2 to 7 with el_torito_set_isolinux_options()

This commit is contained in:
Thomas Schmitt 2012-06-20 19:21:35 +02:00
parent 27277914c6
commit bab3cf0c7c
7 changed files with 285 additions and 186 deletions

View File

@ -895,7 +895,7 @@ Sources:
Mail conversations with Vladimir Serbinenko. 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 446 - 461 | mbr_entry1 | Partition table entry 1 describing the size of
| | the ISO image plus the backup GPT, padded up to | | the ISO image plus the backup GPT, padded up to
| | the next full MiB. | | 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. 478 - 493 | mbr_entry3 | Entry 3 describing the HFS+ boot image.
| | | |
512 - 1023 | gpt_head | GPT header describing the GPT partition array. 512 - 1023 | gpt_head | GPT header describing the GPT partition array.
1024 - 2047 | unused | 1024 - 2047 | unused |
2048 - 4095 | apm_entry1 | APM entry 1 describing APM entries 1 to 3. 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. 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. 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. 8448 - 8575 | gpt_entry3 | GPT partition entry 3 for the HFS+ boot image.
8576 - 24575 | gtp_empty | Empty GPT partition entries 4 to 128. 8576 - 24575 | gtp_empty | Empty GPT partition entries 4 to 128.
24576 - 32767 | unused | 24576 - 32767 | unused |
@ -1376,7 +1376,7 @@ System Area may contain simultaneously:
MBR Partitions: MBR Partitions:
0xee from 0 to PREP-1, protective partition, announcing presence of GPT 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 0x0c from HFAT to END-1, FAT partition, bootable bit on
0x00 Empty partition 0x00 Empty partition

View File

@ -1918,12 +1918,17 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
iso_node_ref(target->hfsplus_blessed[i]); iso_node_ref(target->hfsplus_blessed[i]);
} }
target->apm_block_size = 512; target->apm_block_size = 512;
target->apm_req_count = 0;
target->apm_req_flags = 0;
for (i = 0; i < ISO_APM_ENTRIES_MAX; i++) for (i = 0; i < ISO_APM_ENTRIES_MAX; i++)
target->apm_req[i] = NULL; target->apm_req[i] = NULL;
for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++) for (i = 0; i < ISO_MBR_ENTRIES_MAX; i++)
target->mbr_req[i] = NULL; target->mbr_req[i] = NULL;
target->mbr_req_count = 0;
for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++) for (i = 0; i < ISO_GPT_ENTRIES_MAX; i++)
target->gpt_req[i] = NULL; target->gpt_req[i] = NULL;
target->gpt_req_count = 0;
target->gpt_req_flags = 0;
target->gpt_part_start = 0; target->gpt_part_start = 0;
target->gpt_backup_end = 0; target->gpt_backup_end = 0;
target->gpt_backup_size = 0; target->gpt_backup_size = 0;

View File

@ -828,6 +828,8 @@ struct ecma119_image
int apm_req_count; int apm_req_count;
/* 512 by default. May be changed to 2048 before writer thread starts. */ /* 512 by default. May be changed to 2048 before writer thread starts. */
int apm_block_size; 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 /* MBR partition table description. To be composed during IsoImageWriter
method ->compute_data_blocks() by calling iso_register_mbr_entry(). 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]; struct iso_gpt_partition_request *gpt_req[ISO_GPT_ENTRIES_MAX];
int gpt_req_count; int gpt_req_count;
/* bit0= GPT partitions may overlap */
int gpt_req_flags;
char *efi_boot_partition; char *efi_boot_partition;
uint32_t efi_boot_part_size; uint32_t efi_boot_part_size;

View File

@ -3424,47 +3424,52 @@ int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag);
* @param options * @param options
* bitmask style flag. The following values are defined: * bitmask style flag. The following values are defined:
* *
* bit 0 -> 1 to patch the boot info table of the boot image. * bit0= Patch the boot info table of the boot image.
* 1 does the same as mkisofs option -boot-info-table. * This does the same as mkisofs option -boot-info-table.
* Needed for ISOLINUX or GRUB boot images with platform ID 0. * Needed for ISOLINUX or GRUB boot images with platform ID 0.
* The table is located at byte 8 of the boot image file. * The table is located at byte 8 of the boot image file.
* Its size is 56 bytes. * Its size is 56 bytes.
* The original boot image file on disk will not be modified. * The original boot image file on disk will not be modified.
* *
* One may use el_torito_seems_boot_info_table() for a * One may use el_torito_seems_boot_info_table() for a
* qualified guess whether a boot info table is present in * qualified guess whether a boot info table is present in
* the boot image. If the result is 1 then it should get bit0 * the boot image. If the result is 1 then it should get bit0
* set if its content gets copied to a new LBA. * set if its content gets copied to a new LBA.
* *
* bit 1 -> 1 to generate a ISOLINUX isohybrid image with MBR. * bit1= Generate a ISOLINUX isohybrid image with MBR.
* ---------------------------------------------------------- * ----------------------------------------------------------
* @deprecated since 31 Mar 2010: * @deprecated since 31 Mar 2010:
* The author of syslinux, H. Peter Anvin requested that this * The author of syslinux, H. Peter Anvin requested that this
* feature shall not be used any more. He intends to cease * feature shall not be used any more. He intends to cease
* support for the MBR template that is included in libisofs. * support for the MBR template that is included in libisofs.
* ---------------------------------------------------------- * ----------------------------------------------------------
* A hybrid image is a boot image that boots from either * A hybrid image is a boot image that boots from either
* CD/DVD media or from disk-like media, e.g. USB stick. * CD/DVD media or from disk-like media, e.g. USB stick.
* For that you need isolinux.bin from SYSLINUX 3.72 or later. * For that you need isolinux.bin from SYSLINUX 3.72 or later.
* IMPORTANT: The application has to take care that the image * IMPORTANT: The application has to take care that the image
* on media gets padded up to the next full MB. * on media gets padded up to the next full MB.
>>> unless a GPT gets created * Under seiveral circumstances it might get aligned
* automatically. But there is no warranty.
* >>> *** Under construction. *** Do not use yet: * bit2-7= Mentioning in isohybrid GPT
* >>> bit2-7= Mentioning in isohybrid GPT * 0= Do not mention in GPT
* >>> 0= do not mention in GPT * 1= Mention as Basic Data partition.
* >>> 1= mention as EFI partition * This cannot be combined with GPT partitions as of
* >>> @since 1.2.4 * iso_write_opts_set_efi_bootp()
* >>> 2= Mention as HFS+ partition * >>> ts B20620 : and not with iso_write_opts_set_hfsplus()
* >>> @since 1.2.4 * >>> if it produces GPT entries
* >>> Primary GPT and backup GPT get written if at least one * @since 1.2.4
* >>> ElToritoBootImage shall be mentioned * 2= Mention as HFS+ partition.
* >>> bit8= Mention in isohybrid Apple partition map * This cannot be combined with HFS+ production by
* >>> APM get written if at least one ElToritoBootImage shall be * iso_write_opts_set_hfsplus().
* >>> mentioned. The ISOLINUX MBR must look suitable or else an error * @since 1.2.4
* >>> event will happen at image generation time. * Primary GPT and backup GPT get written if at least one
* >>> @since 1.2.4 * 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 * @param flag
* Reserved for future usage, set to 0. * Reserved for future usage, set to 0.
* @return * @return

View File

@ -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 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 */ /* Find out whether GPT and APM are desired
static int assess_gpt_apm(Ecma119Image *t, int *gpt_count, int gpt_idx[128], flag bit0 = register APM and GPT requests in Ecma119Image
int *apm_count) */
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++) { for (i = 0; i < t->catalog->num_bootimages; i++) {
ilx_opts = t->catalog->bootimages[i]->isolinux_options; 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) if (*gpt_count < 128)
gpt_idx[*gpt_count]= i; gpt_idx[*gpt_count]= i;
(*gpt_count)++; (*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)++; (*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) { if ((flag & 1) && *gpt_count > 0) {
iso_msgs_submit(0, /* Register overall GPT partition */
"Too many entries desired for Apple Partition Map. (max 6)", memset(gpt_name, 0, 72);
0, "FAILURE", 0); sprintf((char *) gpt_name, "ISOHybrid");
return ISO_BOOT_TOO_MANY_APM; 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; return ISO_SUCCESS;
} }
@ -432,6 +495,12 @@ static int insert_apm_head(uint8_t *buf, int apm_count)
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
if(buf[i] != apm_mbr_start[i]) if(buf[i] != apm_mbr_start[i])
break; 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) { if (i < 32) {
iso_msgs_submit(0, iso_msgs_submit(0,
"MBR template file seems not prepared for Apple Partition Map.", "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, static int gpt_images_as_mbr_partitions(Ecma119Image *t, char *wpt,
int gpt_idx[128], int *gpt_cursor) 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 * @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; uint32_t id, part, nominal_part_size;
off_t hd_img_blocks, hd_boot_lba; off_t hd_img_blocks, hd_boot_lba;
char *wpt; 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 head_count, sector_count, ret;
int gpt_count = 0, gpt_idx[128], apm_count = 0, gpt_cursor; int gpt_count = 0, gpt_idx[128], apm_count = 0, gpt_cursor;
/* For generating a weak random number */ /* 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; head_count = t->partition_heads_per_cyl;
sector_count = t->partition_secs_per_head; sector_count = t->partition_secs_per_head;
ret = assess_gpt_apm(t, &gpt_count, gpt_idx, &apm_count); ret = assess_isohybrid_gpt_apm(t, &gpt_count, gpt_idx, &apm_count, 0);
if (ret < 0)
return ret;
ret = insert_apm_head(buf, apm_count);
if (ret < 0) if (ret < 0)
return ret; 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 /* Padding of image_size to a multiple of sector_count*head_count
happens already at compute time and is implemented by happens already at compute time and is implemented by
an appropriate increase of Ecma119Image->tail_blocks. 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; wpt = (char *) buf + 432;
/* write qword boot_lba # Offset 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); 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); return(1);
} }

View File

@ -58,6 +58,13 @@ int make_isolinux_mbr(uint32_t *img_blocks, Ecma119Image *t,
int part_offset, int part_number, int fs_type, int part_offset, int part_number, int fs_type,
uint8_t *buf, int flag); 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); static int precompute_gpt(Ecma119Image *t);
@ -804,6 +811,12 @@ int cmp_partition_request(const void *f1, const void *f2)
return -1; return -1;
if (r1->start_block > r2->start_block) if (r1->start_block > r2->start_block)
return 1; 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; 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", "Program error: APM partitions %d and %d overlap by %lu blocks",
i - 1, i, part_end - goal); i - 1, i, part_end - goal);
return ISO_BOOT_APM_OVERLAP; 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 */ if (part_end < goal || i == up_to - 1) { /* Always add a final entry */
sprintf(gap_name, "Gap%d", gap_counter); sprintf(gap_name, "Gap%d", gap_counter);
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 */ /* Merge list of gap partitions with list of already sorted entries */
qsort(t->apm_req, t->apm_req_count, if (!(t->apm_req_flags & 2)) /* No gaps were filled */
sizeof(struct iso_apm_partition_request *), cmp_partition_request); qsort(t->apm_req, t->apm_req_count,
sizeof(struct iso_apm_partition_request *), cmp_partition_request);
return 1; 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; int i, ret;
/* This is a micro mick-up of an APM Block0 /* 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) if (t->apm_req_count <= 0)
return 2; return 2;
/* Adjust last partition to img_size. This size was not known when the if (!(t->apm_req_flags & 2)) {
number of APM partitions was determined. /* Gaps have been filled. Care for the final one */
*/ /* Adjust last partition to img_size. This size was not known when the
t->apm_req[t->apm_req_count - 1]->block_count = number of APM partitions was determined.
img_blocks - t->apm_req[t->apm_req_count - 1]->start_block; */
/* If it is still empty, remove it */ t->apm_req[t->apm_req_count - 1]->block_count =
if(t->apm_req[t->apm_req_count - 1]->block_count == 0) { img_blocks - t->apm_req[t->apm_req_count - 1]->start_block;
free(t->apm_req[t->apm_req_count - 1]); /* If it is still empty, remove it */
t->apm_req_count--; 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 */ /* 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]->start_block = 1;
t->apm_req[0]->block_count = t->apm_req_count; t->apm_req[0]->block_count = t->apm_req_count;
/* Write APM block 0. Very sparse, not to overwrite much of possible MBR.*/ if (!(flag & 1)) {
memcpy(buf, block0_template, 8); /* Write APM block 0. Very sparse, not to overwrite much of
buf[2]= (t->apm_block_size >> 8) & 0xff; possible MBR.
buf[3]= 0; */
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 */ /* Write APM Block 1 to t->apm_req_count */
for (i = 0; i < t->apm_req_count; i++) { 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 */ /* 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; 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 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; uint64_t start_lba, end_lba;
int ret, i, gap_counter = 0, up_to; int ret, i, gap_counter = 0, up_to;
struct iso_gpt_partition_request *req; 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); sizeof(struct iso_gpt_partition_request *), cmp_partition_request);
/* t->gpt_req_count will grow during the loop */ /* t->gpt_req_count will grow during the loop */
up_to = t->gpt_req_count + 1; up_to = t->gpt_req_count + 1;
goal = 0;
part_end = 0;
for (i = 0; i < up_to; i++) { for (i = 0; i < up_to; i++) {
if (i < up_to - 1) if (i < up_to - 1) {
goal = t->gpt_req[i]->start_block; goal = t->gpt_req[i]->start_block;
else } else {
goal = img_blocks; goal = img_blocks;
}
if (i == 0) { if (i == 0) {
if (goal <= 16) if (goal <= 16)
continue; continue;
part_end = 16; next_end = 16;
} else { } 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; t->gpt_req[i - 1]->block_count;
} }
if (next_end > part_end)
part_end = next_end;
if (part_end > goal) { 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", "Program error: GPT partitions %d and %d overlap by %lu blocks",
i - 1, i, part_end - goal); i - 1, i, part_end - goal);
return ISO_BOOT_GPT_OVERLAP; return ISO_BOOT_GPT_OVERLAP;
} }
if (part_end < goal) { } else if (part_end < goal) {
memset(gpt_name, 0, 72); memset(gpt_name, 0, 72);
sprintf((char *) gpt_name, "Gap%d", gap_counter); sprintf((char *) gpt_name, "Gap%d", gap_counter);
poor_man_s_utf_16le(gpt_name); iso_ascii_utf_16le(gpt_name);
gap_counter++; gap_counter++;
ret = iso_quick_gpt_entry(t, part_end, goal - part_end, ret = iso_quick_gpt_entry(t, part_end, goal - part_end,
basic_data_uuid, zero_uuid, 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++) { for (i = 0; i < t->gpt_req_count; i++) {
req = t->gpt_req[i]; req = t->gpt_req[i];
start_lba = ((uint64_t) req->start_block) * 4; 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, iso_write_gpt_entry(t, buf + 512 * t->gpt_part_start + 128 * i,
req->type_guid, req->partition_guid, req->type_guid, req->partition_guid,
start_lba, end_lba, req->flags, req->name); 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 iso_write_system_area(Ecma119Image *t, uint8_t *buf)
{ {
int ret, int_img_blocks, sa_type, i, will_append = 0; int ret, int_img_blocks, sa_type, i, will_append = 0, do_isohybrid = 0;
int first_partition = 1, last_partition = 4; 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; uint32_t img_blocks;
if ((t == NULL) || (buf == NULL)) { 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 >>> A sa_type, that does this, will have to adjust the last APM entry
>>> if exactness matters. >>> 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) { if (ret < 0) {
iso_msg_submit(t->image->id, ret, 0, iso_msg_submit(t->image->id, ret, 0,
"Cannot set up Apple Partition Map"); "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 */ if (ret != ISO_SUCCESS) /* error should never happen */
return ISO_ASSERT_FAILURE; 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 */ /* Patch externally provided system area as isohybrid MBR */
if (t->catalog == NULL || t->system_area_data == NULL) { if (t->catalog == NULL || t->system_area_data == NULL) {
/* isohybrid makes only sense together with ISOLINUX boot image /* 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; return ISO_ISOLINUX_CANT_PATCH;
} }
/* >>> ISOHYBRID : need option to set fs_type of MBR partition 1 if (gpt_count > 0 || apm_count > 0)
(here it is 0x17) */; part_type = 0x00;
else
part_type = 0x17;
/* >>> ??? Why is partition_offset 0 here ? /* >>> ??? Why is partition_offset 0 here ?
It gets adjusted later by iso_offset_partition_start() It gets adjusted later by iso_offset_partition_start()
Would it harm to give the real offset here ? Would it harm to give the real offset here ?
*/; */;
/* >>> Coordinate with partprepend writer */ ret = make_isolinux_mbr(&img_blocks, t, 0, 1, part_type, buf, 1);
/* <<< 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);
if (ret != 1) if (ret != 1)
return ret; return ret;
} else if (sa_type == 1) { } 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) static int precompute_gpt(Ecma119Image *t)
{ {
uint32_t gpt_part_start; 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 */ /* Avoid repetition by gpt_tail_writer_compute_data_blocks */
t->gpt_is_computed = 1; 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. /* Rectify APM requests early in order to learn the size of GPT.
iso_write_apm() relies on this being already done here. iso_write_apm() relies on this being already done here.
So perform even if no GPT is required. So perform even if no GPT is required.
@ -1841,7 +1922,7 @@ static int precompute_gpt(Ecma119Image *t)
memset(gpt_name, 0, 72); memset(gpt_name, 0, 72);
gpt_name[0] = 'T'; gpt_name[2] = '1'; gpt_name[0] = 'T'; gpt_name[2] = '1';
strcpy((char *) gpt_name, "GPT Test 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, ret = iso_quick_gpt_entry(t, 16, 20, hfs_uuid, zero_uuid,
gpt_flags, gpt_name); gpt_flags, gpt_name);
@ -1854,7 +1935,7 @@ static int precompute_gpt(Ecma119Image *t)
if (ret < 0) if (ret < 0)
return ret; return ret;
strcpy((char *) gpt_name, "GPT Test 2"); 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, ret = iso_quick_gpt_entry(t, 110, 60, basic_data_uuid, zero_uuid,
gpt_flags, gpt_name); gpt_flags, gpt_name);
if (ret < 0) if (ret < 0)
@ -2058,7 +2139,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
} }
memset(gpt_name, 0, 72); memset(gpt_name, 0, 72);
strcpy((char *) gpt_name, "EFI boot partition"); 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, ret = iso_quick_gpt_entry(t, t->curblock, t->efi_boot_part_size,
efi_sys_uuid, zero_uuid, gpt_flags, gpt_name); efi_sys_uuid, zero_uuid, gpt_flags, gpt_name);
if (ret < 0) if (ret < 0)
@ -2091,7 +2172,7 @@ static int partprepend_writer_compute_data_blocks(IsoImageWriter *writer)
return ret; return ret;
} }
if (t->prep_part_size > 0) { 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) if (ret < 0)
return ret; return ret;
t->curblock += t->prep_part_size; t->curblock += t->prep_part_size;

View File

@ -117,6 +117,8 @@ int iso_quick_mbr_entry(Ecma119Image *t,
to the final size of the partition map. to the final size of the partition map.
If no such entry is requested, then it will be prepended automatically If no such entry is requested, then it will be prepended automatically
with name "Apple" and type "Apple_partition_map". 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 { 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. See also the partial GPT description in doc/boot_sectors.txt.
The list of entries is stored in Ecma119Image.gpt_req. The list of entries is stored in Ecma119Image.gpt_req.
The GPT header block at byte 0x200 will get produced automatically. 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 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 gets generated too. Both partition descriptions must fit into the 32 KiB
of the ISO 9660 System Area. of the ISO 9660 System Area.
GPT can be combined with APM only if (Ecma119Image.apm_block_size > 512). GPT can be combined with APM only if (Ecma119Image.apm_block_size > 512).
Otherwise, block 1 of APM and GPT header block would collide. Otherwise, block 1 of APM and GPT header block would collide.
So Ecma119Image.apm_block_size is set automatically to 2048 if at least 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); 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_ */ #endif /* SYSTEM_AREA_H_ */