diff options
Diffstat (limited to 'genisoimage/boot-mips.c')
-rw-r--r-- | genisoimage/boot-mips.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/genisoimage/boot-mips.c b/genisoimage/boot-mips.c new file mode 100644 index 0000000..956b94f --- /dev/null +++ b/genisoimage/boot-mips.c @@ -0,0 +1,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"}; |