2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
14 * Program boot-mipsel.c - Handle Mipsel boot extensions to iso9660.
16 * Written by Steve McIntyre <steve@einval.com> (2004).
18 * Heavily inspired by / borrowed from delo:
20 * Copyright: (C) 2002 by Florian Lohoff <flo@rfc822.org>
21 * (C) 2004 by Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
23 * This program is free software; you can redistribute it and/or modify it under
24 * the terms of the GNU General Public License, Version 2, as published by the
25 * Free Software Foundation.
27 * Format for volume header information
29 * The volume header is a block located at the beginning of all disk
30 * media (sector 0). It contains information pertaining to physical
31 * device parameters and logical partition information.
33 * The volume header is manipulated by disk formatters/verifiers,
34 * partition builders (e.g. fx, dvhtool, and mkfs), and disk drivers.
36 * Previous versions of IRIX wrote a copy of the volume header is
37 * located at sector 0 of each track of cylinder 0. These copies were
38 * never used, and reduced the capacity of the volume header to hold large
39 * files, so this practice was discontinued.
40 * The volume header is constrained to be less than or equal to 512
41 * bytes long. A particular copy is assumed valid if no drive errors
42 * are detected, the magic number is correct, and the 32 bit 2's complement
43 * of the volume header is correct. The checksum is calculated by initially
44 * zeroing vh_csum, summing the entire structure and then storing the
45 * 2's complement of the sum. Thus a checksum to verify the volume header
48 * The error summary table, bad sector replacement table, and boot blocks are
49 * located by searching the volume directory within the volume header.
51 * Tables are sized simply by the integral number of table records that
52 * will fit in the space indicated by the directory entry.
54 * The amount of space allocated to the volume header, replacement blocks,
55 * and other tables is user defined when the device is formatted.
59 #include "genisoimage.h"
67 #include "endianconv.h"
69 #include <glibc_elf.h>
71 int add_boot_mipsel_filename(char *filename);
72 static int boot_mipsel_write(FILE *outfile);
74 static char *boot_file_name = NULL;
77 #define DEC_BOOT_MAGIC 0x02757a
78 #define HD_SECTOR_SIZE 512
80 /* Those were stolen from linux kernel headers. */
87 __attribute__((packed))
91 struct dec_bootblock {
93 int32_t magic; /* We are a DEC BootBlock */
94 int32_t mode; /* 0: Single extent, 1: Multi extent boot */
95 int32_t loadAddr; /* Load below kernel */
96 int32_t execAddr; /* And exec there */
97 struct extent bootmap[MAX_MAPS];
100 __attribute__((packed))
104 static void swap_in_elf32_ehdr(Elf32_Ehdr *ehdr)
106 ehdr->e_type = read_le16((unsigned char *)&ehdr->e_type);
107 ehdr->e_machine = read_le16((unsigned char *)&ehdr->e_machine);
108 ehdr->e_version = read_le32((unsigned char *)&ehdr->e_version);
109 ehdr->e_entry = read_le32((unsigned char *)&ehdr->e_entry);
110 ehdr->e_phoff = read_le32((unsigned char *)&ehdr->e_phoff);
111 ehdr->e_shoff = read_le32((unsigned char *)&ehdr->e_shoff);
112 ehdr->e_flags = read_le32((unsigned char *)&ehdr->e_flags);
113 ehdr->e_ehsize = read_le16((unsigned char *)&ehdr->e_ehsize);
114 ehdr->e_phentsize = read_le16((unsigned char *)&ehdr->e_phentsize);
115 ehdr->e_phnum = read_le16((unsigned char *)&ehdr->e_phnum);
116 ehdr->e_shentsize = read_le16((unsigned char *)&ehdr->e_shentsize);
117 ehdr->e_shnum = read_le16((unsigned char *)&ehdr->e_shnum);
118 ehdr->e_shstrndx = read_le16((unsigned char *)&ehdr->e_shstrndx);
121 static void swap_in_elf32_phdr(Elf32_Phdr *phdr)
123 phdr->p_type = read_le32((unsigned char *)&phdr->p_type);
124 phdr->p_offset = read_le32((unsigned char *)&phdr->p_offset);
125 phdr->p_vaddr = read_le32((unsigned char *)&phdr->p_vaddr);
126 phdr->p_paddr = read_le32((unsigned char *)&phdr->p_paddr);
127 phdr->p_filesz = read_le32((unsigned char *)&phdr->p_filesz);
128 phdr->p_memsz = read_le32((unsigned char *)&phdr->p_memsz);
129 phdr->p_flags = read_le32((unsigned char *)&phdr->p_flags);
130 phdr->p_align = read_le32((unsigned char *)&phdr->p_align);
133 /* Simple function: store the filename to be used later when we need
134 to find the boot file */
135 extern int add_boot_mipsel_filename(char *filename)
137 boot_file_name = filename;
141 /* Parse the ELF header of the boot loaded to work out the load
142 address and exec address */
143 static int parse_boot_file(char *filename, int32_t *loadaddr, int32_t *execaddr, int32_t *offset, int32_t *count)
150 loader = fopen(filename, "rb");
154 error = fread(&ehdr, sizeof(ehdr), 1, loader);
158 swap_in_elf32_ehdr(&ehdr);
159 if (!(ehdr.e_ident[EI_MAG0] == ELFMAG0
160 && ehdr.e_ident[EI_MAG1] == ELFMAG1
161 && ehdr.e_ident[EI_MAG2] == ELFMAG2
162 && ehdr.e_ident[EI_MAG3] == ELFMAG3
163 && ehdr.e_ident[EI_CLASS] == ELFCLASS32
164 && ehdr.e_ident[EI_DATA] == ELFDATA2LSB
165 && ehdr.e_ident[EI_VERSION] == EV_CURRENT
166 && ehdr.e_type == ET_EXEC
167 && ehdr.e_machine == EM_MIPS
168 && ehdr.e_version == EV_CURRENT))
170 fprintf(stderr, "Sorry, %s is not a MIPS ELF32 little endian file", filename);
173 if (ehdr.e_phnum != 1)
175 fprintf(stderr, "Sorry, %s has more than one ELF segment", filename);
178 fseek(loader, ehdr.e_phoff, SEEK_SET);
179 error = fread(&phdr, sizeof(phdr), 1, loader);
183 *loadaddr = phdr.p_vaddr;
184 *execaddr = ehdr.e_entry;
185 *offset = (phdr.p_offset + HD_SECTOR_SIZE - 1) / HD_SECTOR_SIZE;
186 *count = (phdr.p_filesz + HD_SECTOR_SIZE - 1) / HD_SECTOR_SIZE;
188 fprintf(stderr, "Parsed mipsel boot image %s: using loadaddr 0x%X, execaddr 0x%X, offset 0x%X, count 0x%X\n",
189 filename, *loadaddr, *execaddr, *offset, *count);
195 static int boot_mipsel_write(FILE *outfile)
198 struct dec_bootblock *bb = (struct dec_bootblock *)sector;
202 struct directory_entry *boot_file; /* Boot file we need to search for in the image */
203 unsigned long length = 0;
204 unsigned long extent = 0;
208 memset(sector, 0, sizeof(sector));
210 /* Fill in our values we care on */
211 write_le32(DEC_BOOT_MAGIC, (unsigned char *)&bb->magic);
212 write_le32(1, (unsigned char *)&bb->mode);
214 /* Find the file entry in the CD image */
215 boot_file = search_tree_file(root, boot_file_name);
219 comerrno(EX_BAD, "Uh oh, unable to find the mipsel boot file '%s'!\n",
222 fprintf(stderr, "Uh oh, unable to find the mipsel boot file '%s'!\n",
228 extent = get_733(boot_file->isorec.extent);
229 length = get_733(boot_file->isorec.size);
230 fprintf(stderr, "Found mipsel boot loader %s: using extent %lu, #blocks %lu\n",
231 boot_file_name, extent, length);
233 /* Parse the ELF headers on the boot file */
234 error = parse_boot_file(boot_file->whole_name, &loadaddr, &execaddr, &offset, &count);
238 comerrno(EX_BAD, "Uh oh, unable to parse the mipsel boot file '%s'!\n",
239 boot_file->whole_name);
241 fprintf(stderr, "Uh oh, unable to parse the mipsel boot file '%s'!\n",
242 boot_file->whole_name);
247 write_le32(loadaddr, (unsigned char *)&bb->loadAddr);
248 write_le32(execaddr, (unsigned char *)&bb->execAddr);
249 write_le32((extent * 4) + offset, (unsigned char *)&bb->bootmap[0].start);
250 write_le32(count, (unsigned char *)&bb->bootmap[0].count);
252 jtwrite(sector, sizeof(sector), 1, 0, FALSE);
253 xfwrite(sector, sizeof(sector), 1, outfile, 0, FALSE);
254 last_extent_written++;
259 struct output_fragment mipselboot_desc = {NULL, oneblock_size, NULL, boot_mipsel_write, "mipsel boot block"};