From a75fb9a894624b0927046533be47d1743ad20a88 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Thu, 14 Oct 2010 22:34:32 +0200 Subject: [PATCH] New system area type 2 for Little Endian MIPS DEC boot block. --- doc/boot_sectors.txt | 26 ++++-- libisofs/libisofs.h | 19 +++-- libisofs/messages.c | 4 +- libisofs/system_area.c | 185 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 215 insertions(+), 19 deletions(-) diff --git a/doc/boot_sectors.txt b/doc/boot_sectors.txt index e994dad..6aa26ec 100644 --- a/doc/boot_sectors.txt +++ b/doc/boot_sectors.txt @@ -16,13 +16,17 @@ specifications, some is just rumor which happens to work (maybe not even that). EL Torito CD booting, for PC-BIOS x86, PowerPC, (old) Mac, EFI. MBR, for PC-BIOS x86 from (pseudo-) hard disk -- SYSLINUX Isohybrid MBR +- SYSLINUX isohybrid MBR - GRUB2 grub-mkrescue MBR. MIPS Volume Header, for MIPS Big Endian, e.g. SGI Indigo2. +DEC Boot Block, for MIPS Little Endian , e.g. DECstation. + + ------------------------------------------------------------------------------ + EL Torito CD booting for PC-BIOS x86, PowerPC, (old) Mac, EFI @@ -239,9 +243,9 @@ Byte Range | Value | Meaning 24 - 63 | 0 | Reserved ---------- | ---------- | ---------------------------------------------------- - ------------------------------------------------------------------------------ + MBR for PC-BIOS x86 from (pseudo-) hard disk @@ -480,7 +484,9 @@ Cleartext part: ------------------------------------------------------------------------------ - MIPSEL Little Endian MIPS , e.g. DECstation + + DEC Boot Block + for MIPS Little Endian , e.g. DECstation Sources: cdrkit-1.1.10/genisoimage/boot-mipsel.c @@ -495,6 +501,7 @@ Sources: There seems to be only one boot file possible. +Some information needs to be read out of the ELF headers of this boot file. Byte Range | Value | Meaning ---------- | ---------- | ---------------------------------------------------- @@ -514,12 +521,13 @@ Byte Range | Value | Meaning | | 24 - 31 | ========== | Boot Map Entry 1 | | - 24 - 27 | count | Segment size in file. + 24 - 27 | seg_size | Segment size in file. Blocks of 512 bytes. | | Stems from ELF header of boot file. | | (Elf32_Phdr field p_filesz + 511) / 512; | | - 28 - 31 | start | Segment file offset - | | Stems from ELF header of boot file. + 28 - 31 | seg_start | Segment file offset. Blocks 512 bytes. + | | ISO 9660 LBA of boot file * 4 plus offset + | | + offset which stems from ELF header of boot file: | | (Elf32_Phdr field p_offset + 511) / 512; | | 32 - 431 | ========== | Boot Map Entries 2 to 51 @@ -547,15 +555,15 @@ Byte Range | Value | Meaning 0 - 3 | | ( Segment type ) | | 4 - 7 | p_offset | /* Segment file offset */ - | -> start | Needed for start + |-> seg_start| Needed for seg_start | | 8 - 11 | p_vaddr | /* Segment virtual address */ - =load_address| Needed for load_address + | =load_adr | Needed for load_adr | | 12 - 15 | | (Segment physical address) | | 16 - 19 | p_filesz | /* Segment size in file */ - | -> count | Needed for count + |-> seg_size | Needed for seg_size | | diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 0b3cbc1..20d55ce 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1775,6 +1775,11 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size); * iso_image_add_mips_boot_file(). * This will overwrite the first 512 bytes of the submitted * data. + * 2= DEC Boot Block for MIPS Little Endian + * The first boot file submitted by + * iso_image_add_mips_boot_file() will be activated. + * This will overwrite the first 512 bytes of the submitted + * data. * @param flag * bit0 = invalidate any attached system area data. Same as data == NULL * (This re-activates eventually loaded image System Area data. @@ -2970,9 +2975,13 @@ int iso_image_get_system_area(IsoImage *img, char data[32768], int *options, int flag); /** - * Add a MIPS Big Endian boot file path to the image. Up to 15 such files can - * be written into a MIPS Big Endian Volume Header if this is enabled by - * value 1 in iso_write_opts_set_system_area() option bits 2 to 7. + * Add a MIPS boot file path to the image. + * Up to 15 such files can be written into a MIPS Big Endian Volume Header + * if this is enabled by value 1 in iso_write_opts_set_system_area() option + * bits 2 to 7. + * A single file can be written into a DEC Boot Block if this is enabled by + * value 2 in iso_write_opts_set_system_area() option bits 2 to 7. So only + * the first added file gets into effect with this system area type. * The data files which shall serve as MIPS boot files have to be brought into * the image by the normal means. * @param img @@ -6315,8 +6324,8 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); /** Too many MIPS Big Endian boot files given (max. 15) (FAILURE, HIGH, -365)*/ #define ISO_BOOT_TOO_MANY_MIPS 0xE830FE91 -/** MIPS Big Endian boot file missing in image (MISHAP, HIGH, -364) */ -#define ISO_BOOT_MIPS_MISSING 0xE430FE90 +/** Boot file missing in image (MISHAP, HIGH, -364) */ +#define ISO_BOOT_FILE_MISSING 0xE430FE90 diff --git a/libisofs/messages.c b/libisofs/messages.c index 79a8419..b7d8d73 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -352,8 +352,8 @@ const char *iso_error_to_msg(int errcode) return "Failed to process file for Jigdo Template Extraction"; case ISO_BOOT_TOO_MANY_MIPS: return "Too many MIPS Big Endian boot files given (max. 15)"; - case ISO_BOOT_MIPS_MISSING: - return "MIPS Big Endian boot file missing in image"; + case ISO_BOOT_FILE_MISSING: + return "Boot file missing in image"; default: return "Unknown error"; } diff --git a/libisofs/system_area.c b/libisofs/system_area.c index 6dfe501..1ee5f12 100644 --- a/libisofs/system_area.c +++ b/libisofs/system_area.c @@ -212,6 +212,41 @@ int iso_offset_partition_start(uint32_t img_blocks, uint32_t partition_offset, } +static int boot_nodes_from_iso_path(Ecma119Image *t, char *path, + IsoNode **iso_node, Ecma119Node **ecma_node, + char *purpose, int flag) +{ + int ret; + + ret = iso_tree_path_to_node(t->image, path, iso_node); + if (ret < 0) { + iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0, + "Cannot find %s '%s'", purpose, path); + return ISO_BOOT_FILE_MISSING; + } + if ((*iso_node)->type != LIBISO_FILE) { + iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, + "Designated boot file is not a data file: '%s'", path); + return ISO_BOOT_IMAGE_NOT_VALID; + } + + *ecma_node= ecma119_search_iso_node(t, *iso_node); + if (*ecma_node == NULL) { + iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, + "Program error: IsoFile has no Ecma119Node: '%s'", path); + return ISO_ASSERT_FAILURE; + } else { + if ((*ecma_node)->type != ECMA119_FILE) { + iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, + "Program error: Ecma119Node of IsoFile is no ECMA119_FILE: '%s'", + path); + return ISO_ASSERT_FAILURE; + } + } + return ISO_SUCCESS; +} + + /* This function was implemented according to doc/boot_sectors.txt section "MIPS Volume Header" which was derived by Thomas Schmitt from cdrkit-1.1.10/genisoimage/boot-mips.c by Steve McIntyre which is based @@ -273,13 +308,27 @@ static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag) #ifdef Libisofs_mips_boot_file_pathS for (idx = 0; idx < t->image->num_mips_boot_files; idx++) { + +#ifndef NIX + + ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[idx], + &node, &ecma_node, "MIPS boot file", 0); + if (ret < 0) + return ret; + + namept = (char *) iso_node_get_name(node); + name_field = (char *) (buf + (72 + 16 * idx)); + strncpy(name_field, namept, 8); + +#else /* ! NIX */ + ret = iso_tree_path_to_node(t->image, t->image->mips_boot_file_paths[idx], &node); if (ret < 0) { - iso_msg_submit(t->image->id, ISO_BOOT_MIPS_MISSING, 0, + iso_msg_submit(t->image->id, ISO_BOOT_FILE_MISSING, 0, "Cannot find MIPS boot file '%s'", t->image->mips_boot_file_paths[idx]); - return ISO_BOOT_MIPS_MISSING; + return ISO_BOOT_FILE_MISSING; } if (node->type != LIBISO_FILE) { iso_msg_submit(t->image->id, ISO_BOOT_IMAGE_NOT_VALID, 0, @@ -306,6 +355,10 @@ static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag) t->image->mips_boot_file_paths[idx]); return ISO_ASSERT_FAILURE; } + +#endif /* NIX */ + + file_lba = ecma_node->info.file->sections[0].block; iso_msb(buf + (72 + 16 * idx) + 8, file_lba * 4, 4); @@ -365,7 +418,129 @@ static int make_mips_volume_header(Ecma119Image *t, uint8_t *buf, int flag) } iso_msb(buf + 504, checksum, 4); - return 1; + return ISO_SUCCESS; +} + + +/* This function was implemented according to doc/boot_sectors.txt section + "MIPS Little Endian" which was derived by Thomas Schmitt from + cdrkit-1.1.10/genisoimage/boot-mipsel.c by Steve McIntyre which is based + on work of Florian Lohoff and Thiemo Seufer, and from by Free + Software Foundation, Inc. + This function itself is entirely under copyright (C) 2010 Thomas Schmitt. +*/ +static int make_mipsel_volume_header(Ecma119Image *t, uint8_t *buf, int flag) +{ + uint32_t load_adr, exec_adr, seg_size, seg_start, p_offset, p_filesz; + uint32_t phdr_adr; + off_t image_size; + int ret; + uint8_t elf_buf[32]; + char *path = NULL; + IsoNode *iso_node; + Ecma119Node *ecma_node; + IsoStream *stream; + FILE *fp = NULL; + + /* Bytes 512 to 32767 may come from image or external file */ + memset(buf, 0, 512); + + /* <<< Unused. No partition table or such ? */ + image_size = t->curblock * 2048; + + if (t->image->num_mips_boot_files <= 0) + return ISO_SUCCESS; /* There seems to be no partition table */ + + ret = boot_nodes_from_iso_path(t, t->image->mips_boot_file_paths[0], + &iso_node, &ecma_node, "MIPS boot file", 0); + if (ret < 0) + return ret; + stream = iso_file_get_stream((IsoFile *) iso_node); + + + /* <<< This does not work for boot file in old session */ + /* >>> Replace by iso_stream_open(), iso_stream_read() which has to be + done earlier, or system area production must happen before + iso_image_create_burn_source() ends. + */ + path= iso_stream_get_source_path(stream, 0); + if (path == NULL) { + iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0, + "Cannot determine disk path of designated MIPS boot file: '%s'", + t->image->mips_boot_file_paths[0]); + return ISO_ASSERT_FAILURE; + } + fp = fopen(path, "r"); + if (fp == NULL) { +cannot_read:; + iso_msg_submit(t->image->id, ISO_FILE_ERROR, 0, + "Cannot open designated MIPS boot file: '%s'", + path[0]); + if (fp != NULL) + fclose(fp); + free(path); + return ISO_FILE_ERROR; + } + free(path); + path = NULL; + + /* Read necessary ELF info */ + ret = fread(elf_buf, 32, 1, fp); + if (ret != 1) + goto cannot_read; + + + /* 24 - 27 | e_entry | Entry point virtual address */ + exec_adr = iso_read_lsb(elf_buf + 24, 4); + + /* 28 - 31 | e_phoff | Program header table file offset */ + phdr_adr = iso_read_lsb(elf_buf + 28, 4); + + /* <<< This does not work for boot file in old session */ + /* >>> replace by skip-reading of stream data */ + ret = fseek(fp, (long) phdr_adr, SEEK_SET); + if (ret != 1) + goto cannot_read; + ret = fread(elf_buf, 20, 1, fp); + if (ret != 1) + goto cannot_read; + + /* 4 - 7 | p_offset | Segment file offset */ + p_offset = iso_read_lsb(elf_buf + 4, 4); + + /* 8 - 11 | p_vaddr | Segment virtual address */ + load_adr = iso_read_lsb(elf_buf + 8, 4); + + /* 16 - 19 | p_filesz | Segment size in file */ + p_filesz = iso_read_lsb(elf_buf + 16, 4); + + fclose(fp); + fp = NULL; + + /* Write DEC Bootblock */ + + /* 8 - 11 | 0x0002757a | Magic number */ + iso_lsb(buf + 8, 0x0002757a, 4); + + /* 12 - 15 | 1 | Mode 1: Multi extent boot */ + iso_lsb(buf + 12, 1, 4); + + /* 16 - 19 | load_adr | Load address */ + iso_lsb(buf + 16, load_adr, 4); + + /* 20 - 23 | exec_adr | Execution address */ + iso_lsb(buf + 20, exec_adr, 4); + + /* 24 - 27 | seg_size | Segment size in file. */ + seg_size = (p_filesz + 511) / 512; + iso_lsb(buf + 24, seg_size, 4); + + /* 28 - 31 | seg_start | Segment file offset */ + seg_start = ecma_node->info.file->sections[0].block * 4 + + (p_offset + 511) / 512; + iso_lsb(buf + 28, seg_start, 4); + + return ISO_SUCCESS; } @@ -426,6 +601,10 @@ int iso_write_system_area(Ecma119Image *t, uint8_t *buf) ret = make_mips_volume_header(t, buf, 0); if (ret != ISO_SUCCESS) return ret; + } else if(sa_type == 2) { + ret = make_mipsel_volume_header(t, buf, 0); + if (ret != ISO_SUCCESS) + return ret; } else if(t->partition_offset > 0 && sa_type == 0) { /* Write a simple partition table. */ ret = make_grub_msdos_label(img_blocks, buf, 2);