summaryrefslogtreecommitdiff
path: root/genisoimage/boot-mips.c
blob: 956b94f00babb37e57ea71014da4a87981c60b01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/*
 * 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-mips.c - Handle big-endian boot extensions to iso9660.
 *
 * Written by Steve McIntyre <steve@einval.com> June 2004
 *
 * Heavily inspired by / borrowed from genisovh:
 *
 * 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 <inttypes.h>
#ifndef MIN
#define MIN(a,b) ( (a<b) ? a : b )
#endif

/*
 * device parameters are in the volume header to determine mapping
 * from logical block numbers to physical device addresses
 *
 * Linux doesn't care ...
 */
struct device_parameters {
	uint8_t dp_skew;	/* spiral addressing skew */
	uint8_t dp_gap1;	/* words of 0 before header */
	uint8_t dp_gap2;	/* words of 0 between hdr and data */
	uint8_t dp_spares_cyl;	/* This is for drives (such as SCSI
		that support zone oriented sparing, where the zone is larger
		than one track.  It gets subracteded from the cylinder size
		( dp_trks0 * dp_sec) when doing partition size calculations */
	uint16_t dp_cyls;	/* number of usable cylinders (i.e.,
		doesn't include cylinders reserved by the drive for badblocks,
		etc.). For drives with variable geometry, this number may be
		decreased so that:
		dp_cyls * ((dp_heads * dp_trks0) - dp_spares_cyl) <= actualcapacity
		This happens on SCSI drives such as the Wren IV and Toshiba 156
		Also see dp_cylshi below */
	uint16_t dp_shd0;	/* starting head vol 0 */
	uint16_t dp_trks0;	/* number of tracks / cylinder vol 0*/
	uint8_t dp_ctq_depth;	/* Depth of CTQ queue */
	uint8_t dp_cylshi;	/* high byte of 24 bits of cylinder count */
	uint16_t dp_unused;	/* not used */
	uint16_t dp_secs;	/* number of sectors/track */
	uint16_t dp_secbytes;	/* length of sector in bytes */
	uint16_t dp_interleave;	/* sector interleave */
	int32_t dp_flags;		/* controller characteristics */
	int32_t dp_datarate;		/* bytes/sec for kernel stats */
	int32_t dp_nretries;		/* max num retries on data error */
	int32_t dp_mspw;		/* ms per word to xfer, for iostat */
	uint16_t dp_xgap1;	/* Gap 1 for xylogics controllers */
	uint16_t dp_xsync;    /* sync delay for xylogics controllers */
	uint16_t dp_xrdly;    /* read delay for xylogics controllers */
	uint16_t dp_xgap2;    /* gap 2 for xylogics controllers */
	uint16_t dp_xrgate;   /* read gate for xylogics controllers */
	uint16_t dp_xwcont;   /* write continuation for xylogics */
};

/*
 * Device characterization flags
 * (dp_flags)
 */
#define	DP_SECTSLIP	0x00000001	/* sector slip to spare sector */
#define	DP_SECTFWD	0x00000002	/* forward to replacement sector */
#define	DP_TRKFWD	0x00000004	/* forward to replacement track */
#define	DP_MULTIVOL	0x00000008	/* multiple volumes per spindle */
#define	DP_IGNOREERRORS	0x00000010	/* transfer data regardless of errors */
#define DP_RESEEK	0x00000020	/* recalibrate as last resort */
#define	DP_CTQ_EN	0x00000040	/* enable command tag queueing */

/*
 * Boot blocks, bad sector tables, and the error summary table, are located
 * via the volume_directory.
 */
#define VDNAMESIZE	8

struct volume_directory {
	int8_t  vd_name[VDNAMESIZE];	/* name */
	int32_t vd_lbn;			/* logical block number */
	int32_t vd_nbytes;		/* file length in bytes */
};

/*
 * partition table describes logical device partitions
 * (device drivers examine this to determine mapping from logical units
 * to cylinder groups, device formatters/verifiers examine this to determine
 * location of replacement tracks/sectors, etc)
 *
 * NOTE: pt_firstlbn SHOULD BE CYLINDER ALIGNED
 */
struct partition_table {		/* one per logical partition */
	int32_t pt_nblks;		/* # of logical blks in partition */
	int32_t pt_firstlbn;		/* first lbn of partition */
	int32_t pt_type;		/* use of partition */
};

#define	PTYPE_VOLHDR	0		/* partition is volume header */
#define	PTYPE_TRKREPL	1		/* partition is used for repl trks */
#define	PTYPE_SECREPL	2		/* partition is used for repl secs */
#define	PTYPE_RAW	3		/* partition is used for data */
#define	PTYPE_BSD42	4		/* partition is 4.2BSD file system */
#define	PTYPE_BSD	4		/* partition is 4.2BSD file system */
#define	PTYPE_SYSV	5		/* partition is SysV file system */
#define	PTYPE_VOLUME	6		/* partition is entire volume */
#define	PTYPE_EFS	7		/* partition is sgi EFS */
#define	PTYPE_LVOL	8		/* partition is part of a logical vol */
#define	PTYPE_RLVOL	9		/* part of a "raw" logical vol */
#define	PTYPE_XFS	10		/* partition is sgi XFS */
#define	PTYPE_XFSLOG	11		/* partition is sgi XFS log */
#define	PTYPE_XLV	12		/* partition is part of an XLV vol */
#define	PTYPE_XVM	13		/* partition is sgi XVM */
#define	PTYPE_LSWAP	0x82		/* partition is Linux swap */
#define	PTYPE_LINUX	0x83		/* partition is Linux native */
#define NPTYPES		16

#define	VHMAGIC		0xbe5a941	/* randomly chosen value */
#define	NPARTAB		16		/* 16 unix partitions */
#define	NVDIR		15		/* max of 15 directory entries */
#define BFNAMESIZE	16		/* max 16 chars in boot file name */

/* Partition types for ARCS */
#define NOT_USED        0       /* Not used 				*/
#define FAT_SHORT       1       /* FAT filesystem, 12-bit FAT entries 	*/
#define FAT_LONG        4       /* FAT filesystem, 16-bit FAT entries 	*/
#define EXTENDED        5       /* extended partition 			*/
#define HUGE            6       /* huge partition- MS/DOS 4.0 and later */

/* Active flags for ARCS */
#define BOOTABLE        0x00;
#define NOT_BOOTABLE    0x80;

struct volume_header {
	int32_t vh_magic; /* identifies volume header */
	int16_t vh_rootpt; /* root partition number */
	int16_t vh_swappt; /* swap partition number */
	int8_t vh_bootfile[BFNAMESIZE]; /* name of file to boot */
	struct device_parameters vh_dp; /* device parameters */
	struct volume_directory vh_vd[NVDIR]; /* other vol hdr contents */
	struct partition_table vh_pt[NPARTAB]; /* device partition layout */
	int32_t vh_csum; /* volume header checksum */
	int32_t vh_fill; /* fill out to 512 bytes */
    char pad[1536];  /* pad out to 2048 */
};

#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"

int     add_boot_mips_filename(char *filename);

static  int     boot_mips_write(FILE *outfile);

#define MAX_NAMES 15
static char *boot_mips_filename[MAX_NAMES] =
{
    NULL, NULL, NULL,
    NULL, NULL, NULL,
    NULL, NULL, NULL,
    NULL, NULL, NULL,
    NULL, NULL, NULL
};

static int boot_mips_num_files = 0;

#define SECTORS_PER_TRACK	32
#define BYTES_PER_SECTOR	512

int add_boot_mips_filename(char *filename)
{
    if (boot_mips_num_files < MAX_NAMES)
    {
        boot_mips_filename[boot_mips_num_files] = filename;
        boot_mips_num_files++;
    }

    else
    {
#ifdef	USE_LIBSCHILY
        comerrno(EX_BAD, "Too many MIPS boot files!\n");
#else
        fprintf(stderr, "Too many MIPS boot files!\n");
        exit(1);
#endif
    }
    return 0;
}

static void vh_calc_checksum(struct volume_header *vh)
{
	uint32_t newsum = 0;
	unsigned char *buffer = (unsigned char *)vh;
	unsigned int i;

	vh->vh_csum = 0;

	for(i = 0; i < sizeof(struct volume_header); i += 4)
        newsum -= read_be32(&buffer[i]);

    write_be32(newsum, (unsigned char *)&vh->vh_csum);
}

static char *file_base_name(char *path)
{
    char *endptr = path;
    char *ptr = path;
    
    while (*ptr != '\0')
    {
        if ('/' == *ptr)
            endptr = ++ptr;
        else
            ++ptr;
    }
    return endptr;
}

static int boot_mips_write(FILE *outfile)
{
	struct directory_entry	*boot_file;	/* Boot file we need to search for */
    unsigned long length = 0;
    unsigned long extent = 0;
	int i;
	struct volume_header vh;
    unsigned long long iso_size = 0;
    char *filename = NULL;

	memset(&vh, 0, sizeof(vh));

    iso_size = last_extent * 2048;

    write_be32(VHMAGIC, (unsigned char *)&vh.vh_magic);

	/* Values from an IRIX cd */
    write_be16(BYTES_PER_SECTOR, (unsigned char *)&vh.vh_dp.dp_secbytes);
    write_be16(SECTORS_PER_TRACK, (unsigned char *)&vh.vh_dp.dp_secs);
    write_be32(DP_RESEEK|DP_IGNOREERRORS|DP_TRKFWD, (unsigned char *)&vh.vh_dp.dp_flags);
    write_be16(1, (unsigned char *)&vh.vh_dp.dp_trks0);

    write_be16((iso_size + BYTES_PER_SECTOR - 1) / (SECTORS_PER_TRACK * BYTES_PER_SECTOR),
               (unsigned char *)&vh.vh_dp.dp_cyls);

	for(i = 0; i < boot_mips_num_files; i++)
    {
        boot_file = search_tree_file(root, boot_mips_filename[i]);
        
        if (!boot_file) {
#ifdef	USE_LIBSCHILY
            comerrno(EX_BAD, "Uh oh, I cant find the MIPS boot file '%s'!\n",
                     boot_mips_filename[i]);
#else
            fprintf(stderr, "Uh oh, I cant find the MIPS boot file '%s'!\n",
                    boot_mips_filename[i]);
            exit(1);
#endif
        }

        extent = get_733(boot_file->isorec.extent) * 4;
        length = ((get_733(boot_file->isorec.size) + 2047) / 2048) * 2048;
        filename = file_base_name(boot_mips_filename[i]);

        strncpy((char *)vh.vh_vd[i].vd_name, filename, MIN(VDNAMESIZE, strlen(filename)));
        write_be32(extent, (unsigned char *)&vh.vh_vd[i].vd_lbn);
        write_be32(length, (unsigned char *)&vh.vh_vd[i].vd_nbytes);
        
        fprintf(stderr, "Found mips boot image %s, using extent %lu (0x%lX), #blocks %lu (0x%lX)\n",
                filename, extent, extent, length, length);
	}

	/* Create volume partition on whole cd iso */
    write_be32((iso_size + (BYTES_PER_SECTOR - 1))/ BYTES_PER_SECTOR, (unsigned char *)&vh.vh_pt[10].pt_nblks);
    write_be32(0, (unsigned char *)&vh.vh_pt[10].pt_firstlbn);
    write_be32(PTYPE_VOLUME, (unsigned char *)&vh.vh_pt[10].pt_type);

	/* Create volume header partition, also on WHOLE cd iso */
    write_be32((iso_size + (BYTES_PER_SECTOR - 1))/ BYTES_PER_SECTOR, (unsigned char *)&vh.vh_pt[8].pt_nblks);
    write_be32(0, (unsigned char *)&vh.vh_pt[8].pt_firstlbn);
    write_be32(PTYPE_VOLHDR, (unsigned char *)&vh.vh_pt[8].pt_type);

	/* Create checksum */
	vh_calc_checksum(&vh);

    jtwrite(&vh, sizeof(vh), 1, 0, FALSE);
    xfwrite(&vh, sizeof(vh), 1, outfile, 0, FALSE);
    last_extent_written++;

	return 0;
}

struct output_fragment mipsboot_desc = {NULL, oneblock_size, NULL, boot_mips_write, "MIPS boot block"};