| /* |
| * 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); |
| } |