From b07d3ab0c358b181a7b65275bad3cc72752b9075 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 12 Oct 2010 12:20:27 +0200 Subject: [PATCH] Provisory implementation of MIPS big endian Volume Header production. For now it is mutually exclusive with El Torito production. It will always be mutually exclusive with MBR production. --- libisofs/ecma119.c | 21 +++++++- libisofs/ecma119.h | 9 +++- libisofs/eltorito.c | 12 +++++ libisofs/filesrc.c | 1 + libisofs/libisofs.h | 15 +++++- libisofs/system_area.c | 107 +++++++++++++++++++++++++++++++++++++++-- 6 files changed, 155 insertions(+), 10 deletions(-) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 8f1887a..62ab044 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1567,6 +1567,8 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } else if (src->system_area_data != NULL) { system_area = src->system_area_data; system_area_options = src->system_area_options; + } else { + system_area_options = opts->system_area_options & 0xfc; } target->system_area_data = NULL; if (system_area != NULL) { @@ -2614,9 +2616,24 @@ int iso_write_opts_get_data_start(IsoWriteOpts *opts, uint32_t *data_start, /* * @param data Either NULL or 32 kB of data. Do not submit less bytes ! - * @param options bit0 = apply GRUB protective msdos label + * @param options + * Can cause manipulations of submitted data before they get written: + * bit0= apply a --protective-msdos-label as of grub-mkisofs. + * This means to patch bytes 446 to 512 of the system area so + * that one partition is defined which begins at the second + * 512-byte block of the image and ends where the image ends. + * This works with and without system_area_data. + * bit1= apply isohybrid MBR patching to the system area. + * This works only with system area data from SYSLINUX plus an + * ISOLINUX boot image (see iso_image_set_boot_image()) and + * only if not bit0 is set. + * bit2-7= System area type + * 0= PC-BIOS DOS MBR + * 1= MIPS Big Endian Volume Header * @param flag bit0 = invalidate any attached system area data * same as data == NULL + * bit1 = keep data unaltered + * bit2 = keep options unaltered */ int iso_write_opts_set_system_area(IsoWriteOpts *opts, char data[32768], int options, int flag) @@ -2634,7 +2651,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 & 3; + opts->system_area_options = options & 0xff; return ISO_SUCCESS; } diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 8335845..28c1b57 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -481,14 +481,19 @@ struct ecma119_image */ char *system_area_data; /* - * bit0= make bytes 446 - 512 of the system area a partition + * bit0= Only with PC-BIOS DOS MBR + * Make bytes 446 - 512 of the system area a partition * table which reserves partition 1 from byte 63*512 to the * end of the ISO image. Assumed are 63 secs/hed, 255 head/cyl. * (GRUB protective msdos label.) * This works with and without system_area_data. - * bit1= apply isohybrid MBR patching to the system area. + * bit1= Only with PC-BIOS DOS MBR + * Apply isohybrid MBR patching to the system area. * This works only with system_area_data plus ISOLINUX boot image * and only if not bit0 is set. + * bit2-7= System area type + * 0= DOS MBR + * 1= MIPS Big Endian Volume Header */ int system_area_options; diff --git a/libisofs/eltorito.c b/libisofs/eltorito.c index 19e3835..c826690 100644 --- a/libisofs/eltorito.c +++ b/libisofs/eltorito.c @@ -1091,6 +1091,10 @@ int eltorito_writer_compute_data_blocks(IsoImageWriter *writer) t = writer->target; + /* >>> Preliminary: No El Torito with system area type other than MBR */ + if (t->system_area_options & 0xfc) + return ISO_SUCCESS; + /* Patch the boot image info tables if indicated */ for (idx = 0; idx < t->catalog->num_bootimages; idx++) { if (!(t->catalog->bootimages[idx]->isolinux_options & 0x01)) @@ -1151,6 +1155,10 @@ int eltorito_writer_write_vol_desc(IsoImageWriter *writer) t = writer->target; cat = t->catalog; + /* >>> Preliminary: No El Torito with system area type other than MBR */ + if (t->system_area_options & 0xfc) + return ISO_SUCCESS; + iso_msg_debug(t->image->id, "Write El-Torito boot record"); memset(&vol, 0, sizeof(struct ecma119_boot_rec_vol_desc)); @@ -1225,6 +1233,10 @@ int eltorito_writer_create(Ecma119Image *target) } } + /* >>> Preliminary: No El Torito with system area type other than MBR */ + if (target->system_area_options & 0xfc) + return ISO_SUCCESS; + /* we need the bootable volume descriptor */ target->curblock++; return ISO_SUCCESS; diff --git a/libisofs/filesrc.c b/libisofs/filesrc.c index faa8a3d..e3058f9 100644 --- a/libisofs/filesrc.c +++ b/libisofs/filesrc.c @@ -11,6 +11,7 @@ #include "../config.h" #endif +#include "libisofs.h" #include "filesrc.h" #include "node.h" #include "util.h" diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 2c01d45..87728e3 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1755,15 +1755,26 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * Either NULL or 32 kB of data. Do not submit less bytes ! * @param options * Can cause manipulations of submitted data before they get written: - * bit0= apply a --protective-msdos-label as of grub-mkisofs. + * bit0= Only with System area type 0 = MBR + * Apply a --protective-msdos-label as of grub-mkisofs. * This means to patch bytes 446 to 512 of the system area so * that one partition is defined which begins at the second * 512-byte block of the image and ends where the image ends. * This works with and without system_area_data. - * bit1= apply isohybrid MBR patching to the system area. + * bit1= Only with System area type 0 = MBR + * Apply isohybrid MBR patching to the system area. * This works only with system area data from SYSLINUX plus an * ISOLINUX boot image (see iso_image_set_boot_image()) and * only if not bit0 is set. + * bit2-7= System area type + * 0= with bit0 or bit1: MBR + * else: unspecified type + * @since 0.6.38 + * 1= MIPS Big Endian Volume Header + >>> EXPERIMENTAL: + Submit MIPS boot image files as El Torito Boot image to + iso_image_set_boot_image() , iso_image_add_boot_image(). + No El Torito info will be produced with system area type 1. * @param flag * bit0 = invalidate any attached system area data. Same as data == NULL * (This re-activates eventually loaded image System Area data. diff --git a/libisofs/system_area.c b/libisofs/system_area.c index c9f9e19..41b2c1f 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -12,6 +12,7 @@ #include "../config.h" #endif +#include "libisofs.h" #include "system_area.h" #include "eltorito.h" #include "filesrc.h" @@ -208,9 +209,102 @@ int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset, } +/* This function was implemented according to a byte map which was derived + by Thomas Schmitt from + cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based + on work of Florian Lohoff and Thiemo Seufer who possibly learned from + documents of MIPS Computer Systems, Inc. and Silicon Graphics Computer + Systems, Inc. + This function itself is entirely under copyright (C) 2010 Thomas Schmitt. +*/ +static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag) +{ + char *namept, *name_field; + uint32_t num_cyl, idx, blocks, num, checksum; + off_t image_size; + static uint32_t bps = 512, spt = 32; + + memset(buf, 0, 16 * BLOCK_SIZE); + + image_size = t->curblock * 2048; + + /* 0 - 3 | 0x0be5a941 | Magic number */ + iso_msb(buf, 0x0be5a941, 4); + + /* 28 - 29 | num_cyl_l | Number of usable cylinder, lower two bytes */ + /* >>> Shall i rather orund up ? */ + num_cyl = image_size / (bps * spt); + iso_msb(buf + 28, num_cyl & 0xffff, 2); + + /* 32 - 33 | 1 | Number of tracks per cylinder */ + iso_msb(buf + 32, 1, 2); + + /* 35 - 35 | num_cyl_h | Number of usable cylinders, high byte */ + buf[35] = (num_cyl >> 16) & 0xff; + + /* 38 - 39 | 32 | Sectors per track */ + iso_msb(buf + 38, spt, 2); + + /* 40 - 41 | 512 | Bytes per sector */ + iso_msb(buf + 40, bps, 2); + + /* 44 - 47 | 0x00000034 | Controller characteristics */ + iso_msb(buf + 44, 0x00000034, 4); + + /* 72 - 87 | ========== | Volume Directory Entry 1 */ + /* 72 - 79 | boot_name | Boot file basename */ + /* 80 - 83 | boot_block | ISO 9660 LBA of boot file * 4 */ + /* 84 - 87 | boot_bytes | File length in bytes */ + /* 88 - 311 | 0 | Volume Directory Entries 2 to 15 */ + for (idx = 0; idx < t->catalog->num_bootimages; idx++) { + + /* >>> skip non-MIPS boot images */; + + namept = iso_node_get_name( + (IsoNode *) t->catalog->bootimages[idx]->image); + name_field = (char *) (buf + (72 + 16 * idx)); + strncpy(name_field, namept, 8); + iso_msb(buf + (72 + 16 * idx) + 8, + t->bootsrc[idx]->sections[0].block * 4, 4); + + /* >>> shall i really round up to 2048 ? */ + iso_msb(buf + (72 + 16 * idx) + 12, + ((t->bootsrc[idx]->sections[0].size + 2047) / 2048 ) * 2048, + 4); + } + + /* 408 - 411 | part_blks | Number of 512 byte blocks in partition */ + blocks = (image_size + bps - 1) / bps; + iso_msb(buf + 408, blocks, 4); + /* 416 - 419 | 0 | Partition is volume header */ + iso_msb(buf + 416, 0, 4); + + /* 432 - 435 | part_blks | Number of 512 byte blocks in partition */ + iso_msb(buf + 432, blocks, 4); + iso_msb(buf + 444, 6, 4); + + /* 504 - 507 | head_chk | Volume header checksum + The two's complement of bytes 0 to 503 read + as big endian unsigned 32 bit: + sum(32-bit-words) + head_chk == 0 + */ + checksum = 0; + for (idx = 0; idx < 504; idx += 4) { + num = iso_read_msb(buf + idx, 4); + /* Addition modulo a natural number is commutative and associative. + Thus the inverse of a sum is the sum of the inverses of the addends. + */ + checksum -= num; + } + iso_msb(buf + 504, checksum, 4); + + return 1; +} + + int iso_write_system_area(Ecma119Image *t, uint8_t *buf) { - int ret, int_img_blocks; + int ret, int_img_blocks, sa_type; uint32_t img_blocks; if ((t == NULL) || (buf == NULL)) { @@ -220,12 +314,13 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) /* set buf to 0s */ memset(buf, 0, 16 * BLOCK_SIZE); + sa_type = (t->system_area_options >> 2) & 0x3f; img_blocks = t->curblock; if (t->system_area_data != NULL) { /* Write more or less opaque boot image */ memcpy(buf, t->system_area_data, 16 * BLOCK_SIZE); - } else if (t->catalog != NULL && + } else if (sa_type == 0 && t->catalog != NULL && (t->catalog->bootimages[0]->isolinux_options & 0x0a) == 0x02) { /* Check for isolinux image with magic number of 3.72 and produce an MBR from our built-in template. (Deprecated since 31 Mar 2010) @@ -243,12 +338,12 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) } return ISO_SUCCESS; } - if (t->system_area_options & 1) { + if (sa_type == 0 && (t->system_area_options & 1)) { /* Write GRUB protective msdos label, i.e. a simple partition table */ ret = make_grub_msdos_label(img_blocks, buf, 0); if (ret != ISO_SUCCESS) /* error should never happen */ return ISO_ASSERT_FAILURE; - } else if(t->system_area_options & 2) { + } else if(sa_type == 0 && (t->system_area_options & 2)) { /* 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 @@ -260,6 +355,10 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) (uint32_t) 0, 64, 32, 0, 1, 0x17, buf, 1); if (ret != 1) return ret; + } else if(sa_type == 1) { + ret = make_mips_volume_header(t, buf, 0); + if (ret != ISO_SUCCESS) /* error should never happen */ + return ISO_ASSERT_FAILURE; } else if(t->partition_offset > 0) { /* Write a simple partition table. */ ret = make_grub_msdos_label(img_blocks, buf, 2);