blob: 192bb397126fac25f5eae2901316252dc19803e6 [file] [log] [blame]
/*
* Makes a prep bootable image which can be dd'd onto
* a disk device to make a bootdisk. Will take
* as input a elf executable, strip off the header
* and write out a boot image as:
* 1) default - strips elf header
* suitable as a network boot image
* 2) -pbp - strips elf header and writes out prep boot partition image
* cat or dd onto disk for booting
* 3) -asm - strips elf header and writes out as asm data
* useful for generating data for a compressed image
* -- Cort
*
* Modified for x86 hosted builds by Matt Porter <porter@neta.com>
* Modified for Sparc hosted builds by Peter Wahl <PeterWahl@web.de>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* size of read buffer */
#define SIZE 0x1000
/*
* Partition table entry
* - from the PReP spec
*/
typedef struct partition_entry {
unsigned char boot_indicator;
unsigned char starting_head;
unsigned char starting_sector;
unsigned char starting_cylinder;
unsigned char system_indicator;
unsigned char ending_head;
unsigned char ending_sector;
unsigned char ending_cylinder;
unsigned char beginning_sector[4];
unsigned char number_of_sectors[4];
} partition_entry_t;
#define BootActive 0x80
#define SystemPrep 0x41
void copy_image(FILE *, FILE *);
void write_prep_partition(FILE *, FILE *);
void write_asm_data(FILE *, FILE *);
unsigned int elfhdr_size = 65536;
int main(int argc, char *argv[])
{
FILE *in, *out;
int argptr = 1;
int prep = 0;
int asmoutput = 0;
if (argc < 3 || argc > 4) {
fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",
argv[0]);
exit(-1);
}
/* needs to handle args more elegantly -- but this is a small/simple program */
/* check for -pbp */
if (!strcmp(argv[argptr], "-pbp")) {
prep = 1;
argptr++;
}
/* check for -asm */
if (!strcmp(argv[argptr], "-asm")) {
asmoutput = 1;
argptr++;
}
/* input file */
if (!strcmp(argv[argptr], "-"))
in = stdin;
else if (!(in = fopen(argv[argptr], "r")))
exit(-1);
argptr++;
/* output file */
if (!strcmp(argv[argptr], "-"))
out = stdout;
else if (!(out = fopen(argv[argptr], "w")))
exit(-1);
argptr++;
/* skip elf header in input file */
/*if ( !prep )*/
fseek(in, elfhdr_size, SEEK_SET);
/* write prep partition if necessary */
if (prep)
write_prep_partition(in, out);
/* write input image to bootimage */
if (asmoutput)
write_asm_data(in, out);
else
copy_image(in, out);
return 0;
}
void store_le32(unsigned int v, unsigned char *p)
{
p[0] = v;
p[1] = v >>= 8;
p[2] = v >>= 8;
p[3] = v >> 8;
}
void write_prep_partition(FILE *in, FILE *out)
{
unsigned char block[512];
partition_entry_t pe;
unsigned char *entry = block;
unsigned char *length = block + 4;
long pos = ftell(in), size;
if (fseek(in, 0, SEEK_END) < 0) {
fprintf(stderr,"info failed\n");
exit(-1);
}
size = ftell(in);
if (fseek(in, pos, SEEK_SET) < 0) {
fprintf(stderr,"info failed\n");
exit(-1);
}
memset(block, '\0', sizeof(block));
/* set entry point and boot image size skipping over elf header */
store_le32(0x400/*+65536*/, entry);
store_le32(size-elfhdr_size+0x400, length);
/* sets magic number for msdos partition (used by linux) */
block[510] = 0x55;
block[511] = 0xAA;
/*
* Build a "PReP" partition table entry in the boot record
* - "PReP" may only look at the system_indicator
*/
pe.boot_indicator = BootActive;
pe.system_indicator = SystemPrep;
/*
* The first block of the diskette is used by this "boot record" which
* actually contains the partition table. (The first block of the
* partition contains the boot image, but I digress...) We'll set up
* one partition on the diskette and it shall contain the rest of the
* diskette.
*/
pe.starting_head = 0; /* zero-based */
pe.starting_sector = 2; /* one-based */
pe.starting_cylinder = 0; /* zero-based */
pe.ending_head = 1; /* assumes two heads */
pe.ending_sector = 18; /* assumes 18 sectors/track */
pe.ending_cylinder = 79; /* assumes 80 cylinders/diskette */
/*
* The "PReP" software ignores the above fields and just looks at
* the next two.
* - size of the diskette is (assumed to be)
* (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
* - unlike the above sector numbers, the beginning sector is zero-based!
*/
#if 0
store_le32(1, pe.beginning_sector);
#else
/* This has to be 0 on the PowerStack? */
store_le32(0, pe.beginning_sector);
#endif
store_le32(2*18*80-1, pe.number_of_sectors);
memcpy(&block[0x1BE], &pe, sizeof(pe));
fwrite(block, sizeof(block), 1, out);
fwrite(entry, 4, 1, out);
fwrite(length, 4, 1, out);
/* set file position to 2nd sector where image will be written */
fseek( out, 0x400, SEEK_SET );
}
void copy_image(FILE *in, FILE *out)
{
char buf[SIZE];
int n;
while ( (n = fread(buf, 1, SIZE, in)) > 0 )
fwrite(buf, 1, n, out);
}
void
write_asm_data(FILE *in, FILE *out)
{
int i, cnt, pos = 0;
unsigned int cksum = 0, val;
unsigned char *lp;
unsigned char buf[SIZE];
size_t len;
fputs("\t.data\n\t.globl input_data\ninput_data:\n", out);
while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
cnt = 0;
lp = buf;
/* Round up to longwords */
while (len & 3)
buf[len++] = '\0';
for (i = 0; i < len; i += 4) {
if (cnt == 0)
fputs("\t.long\t", out);
fprintf(out, "0x%02X%02X%02X%02X",
lp[0], lp[1], lp[2], lp[3]);
val = *(unsigned long *)lp;
cksum ^= val;
lp += 4;
if (++cnt == 4) {
cnt = 0;
fprintf(out, " # %x \n", pos+i-12);
} else {
fputs(",", out);
}
}
if (cnt)
fputs("0\n", out);
pos += len;
}
fprintf(out, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
fprintf(stderr, "cksum = %x\n", cksum);
}