xref: /linux/arch/powerpc/boot/mktree.c (revision 3c15a68880023722fc794018768df556f438ae98)
10cfcccb4SJosh Boyer /*
20cfcccb4SJosh Boyer  * Makes a tree bootable image for IBM Evaluation boards.
30cfcccb4SJosh Boyer  * Basically, just take a zImage, skip the ELF header, and stuff
40cfcccb4SJosh Boyer  * a 32 byte header on the front.
50cfcccb4SJosh Boyer  *
60cfcccb4SJosh Boyer  * We use htonl, which is a network macro, to make sure we're doing
70cfcccb4SJosh Boyer  * The Right Thing on an LE machine.  It's non-obvious, but it should
80cfcccb4SJosh Boyer  * work on anything BSD'ish.
90cfcccb4SJosh Boyer  */
100cfcccb4SJosh Boyer 
110cfcccb4SJosh Boyer #include <fcntl.h>
120cfcccb4SJosh Boyer #include <stdio.h>
130cfcccb4SJosh Boyer #include <stdlib.h>
140cfcccb4SJosh Boyer #include <string.h>
150cfcccb4SJosh Boyer #include <sys/stat.h>
160cfcccb4SJosh Boyer #include <unistd.h>
170cfcccb4SJosh Boyer #include <netinet/in.h>
180cfcccb4SJosh Boyer #ifdef __sun__
190cfcccb4SJosh Boyer #include <inttypes.h>
200cfcccb4SJosh Boyer #else
210cfcccb4SJosh Boyer #include <stdint.h>
220cfcccb4SJosh Boyer #endif
230cfcccb4SJosh Boyer 
240cfcccb4SJosh Boyer /* This gets tacked on the front of the image.  There are also a few
250cfcccb4SJosh Boyer  * bytes allocated after the _start label used by the boot rom (see
260cfcccb4SJosh Boyer  * head.S for details).
270cfcccb4SJosh Boyer  */
280cfcccb4SJosh Boyer typedef struct boot_block {
290cfcccb4SJosh Boyer 	uint32_t bb_magic;		/* 0x0052504F */
300cfcccb4SJosh Boyer 	uint32_t bb_dest;		/* Target address of the image */
310cfcccb4SJosh Boyer 	uint32_t bb_num_512blocks;	/* Size, rounded-up, in 512 byte blks */
320cfcccb4SJosh Boyer 	uint32_t bb_debug_flag;	/* Run debugger or image after load */
330cfcccb4SJosh Boyer 	uint32_t bb_entry_point;	/* The image address to start */
340cfcccb4SJosh Boyer 	uint32_t bb_checksum;	/* 32 bit checksum including header */
350cfcccb4SJosh Boyer 	uint32_t reserved[2];
360cfcccb4SJosh Boyer } boot_block_t;
370cfcccb4SJosh Boyer 
380cfcccb4SJosh Boyer #define IMGBLK	512
39*3c15a688SStephen Rothwell unsigned int	tmpbuf[IMGBLK / sizeof(unsigned int)];
400cfcccb4SJosh Boyer 
410cfcccb4SJosh Boyer int main(int argc, char *argv[])
420cfcccb4SJosh Boyer {
430cfcccb4SJosh Boyer 	int	in_fd, out_fd;
440cfcccb4SJosh Boyer 	int	nblks, i;
4593f1cc60STimur Tabi 	unsigned int	cksum, *cp;
460cfcccb4SJosh Boyer 	struct	stat	st;
470cfcccb4SJosh Boyer 	boot_block_t	bt;
480cfcccb4SJosh Boyer 
49f6dfc805SDavid Gibson 	if (argc < 5) {
50f6dfc805SDavid Gibson 		fprintf(stderr, "usage: %s <zImage-file> <boot-image> <load address> <entry point>\n",argv[0]);
510cfcccb4SJosh Boyer 		exit(1);
520cfcccb4SJosh Boyer 	}
530cfcccb4SJosh Boyer 
540cfcccb4SJosh Boyer 	if (stat(argv[1], &st) < 0) {
550cfcccb4SJosh Boyer 		perror("stat");
560cfcccb4SJosh Boyer 		exit(2);
570cfcccb4SJosh Boyer 	}
580cfcccb4SJosh Boyer 
590cfcccb4SJosh Boyer 	nblks = (st.st_size + IMGBLK) / IMGBLK;
600cfcccb4SJosh Boyer 
610cfcccb4SJosh Boyer 	bt.bb_magic = htonl(0x0052504F);
620cfcccb4SJosh Boyer 
630cfcccb4SJosh Boyer 	/* If we have the optional entry point parameter, use it */
64f6dfc805SDavid Gibson 	bt.bb_dest = htonl(strtoul(argv[3], NULL, 0));
65f6dfc805SDavid Gibson 	bt.bb_entry_point = htonl(strtoul(argv[4], NULL, 0));
660cfcccb4SJosh Boyer 
670cfcccb4SJosh Boyer 	/* We know these from the linker command.
680cfcccb4SJosh Boyer 	 * ...and then move it up into memory a little more so the
690cfcccb4SJosh Boyer 	 * relocation can happen.
700cfcccb4SJosh Boyer 	 */
710cfcccb4SJosh Boyer 	bt.bb_num_512blocks = htonl(nblks);
720cfcccb4SJosh Boyer 	bt.bb_debug_flag = 0;
730cfcccb4SJosh Boyer 
740cfcccb4SJosh Boyer 	bt.bb_checksum = 0;
750cfcccb4SJosh Boyer 
760cfcccb4SJosh Boyer 	/* To be neat and tidy :-).
770cfcccb4SJosh Boyer 	*/
780cfcccb4SJosh Boyer 	bt.reserved[0] = 0;
790cfcccb4SJosh Boyer 	bt.reserved[1] = 0;
800cfcccb4SJosh Boyer 
810cfcccb4SJosh Boyer 	if ((in_fd = open(argv[1], O_RDONLY)) < 0) {
820cfcccb4SJosh Boyer 		perror("zImage open");
830cfcccb4SJosh Boyer 		exit(3);
840cfcccb4SJosh Boyer 	}
850cfcccb4SJosh Boyer 
860cfcccb4SJosh Boyer 	if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) {
870cfcccb4SJosh Boyer 		perror("bootfile open");
880cfcccb4SJosh Boyer 		exit(3);
890cfcccb4SJosh Boyer 	}
900cfcccb4SJosh Boyer 
910cfcccb4SJosh Boyer 	cksum = 0;
920cfcccb4SJosh Boyer 	cp = (void *)&bt;
9393f1cc60STimur Tabi 	for (i = 0; i < sizeof(bt) / sizeof(unsigned int); i++)
940cfcccb4SJosh Boyer 		cksum += *cp++;
950cfcccb4SJosh Boyer 
960cfcccb4SJosh Boyer 	/* Assume zImage is an ELF file, and skip the 64K header.
970cfcccb4SJosh Boyer 	*/
98*3c15a688SStephen Rothwell 	if (read(in_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
990cfcccb4SJosh Boyer 		fprintf(stderr, "%s is too small to be an ELF image\n",
1000cfcccb4SJosh Boyer 				argv[1]);
1010cfcccb4SJosh Boyer 		exit(4);
1020cfcccb4SJosh Boyer 	}
1030cfcccb4SJosh Boyer 
104*3c15a688SStephen Rothwell 	if (tmpbuf[0] != htonl(0x7f454c46)) {
1050cfcccb4SJosh Boyer 		fprintf(stderr, "%s is not an ELF image\n", argv[1]);
1060cfcccb4SJosh Boyer 		exit(4);
1070cfcccb4SJosh Boyer 	}
1080cfcccb4SJosh Boyer 
1090cfcccb4SJosh Boyer 	if (lseek(in_fd, (64 * 1024), SEEK_SET) < 0) {
1100cfcccb4SJosh Boyer 		fprintf(stderr, "%s failed to seek in ELF image\n", argv[1]);
1110cfcccb4SJosh Boyer 		exit(4);
1120cfcccb4SJosh Boyer 	}
1130cfcccb4SJosh Boyer 
1140cfcccb4SJosh Boyer 	nblks -= (64 * 1024) / IMGBLK;
1150cfcccb4SJosh Boyer 
1160cfcccb4SJosh Boyer 	/* And away we go......
1170cfcccb4SJosh Boyer 	*/
1180cfcccb4SJosh Boyer 	if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
1190cfcccb4SJosh Boyer 		perror("boot-image write");
1200cfcccb4SJosh Boyer 		exit(5);
1210cfcccb4SJosh Boyer 	}
1220cfcccb4SJosh Boyer 
1230cfcccb4SJosh Boyer 	while (nblks-- > 0) {
124*3c15a688SStephen Rothwell 		if (read(in_fd, tmpbuf, sizeof(tmpbuf)) < 0) {
1250cfcccb4SJosh Boyer 			perror("zImage read");
1260cfcccb4SJosh Boyer 			exit(5);
1270cfcccb4SJosh Boyer 		}
128*3c15a688SStephen Rothwell 		cp = tmpbuf;
12993f1cc60STimur Tabi 		for (i = 0; i < sizeof(tmpbuf) / sizeof(unsigned int); i++)
1300cfcccb4SJosh Boyer 			cksum += *cp++;
1310cfcccb4SJosh Boyer 		if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
1320cfcccb4SJosh Boyer 			perror("boot-image write");
1330cfcccb4SJosh Boyer 			exit(5);
1340cfcccb4SJosh Boyer 		}
1350cfcccb4SJosh Boyer 	}
1360cfcccb4SJosh Boyer 
1370cfcccb4SJosh Boyer 	/* rewrite the header with the computed checksum.
1380cfcccb4SJosh Boyer 	*/
1390cfcccb4SJosh Boyer 	bt.bb_checksum = htonl(cksum);
1400cfcccb4SJosh Boyer 	if (lseek(out_fd, 0, SEEK_SET) < 0) {
1410cfcccb4SJosh Boyer 		perror("rewrite seek");
1420cfcccb4SJosh Boyer 		exit(1);
1430cfcccb4SJosh Boyer 	}
1440cfcccb4SJosh Boyer 	if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
1450cfcccb4SJosh Boyer 		perror("boot-image rewrite");
1460cfcccb4SJosh Boyer 		exit(1);
1470cfcccb4SJosh Boyer 	}
1480cfcccb4SJosh Boyer 
1490cfcccb4SJosh Boyer 	exit(0);
1500cfcccb4SJosh Boyer }
151