diff options
Diffstat (limited to 'genisoimage/boot-mipsel.c')
-rw-r--r-- | genisoimage/boot-mipsel.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/genisoimage/boot-mipsel.c b/genisoimage/boot-mipsel.c new file mode 100644 index 0000000..3d8ca65 --- /dev/null +++ b/genisoimage/boot-mipsel.c @@ -0,0 +1,259 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* + * Program boot-mipsel.c - Handle Mipsel boot extensions to iso9660. + * + * Written by Steve McIntyre <steve@einval.com> (2004). + * + * Heavily inspired by / borrowed from delo: + * + * Copyright: (C) 2002 by Florian Lohoff <flo@rfc822.org> + * (C) 2004 by Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, Version 2, as published by the + * Free Software Foundation. + * + * Format for volume header information + * + * The volume header is a block located at the beginning of all disk + * media (sector 0). It contains information pertaining to physical + * device parameters and logical partition information. + * + * The volume header is manipulated by disk formatters/verifiers, + * partition builders (e.g. fx, dvhtool, and mkfs), and disk drivers. + * + * Previous versions of IRIX wrote a copy of the volume header is + * located at sector 0 of each track of cylinder 0. These copies were + * never used, and reduced the capacity of the volume header to hold large + * files, so this practice was discontinued. + * The volume header is constrained to be less than or equal to 512 + * bytes long. A particular copy is assumed valid if no drive errors + * are detected, the magic number is correct, and the 32 bit 2's complement + * of the volume header is correct. The checksum is calculated by initially + * zeroing vh_csum, summing the entire structure and then storing the + * 2's complement of the sum. Thus a checksum to verify the volume header + * should be 0. + * + * The error summary table, bad sector replacement table, and boot blocks are + * located by searching the volume directory within the volume header. + * + * Tables are sized simply by the integral number of table records that + * will fit in the space indicated by the directory entry. + * + * The amount of space allocated to the volume header, replacement blocks, + * and other tables is user defined when the device is formatted. + */ + +#include <mconfig.h> +#include "genisoimage.h" +#include <fctldefs.h> +#include <utypes.h> +#include <intcvt.h> +#include "match.h" +#include "diskmbr.h" +#include "bootinfo.h" +#include <schily.h> +#include "endianconv.h" +#include <errno.h> +#include <glibc_elf.h> + +int add_boot_mipsel_filename(char *filename); +static int boot_mipsel_write(FILE *outfile); + +static char *boot_file_name = NULL; + +#define MAX_MAPS 51 +#define DEC_BOOT_MAGIC 0x02757a +#define HD_SECTOR_SIZE 512 + +/* Those were stolen from linux kernel headers. */ + +struct extent { + uint32_t count; + uint32_t start; +} +#ifdef __GNUC__ +__attribute__((packed)) +#endif + ; + +struct dec_bootblock { + int8_t pad[8]; + int32_t magic; /* We are a DEC BootBlock */ + int32_t mode; /* 0: Single extent, 1: Multi extent boot */ + int32_t loadAddr; /* Load below kernel */ + int32_t execAddr; /* And exec there */ + struct extent bootmap[MAX_MAPS]; +} +#ifdef __GNUC__ +__attribute__((packed)) +#endif + ; + +static void swap_in_elf32_ehdr(Elf32_Ehdr *ehdr) +{ + ehdr->e_type = read_le16((unsigned char *)&ehdr->e_type); + ehdr->e_machine = read_le16((unsigned char *)&ehdr->e_machine); + ehdr->e_version = read_le32((unsigned char *)&ehdr->e_version); + ehdr->e_entry = read_le32((unsigned char *)&ehdr->e_entry); + ehdr->e_phoff = read_le32((unsigned char *)&ehdr->e_phoff); + ehdr->e_shoff = read_le32((unsigned char *)&ehdr->e_shoff); + ehdr->e_flags = read_le32((unsigned char *)&ehdr->e_flags); + ehdr->e_ehsize = read_le16((unsigned char *)&ehdr->e_ehsize); + ehdr->e_phentsize = read_le16((unsigned char *)&ehdr->e_phentsize); + ehdr->e_phnum = read_le16((unsigned char *)&ehdr->e_phnum); + ehdr->e_shentsize = read_le16((unsigned char *)&ehdr->e_shentsize); + ehdr->e_shnum = read_le16((unsigned char *)&ehdr->e_shnum); + ehdr->e_shstrndx = read_le16((unsigned char *)&ehdr->e_shstrndx); +} + +static void swap_in_elf32_phdr(Elf32_Phdr *phdr) +{ + phdr->p_type = read_le32((unsigned char *)&phdr->p_type); + phdr->p_offset = read_le32((unsigned char *)&phdr->p_offset); + phdr->p_vaddr = read_le32((unsigned char *)&phdr->p_vaddr); + phdr->p_paddr = read_le32((unsigned char *)&phdr->p_paddr); + phdr->p_filesz = read_le32((unsigned char *)&phdr->p_filesz); + phdr->p_memsz = read_le32((unsigned char *)&phdr->p_memsz); + phdr->p_flags = read_le32((unsigned char *)&phdr->p_flags); + phdr->p_align = read_le32((unsigned char *)&phdr->p_align); +} + +/* Simple function: store the filename to be used later when we need + to find the boot file */ +extern int add_boot_mipsel_filename(char *filename) +{ + boot_file_name = filename; + return 0; +} + +/* Parse the ELF header of the boot loaded to work out the load + address and exec address */ +static int parse_boot_file(char *filename, int32_t *loadaddr, int32_t *execaddr, int32_t *offset, int32_t *count) +{ + int error = 0; + FILE *loader = NULL; + Elf32_Ehdr ehdr; + Elf32_Phdr phdr; + + loader = fopen(filename, "rb"); + if (!loader) + return errno; + + error = fread(&ehdr, sizeof(ehdr), 1, loader); + if (1 != error) + return EIO; + + swap_in_elf32_ehdr(&ehdr); + if (!(ehdr.e_ident[EI_MAG0] == ELFMAG0 + && ehdr.e_ident[EI_MAG1] == ELFMAG1 + && ehdr.e_ident[EI_MAG2] == ELFMAG2 + && ehdr.e_ident[EI_MAG3] == ELFMAG3 + && ehdr.e_ident[EI_CLASS] == ELFCLASS32 + && ehdr.e_ident[EI_DATA] == ELFDATA2LSB + && ehdr.e_ident[EI_VERSION] == EV_CURRENT + && ehdr.e_type == ET_EXEC + && ehdr.e_machine == EM_MIPS + && ehdr.e_version == EV_CURRENT)) + { + fprintf(stderr, "Sorry, %s is not a MIPS ELF32 little endian file", filename); + return EINVAL; + } + if (ehdr.e_phnum != 1) + { + fprintf(stderr, "Sorry, %s has more than one ELF segment", filename); + return EINVAL; + } + fseek(loader, ehdr.e_phoff, SEEK_SET); + error = fread(&phdr, sizeof(phdr), 1, loader); + if (1 != error) + return EIO; + + *loadaddr = phdr.p_vaddr; + *execaddr = ehdr.e_entry; + *offset = (phdr.p_offset + HD_SECTOR_SIZE - 1) / HD_SECTOR_SIZE; + *count = (phdr.p_filesz + HD_SECTOR_SIZE - 1) / HD_SECTOR_SIZE; + + fprintf(stderr, "Parsed mipsel boot image %s: using loadaddr 0x%X, execaddr 0x%X, offset 0x%X, count 0x%X\n", + filename, *loadaddr, *execaddr, *offset, *count); + + fclose(loader); + return 0; +} + +static int boot_mipsel_write(FILE *outfile) +{ + char sector[2048]; + struct dec_bootblock *bb = (struct dec_bootblock *)sector; + int error = 0; + int offset = 0; + int count = 0; + struct directory_entry *boot_file; /* Boot file we need to search for in the image */ + unsigned long length = 0; + unsigned long extent = 0; + int loadaddr = 0; + int execaddr = 0; + + memset(sector, 0, sizeof(sector)); + + /* Fill in our values we care on */ + write_le32(DEC_BOOT_MAGIC, (unsigned char *)&bb->magic); + write_le32(1, (unsigned char *)&bb->mode); + + /* Find the file entry in the CD image */ + boot_file = search_tree_file(root, boot_file_name); + if (!boot_file) + { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, "Uh oh, unable to find the mipsel boot file '%s'!\n", + boot_file_name); +#else + fprintf(stderr, "Uh oh, unable to find the mipsel boot file '%s'!\n", + boot_file_name); + exit(1); +#endif + } + + extent = get_733(boot_file->isorec.extent); + length = get_733(boot_file->isorec.size); + fprintf(stderr, "Found mipsel boot loader %s: using extent %lu, #blocks %lu\n", + boot_file_name, extent, length); + + /* Parse the ELF headers on the boot file */ + error = parse_boot_file(boot_file->whole_name, &loadaddr, &execaddr, &offset, &count); + if (error) + { +#ifdef USE_LIBSCHILY + comerrno(EX_BAD, "Uh oh, unable to parse the mipsel boot file '%s'!\n", + boot_file->whole_name); +#else + fprintf(stderr, "Uh oh, unable to parse the mipsel boot file '%s'!\n", + boot_file->whole_name); + exit(1); +#endif + } + + write_le32(loadaddr, (unsigned char *)&bb->loadAddr); + write_le32(execaddr, (unsigned char *)&bb->execAddr); + write_le32((extent * 4) + offset, (unsigned char *)&bb->bootmap[0].start); + write_le32(count, (unsigned char *)&bb->bootmap[0].count); + + jtwrite(sector, sizeof(sector), 1, 0, FALSE); + xfwrite(sector, sizeof(sector), 1, outfile, 0, FALSE); + last_extent_written++; + + return 0; +} + +struct output_fragment mipselboot_desc = {NULL, oneblock_size, NULL, boot_mipsel_write, "mipsel boot block"}; |