From 337bade549c535469d18a1cd8bcb3a7f6e125df7 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 13 Apr 2013 08:38:52 +0200 Subject: [PATCH] New option bits with el_torito_set_isolinux_options() and iso_write_opts_set_system_area() to control GRUB2 patching of boot image and MBR --- libisofs/ecma119.c | 2 +- libisofs/eltorito.c | 56 +++++++++++++++++++++++++++++++++++------- libisofs/eltorito.h | 9 +++++++ libisofs/fs_image.c | 14 ++++++++++- libisofs/libisofs.h | 22 +++++++++++++++-- libisofs/system_area.c | 13 +++++++++- libisofs/system_area.h | 7 ++++++ 7 files changed, 109 insertions(+), 14 deletions(-) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index fa94348..aa30929 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -3275,7 +3275,7 @@ int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768], memcpy(opts->system_area_data, data, 32768); } if (!(flag & 4)) - opts->system_area_options = options & 0x3fff; + opts->system_area_options = options & 0x7fff; return ISO_SUCCESS; } diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index 1cbdd05..b6f0e84 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2010 Thomas Schmitt + * Copyright (c) 2010 - 2013 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 @@ -160,7 +160,13 @@ int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20]) /* API */ int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag) { - return bootimg->seems_boot_info_table; + switch (flag & 15) { + case 0: + return bootimg->seems_boot_info_table; + case 1: + return bootimg->seems_grub2_boot_info; + } + return 0; } /** @@ -197,14 +203,14 @@ void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg) */ int el_torito_set_isolinux_options(ElToritoBootImage *bootimg, int options, int flag) { - bootimg->isolinux_options = (options & 0x01ff); + bootimg->isolinux_options = (options & 0x03ff); return ISO_SUCCESS; } /* API */ int el_torito_get_isolinux_options(ElToritoBootImage *bootimg, int flag) { - return bootimg->isolinux_options & 0x01ff; + return bootimg->isolinux_options & 0x03ff; } /* API */ @@ -1096,7 +1102,7 @@ int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba, } /** - * Patch an isolinux boot image. + * Patch an El Torito boot image by a boot info table. * * @return * 1 on success, 0 error (but continue), < 0 error @@ -1117,6 +1123,27 @@ int patch_boot_info_table(uint8_t *buf, Ecma119Image *t, return ret; } + +/** + * Patch a GRUB2 El Torito boot image. + */ +static +int patch_grub2_boot_image(uint8_t *buf, Ecma119Image *t, + size_t imgsize, int idx, + size_t pos, int offst) +{ + uint64_t blk; + + if (imgsize < pos + 8) + return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0, + "Isolinux image too small for GRUB2. Will not patch it."); + blk = ((uint64_t) t->bootsrc[idx]->sections[0].block) * 4 + offst; + iso_lsb((buf + pos), blk & 0xffffffff, 4); + iso_lsb((buf + pos + 4), blk >> 32, 4); + return ISO_SUCCESS; +} + + /* Patch the boot images if indicated */ int iso_patch_eltoritos(Ecma119Image *t) { @@ -1130,7 +1157,7 @@ int iso_patch_eltoritos(Ecma119Image *t) return ISO_SUCCESS; for (idx = 0; idx < t->catalog->num_bootimages; idx++) { - if (!(t->catalog->bootimages[idx]->isolinux_options & 0x01)) + if (!(t->catalog->bootimages[idx]->isolinux_options & 0x201)) continue; original = t->bootsrc[idx]->stream; size = (size_t) iso_stream_get_size(original); @@ -1154,9 +1181,20 @@ int iso_patch_eltoritos(Ecma119Image *t) } /* ok, patch the read buffer */ - ret = patch_boot_info_table(buf, t, size, idx); - if (ret < 0) { - return ret; + if (t->catalog->bootimages[idx]->isolinux_options & 0x200) { + /* GRUB2 boot provisions */ + ret = patch_grub2_boot_image(buf, t, size, idx, + Libisofs_grub2_elto_patch_poS, + Libisofs_grub2_elto_patch_offsT); + if (ret < 0) + return ret; + } + /* Must be done as last patching */ + if (t->catalog->bootimages[idx]->isolinux_options & 0x01) { + /* Boot Info Table */ + ret = patch_boot_info_table(buf, t, size, idx); + if (ret < 0) + return ret; } /* replace the original stream with a memory stream that reads from diff --git a/libisofs/eltorito.h b/libisofs/eltorito.h index 506c3b6..d26c01a 100644 --- a/libisofs/eltorito.h +++ b/libisofs/eltorito.h @@ -58,6 +58,7 @@ struct el_torito_boot_image { * Whether the boot image seems to contain a boot_info_table */ unsigned int seems_boot_info_table:1; + unsigned int seems_grub2_boot_info:1; /** * isolinux options * bit 0 -> whether to patch image @@ -155,4 +156,12 @@ int make_boot_info_table(uint8_t *buf, uint32_t pvd_lba, */ int iso_patch_eltoritos(Ecma119Image *t); + +/* Parameters for patch_grub2_boot_image() + Might later become variables in struct el_torito_boot_image. +*/ +#define Libisofs_grub2_elto_patch_poS (512 * 5 - 12) +#define Libisofs_grub2_elto_patch_offsT 5 + + #endif /* LIBISO_ELTORITO_H */ diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 2e31c64..7a9d185 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -3375,13 +3375,14 @@ static int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts, IsoDataSource *src, uint32_t iso_image_size, int flag) { - int i, ret, section_count, todo, chunk; + int i, j, ret, section_count, todo, chunk; uint32_t img_lba, img_size, boot_pvd_found, image_pvd, alleged_size; struct iso_file_section *sections = NULL; struct el_torito_boot_image *boot; uint8_t *boot_image_buf = NULL, boot_info_found[16], *buf = NULL; IsoStream *stream = NULL; IsoFile *boot_file; + uint64_t blk; if (image->bootcat == NULL) {ret = ISO_SUCCESS; goto ex;} @@ -3390,6 +3391,7 @@ int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts, boot = image->bootcat->bootimages[i]; boot_file = boot->image; boot->seems_boot_info_table = 0; + boot->seems_grub2_boot_info = 0; img_size = iso_file_get_size(boot_file); if (img_size > Libisofs_boot_image_max_sizE || img_size < 64) continue; @@ -3455,6 +3457,16 @@ int iso_image_eval_boot_info_table(IsoImage *image, struct iso_read_opts *opts, goto ex; if (memcmp(boot_image_buf + 8, boot_info_found, 16) == 0) boot->seems_boot_info_table = 1; + + if (img_size >= Libisofs_grub2_elto_patch_poS + 8) { + blk = 0; + for (j = Libisofs_grub2_elto_patch_poS + 7; + j >= Libisofs_grub2_elto_patch_poS; j--) + blk = (blk << 8) | boot_image_buf[j]; + if (blk == img_lba * 4 + Libisofs_grub2_elto_patch_offsT) + boot->seems_grub2_boot_info = 1; + } + free(boot_image_buf); boot_image_buf = NULL; } diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index b43b1c1..59fb204 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2191,6 +2191,13 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * 1 = CHRP: A single MBR partition of type 0x96 covers the * ISO image. Not compatible with any other feature * which needs to have own MBR partition entries. + * bit14= Only with System area type 0 = MBR + * GRUB2 boot provisions: + * @since 1.3.0 + * Patch system area at byte 92 to 99 with 512-block address + 1 + * of the first boot image file. Little-endian 8-byte. + * Should be combined with options bit0. + * Will not be in effect if options bit1 is set. * @param flag * bit0 = invalidate any attached system area data. Same as data == NULL * (This re-activates eventually loaded image System Area data. @@ -3465,9 +3472,15 @@ int el_torito_get_selection_crit(ElToritoBootImage *bootimg, uint8_t crit[20]); * @param bootimg * The image to inquire * @param flag - * Reserved for future usage, set to 0. + * Bitfield for control purposes: + * bit0 - bit3= mode + * 0 = inquire for classic boot info table as described in man mkisofs + * @since 0.6.32 + * 1 = inquire for GRUB2 boot info as of bit9 of options of + * el_torito_set_isolinux_options() + * @since 1.3.0 * @return - * 1 = seems to contain oot info table , 0 = quite surely not + * 1 = seems to contain the inquired boot info, 0 = quite surely not * @since 0.6.32 */ int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag); @@ -3531,6 +3544,11 @@ int el_torito_seems_boot_info_table(ElToritoBootImage *bootimg, int flag); * mentioned. The ISOLINUX MBR must look suitable or else an error * event will happen at image generation time. * @since 1.2.4 + * bit9= GRUB2 boot info + * Patch the boot image file at byte 1012 with the 512-block + * address + 2. Two little endian 32-bit words. Low word first. + * This is combinable with bit0. + * @since 1.3.0 * @param flag * Reserved for future usage, set to 0. * @return diff --git a/libisofs/system_area.c b/libisofs/system_area.c index abc5a9b..3f67975 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2008 Vreixo Formoso - * Copyright (c) 2010 - 2012 Thomas Schmitt + * Copyright (c) 2010 - 2013 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 @@ -1417,6 +1417,8 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) 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; + uint64_t blk; + uint8_t *wpt; if ((t == NULL) || (buf == NULL)) { return ISO_NULL_POINTER; @@ -1607,6 +1609,15 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) return ret; } + if (sa_type == 0 && (t->system_area_options & 0x4000) && !do_isohybrid) { + /* Patch MBR for GRUB2 */ + blk = t->bootsrc[0]->sections[0].block * 4 + + Libisofs_grub2_mbr_patch_offsT; + wpt = buf + Libisofs_grub2_mbr_patch_poS; + for (i = 0; i < 8; i++) + wpt[i] = blk >> (i * 8); + } + return ISO_SUCCESS; } diff --git a/libisofs/system_area.h b/libisofs/system_area.h index 9585fde..ccd34c9 100644 --- a/libisofs/system_area.h +++ b/libisofs/system_area.h @@ -266,4 +266,11 @@ 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]); + +/* Parameters of MBR patching for GRUB2 + Might later become variables in Ecma119Image +*/ +#define Libisofs_grub2_mbr_patch_poS 0x1b0 +#define Libisofs_grub2_mbr_patch_offsT 3 + #endif /* SYSTEM_AREA_H_ */