1/*
2 * BK Id: %F% %I% %G% %U% %#%
3 *
4 * Makes a tree bootable image for IBM Evaluation boards.
5 * Basically, just take a zImage, skip the ELF header, and stuff
6 * a 32 byte header on the front.
7 *
8 * We use htonl, which is a network macro, to make sure we're doing
9 * The Right Thing on an LE machine.  It's non-obvious, but it should
10 * work on anything BSD'ish.
11 */
12
13#include <fcntl.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/stat.h>
18#include <unistd.h>
19#include <netinet/in.h>
20
21/* This gets tacked on the front of the image.  There are also a few
22 * bytes allocated after the _start label used by the boot rom (see
23 * head.S for details).
24 */
25typedef struct boot_block {
26	unsigned long bb_magic;		/* 0x0052504F */
27	unsigned long bb_dest;		/* Target address of the image */
28	unsigned long bb_num_512blocks;	/* Size, rounded-up, in 512 byte blks */
29	unsigned long bb_debug_flag;	/* Run debugger or image after load */
30	unsigned long bb_entry_point;	/* The image address to start */
31	unsigned long bb_checksum;	/* 32 bit checksum including header */
32	unsigned long reserved[2];
33} boot_block_t;
34
35#define IMGBLK	512
36char	tmpbuf[IMGBLK];
37
38int main(int argc, char *argv[])
39{
40	int	in_fd, out_fd;
41	int	nblks, i;
42	uint	cksum, *cp;
43	struct	stat	st;
44	boot_block_t	bt;
45
46	if (argc < 3) {
47		fprintf(stderr, "usage: %s <zImage-file> <boot-image> [entry-point]\n",argv[0]);
48		exit(1);
49	}
50
51	if (stat(argv[1], &st) < 0) {
52		perror("stat");
53		exit(2);
54	}
55
56	nblks = (st.st_size + IMGBLK) / IMGBLK;
57
58	bt.bb_magic = htonl(0x0052504F);
59
60	/* If we have the optional entry point parameter, use it */
61	if (argc == 4)
62		bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0));
63	else
64		bt.bb_dest = bt.bb_entry_point = htonl(0x500000);
65
66	/* We know these from the linker command.
67	 * ...and then move it up into memory a little more so the
68	 * relocation can happen.
69	 */
70	bt.bb_num_512blocks = htonl(nblks);
71	bt.bb_debug_flag = 0;
72
73	bt.bb_checksum = 0;
74
75	/* To be neat and tidy :-).
76	*/
77	bt.reserved[0] = 0;
78	bt.reserved[1] = 0;
79
80	if ((in_fd = open(argv[1], O_RDONLY)) < 0) {
81		perror("zImage open");
82		exit(3);
83	}
84
85	if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) {
86		perror("bootfile open");
87		exit(3);
88	}
89
90	cksum = 0;
91	cp = (uint *)&bt;
92	for (i=0; i<sizeof(bt)/sizeof(uint); i++)
93		cksum += *cp++;
94
95	/* Assume zImage is an ELF file, and skip the 64K header.
96	*/
97	if (read(in_fd, tmpbuf, IMGBLK) != IMGBLK) {
98		fprintf(stderr, "%s is too small to be an ELF image\n",
99				argv[1]);
100		exit(4);
101	}
102
103	if ((*(uint *)tmpbuf) != htonl(0x7f454c46)) {
104		fprintf(stderr, "%s is not an ELF image\n", argv[1]);
105		exit(4);
106	}
107
108	if (lseek(in_fd, (64 * 1024), SEEK_SET) < 0) {
109		fprintf(stderr, "%s failed to seek in ELF image\n", argv[1]);
110		exit(4);
111	}
112
113	nblks -= (64 * 1024) / IMGBLK;
114
115	/* And away we go......
116	*/
117	if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
118		perror("boot-image write");
119		exit(5);
120	}
121
122	while (nblks-- > 0) {
123		if (read(in_fd, tmpbuf, IMGBLK) < 0) {
124			perror("zImage read");
125			exit(5);
126		}
127		cp = (uint *)tmpbuf;
128		for (i=0; i<sizeof(tmpbuf)/sizeof(uint); i++)
129			cksum += *cp++;
130		if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
131			perror("boot-image write");
132			exit(5);
133		}
134	}
135
136	/* rewrite the header with the computed checksum.
137	*/
138	bt.bb_checksum = htonl(cksum);
139	if (lseek(out_fd, 0, SEEK_SET) < 0) {
140		perror("rewrite seek");
141		exit(1);
142	}
143	if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) {
144		perror("boot-image rewrite");
145		exit(1);
146	}
147
148	exit(0);
149}
150