/* * 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 * Modified for Sparc hosted builds by Peter Wahl */ #include #include #include /* 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] \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); }