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