Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / genisoimage / boot-mipsel.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /*
14  * Program boot-mipsel.c - Handle Mipsel boot extensions to iso9660.
15  *
16  *  Written by Steve McIntyre <steve@einval.com> (2004).
17  *
18  * Heavily inspired by / borrowed from delo:
19  *
20  * Copyright: (C) 2002 by Florian Lohoff <flo@rfc822.org>
21  *            (C) 2004 by Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
22  *
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.
26  *
27  * Format for volume header information
28  *
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.
32  *
33  * The volume header is manipulated by disk formatters/verifiers,
34  * partition builders (e.g. fx, dvhtool, and mkfs), and disk drivers.
35  *
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
46  * should be 0.
47  *
48  * The error summary table, bad sector replacement table, and boot blocks are
49  * located by searching the volume directory within the volume header.
50  *
51  * Tables are sized simply by the integral number of table records that
52  * will fit in the space indicated by the directory entry.
53  *
54  * The amount of space allocated to the volume header, replacement blocks,
55  * and other tables is user defined when the device is formatted.
56  */
57
58 #include <mconfig.h>
59 #include "genisoimage.h"
60 #include <fctldefs.h>
61 #include <utypes.h>
62 #include <intcvt.h>
63 #include "match.h"
64 #include "diskmbr.h"
65 #include "bootinfo.h"
66 #include <schily.h>
67 #include "endianconv.h"
68 #include <errno.h>
69 #include <glibc_elf.h>
70
71 int             add_boot_mipsel_filename(char *filename);
72 static  int     boot_mipsel_write(FILE *outfile);
73
74 static  char   *boot_file_name = NULL;
75
76 #define MAX_MAPS        51
77 #define DEC_BOOT_MAGIC  0x02757a
78 #define HD_SECTOR_SIZE  512
79
80 /* Those were stolen from linux kernel headers. */
81
82 struct extent {
83     uint32_t count;
84     uint32_t start;
85 }
86 #ifdef __GNUC__
87 __attribute__((packed))
88 #endif
89    ;
90
91 struct dec_bootblock {
92     int8_t pad[8];
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];
98 }
99 #ifdef __GNUC__
100 __attribute__((packed))
101 #endif
102    ;
103
104 static void swap_in_elf32_ehdr(Elf32_Ehdr *ehdr)
105 {
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);
119 }
120
121 static void swap_in_elf32_phdr(Elf32_Phdr *phdr)
122 {
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);
131 }
132
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)
136 {
137     boot_file_name = filename;
138     return 0;
139 }
140
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)
144 {
145     int error = 0;
146     FILE *loader = NULL;
147     Elf32_Ehdr ehdr;
148     Elf32_Phdr phdr;
149     
150     loader = fopen(filename, "rb");
151     if (!loader)
152         return errno;
153     
154     error = fread(&ehdr, sizeof(ehdr), 1, loader);
155     if (1 != error)
156         return EIO;
157
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))
169     {
170         fprintf(stderr, "Sorry, %s is not a MIPS ELF32 little endian file", filename);        
171         return EINVAL;
172     }
173     if (ehdr.e_phnum != 1)
174     {
175         fprintf(stderr, "Sorry, %s has more than one ELF segment", filename);
176         return EINVAL;
177     }
178     fseek(loader, ehdr.e_phoff, SEEK_SET);
179     error = fread(&phdr, sizeof(phdr), 1, loader);
180     if (1 != error)
181         return EIO;
182
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;
187
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);
190
191     fclose(loader);
192     return 0;
193 }
194
195 static int boot_mipsel_write(FILE *outfile)
196 {
197     char sector[2048];
198     struct dec_bootblock *bb = (struct dec_bootblock *)sector;
199     int error = 0;
200     int offset = 0;
201     int count = 0;
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;
205     int loadaddr = 0;
206     int execaddr = 0;
207
208     memset(sector, 0, sizeof(sector));
209
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);
213
214     /* Find the file entry in the CD image */
215     boot_file = search_tree_file(root, boot_file_name);
216     if (!boot_file)
217     {
218 #ifdef  USE_LIBSCHILY
219                 comerrno(EX_BAD, "Uh oh, unable to find the mipsel boot file '%s'!\n",
220                  boot_file_name);
221 #else
222                 fprintf(stderr, "Uh oh, unable to find the mipsel boot file '%s'!\n",
223                 boot_file_name);
224                 exit(1);
225 #endif
226     }
227
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);
232
233     /* Parse the ELF headers on the boot file */
234     error = parse_boot_file(boot_file->whole_name, &loadaddr, &execaddr, &offset, &count);
235     if (error)
236     {
237 #ifdef  USE_LIBSCHILY
238                 comerrno(EX_BAD, "Uh oh, unable to parse the mipsel boot file '%s'!\n",
239                  boot_file->whole_name);
240 #else
241                 fprintf(stderr, "Uh oh, unable to parse the mipsel boot file '%s'!\n",
242                 boot_file->whole_name);
243                 exit(1);
244 #endif
245     }
246
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);
251     
252     jtwrite(sector, sizeof(sector), 1, 0, FALSE);
253     xfwrite(sector, sizeof(sector), 1, outfile, 0, FALSE);
254     last_extent_written++;
255
256     return 0;
257 }
258
259 struct output_fragment mipselboot_desc = {NULL, oneblock_size, NULL, boot_mipsel_write, "mipsel boot block"};