1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Boot program installer			File: installboot.c
5    *
6    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
7    *
8    *  This program converts a binary file (bootstrap program)
9    *  into a boot block by prepending the boot block sector
10    *  to the program.  It generates the appropriate
11    *  boot block checksums and such.  The resulting file may
12    *  be used by installboot (for example) to put into a disk
13    *  image for the simulator.
14    *
15    *********************************************************************
16    *
17    *  Copyright 2000,2001,2002,2003
18    *  Broadcom Corporation. All rights reserved.
19    *
20    *  This software is furnished under license and may be used and
21    *  copied only in accordance with the following terms and
22    *  conditions.  Subject to these conditions, you may download,
23    *  copy, install, use, modify and distribute modified or unmodified
24    *  copies of this software in source and/or binary form.  No title
25    *  or ownership is transferred hereby.
26    *
27    *  1) Any source code used, modified or distributed must reproduce
28    *     and retain this copyright notice and list of conditions
29    *     as they appear in the source file.
30    *
31    *  2) No right is granted to use any trade name, trademark, or
32    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
33    *     name may not be used to endorse or promote products derived
34    *     from this software without the prior written permission of
35    *     Broadcom Corporation.
36    *
37    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
38    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
39    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
40    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
41    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
42    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
43    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
45    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
46    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
47    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
48    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
49    *     THE POSSIBILITY OF SUCH DAMAGE.
50    ********************************************************************* */
51
52#include <sys/types.h>
53#include <sys/stat.h>
54
55typedef unsigned long long uint64_t;
56typedef unsigned long uint32_t;
57
58#include "cfe_bootblock.h"
59#include <fcntl.h>
60#include <stdlib.h>
61#include <stdio.h>
62#include <string.h>
63
64#define roundup(x,align) (((x)+(align)-1)&~((align)-1))
65#define howmany(x,align) (((x)+(align)-1)/(align))
66
67static int verbose = 0;
68static int big_endian = 1;
69static int swapflg = 1;
70static unsigned long bootcode_offset = 2;
71static unsigned long bootsect_offset = 1;
72
73static void usage(void)
74{
75    fprintf(stderr,"usage: installboot [-bootsect <sector offset>] [-bootcode <sector offset>]\n"
76	           "                   [-v] [-EB] [-EL] bootloaderfile.bin devicefile\n\n");
77    fprintf(stderr,"This program installs a boot block onto a disk.  Typically, installboot\n"
78	           "is used to install sibyl or other OS bootloaders.  The binary you install\n"
79	           "should be a raw program (not ELF) located to run in CFE's boot area\n"
80	           "at address 0x2000_0000.  The devicefile should be the name of the raw device\n"
81	           "such as /dev/hda on Linux.\n\n"
82	           "Care must be taken when choosing the values for -bootsect and -bootcode\n"
83	           "not to interfere with other partitions on your disk.   When partitioning,\n"
84	           "it's a good idea to reserve 3 cylinders at the beginning of the disk for\n"
85	           "the boot loader.\n\n"
86	           "-bootsect nn    specifies that the boot sector will be placed on sector 'nn'\n"
87	           "-bootcode nn    specifies that the boot program itself will be placed\n"
88	           "                on sectors starting with 'nn'.  The boot sector will point\n"
89	           "                to this sector.\n");
90
91    exit(1);
92}
93
94static void bswap32(uint32_t *ptr)
95{
96    unsigned char b;
97    unsigned char *bptr;
98
99    if (swapflg) {
100	bptr = (unsigned char *) ptr;
101	b = bptr[0]; bptr[0] = bptr[3]; bptr[3] = b;
102	b = bptr[1]; bptr[1] = bptr[2]; bptr[2] = b;
103	}
104}
105
106static void bswap64(uint64_t *ptr)
107{
108    unsigned char b;
109    unsigned char *bptr;
110
111    bptr = (unsigned char *) ptr;
112
113    if (swapflg) {
114	b = bptr[0]; bptr[0] = bptr[7]; bptr[7] = b;
115	b = bptr[1]; bptr[1] = bptr[6]; bptr[6] = b;
116	b = bptr[2]; bptr[2] = bptr[5]; bptr[5] = b;
117	b = bptr[3]; bptr[3] = bptr[4]; bptr[4] = b;
118	}
119}
120
121
122static void bswap_bootblock(struct boot_block *bb)
123{
124    int idx;
125
126    for (idx = 59; idx <= 63; idx++) {
127	bswap64(&(bb->bb_data[idx]));
128	}
129}
130
131static void do_checksum(void *ptr,int length,uint32_t *csptr,int swap)
132{
133    uint32_t *p;
134    uint32_t chksum = 0;
135    uint32_t d;
136
137    p = (uint32_t *) ptr;
138
139    length /= sizeof(uint32_t);
140
141    while (length) {
142	d = *p;
143	if (swap) bswap32(&d);
144	chksum += d;
145	p++;
146	length--;
147	}
148
149    if (swap) bswap32(&chksum);
150
151    *csptr = chksum;
152}
153
154
155static void dumpbootblock(struct boot_block *bb)
156{
157    int idx;
158
159    fprintf(stderr,"Magic Number:       %016llX\n",
160	    bb->bb_magic);
161    fprintf(stderr,"Boot code offset:   %llu\n",
162	    (unsigned long long)bb->bb_secstart);
163    fprintf(stderr,"Boot code size:     %u\n",
164	    (uint32_t) (bb->bb_secsize & BOOT_SECSIZE_MASK));
165    fprintf(stderr,"Header checksum:    %08X\n",
166	    (uint32_t) (bb->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK));
167    fprintf(stderr,"Header version:     %d\n",
168	    (uint32_t) ((bb->bb_hdrinfo  & BOOT_HDR_VER_MASK) >> BOOT_HDR_VER_SHIFT));
169    fprintf(stderr,"Data checksum:      %08X\n",
170	    (uint32_t) ((bb->bb_secsize & BOOT_DATA_CHECKSUM_MASK) >> BOOT_DATA_CHECKSUM_SHIFT));
171    fprintf(stderr,"Architecture info:  %08X\n",
172	    (uint32_t) (bb->bb_archinfo & BOOT_ARCHINFO_MASK));
173    fprintf(stderr,"\n");
174
175    for (idx = 59; idx <= 63; idx++) {
176	fprintf(stderr,"Word %d = %016llX\n",idx,bb->bb_data[idx]);
177	}
178}
179
180static int host_is_little(void)
181{
182    unsigned long var = 1;
183    unsigned char *pvar = (unsigned char *) &var;
184
185    return (*pvar == 1);
186}
187
188int main(int argc, char *argv[])
189{
190    int fh;
191    long bootsize;
192    long bootbufsize;
193    unsigned char *bootcode;
194    struct boot_block bootblock;
195    uint32_t datacsum,hdrcsum;
196    int host_le;
197
198    while ((argc > 1) && (argv[1][0] == '-')) {
199	if (strcmp(argv[1],"-v") == 0) {
200	    verbose = 1;
201	    }
202	else if (strcmp(argv[1],"-EB") == 0) {
203	    big_endian = 1;
204	    }
205	else if (strcmp(argv[1],"-EL") == 0) {
206	    big_endian = 0;
207	    }
208        else if (strcmp(argv[1],"-bootsect") == 0) {
209	    char *tmp_ptr;
210	    argv++;
211	    argc--;
212	    if (argc == 1) {
213	    	fprintf(stderr,"-bootsect requires an argument\n");
214	    	exit(1);
215	        }
216	    bootsect_offset = strtoul(argv[1], &tmp_ptr, 0);
217	    bootcode_offset = bootsect_offset + 1;	/* default if -bootcode not specified */
218	    if (*tmp_ptr) {
219	    	fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]);
220	    	exit(1);
221		}
222	    }
223        else if (strcmp(argv[1],"-bootcode") == 0) {
224	    char *tmp_ptr;
225	    argv++;
226	    argc--;
227	    if (argc == 1) {
228	    	fprintf(stderr,"-bootcode requires an argument\n");
229	    	exit(1);
230	        }
231	    bootcode_offset = strtoul(argv[1], &tmp_ptr, 0);
232	    if (*tmp_ptr) {
233	    	fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]);
234	    	exit(1);
235		}
236	    }
237	else {
238	    fprintf(stderr,"Invalid switch: %s\n",argv[1]);
239	    exit(1);
240	    }
241	argv++;
242	argc--;
243	}
244
245    /*
246     * We need to swap things around if the host and
247     * target are different endianness
248     */
249
250    swapflg = 0;
251    host_le = host_is_little();
252
253    if (big_endian && host_is_little()) swapflg = 1;
254    if ((big_endian == 0) && !(host_is_little())) swapflg = 1;
255
256    fprintf(stderr,"Host is %s-endian.\n",host_le ? "little" : "big");
257    fprintf(stderr,"Target is %s-endian.\n",big_endian ? "big" : "little");
258
259    if (argc != 3) {
260	usage();
261	}
262
263    /*
264     * Read in the boot file
265     */
266
267    fh = open(argv[1],O_RDONLY);
268    if (fh < 0) {
269	perror(argv[1]);
270	}
271
272    bootsize = lseek(fh,0L,SEEK_END);
273    lseek(fh,0L,SEEK_SET);
274
275    bootbufsize = roundup(bootsize,BOOT_BLOCK_BLOCKSIZE);
276
277    bootcode = malloc(bootbufsize);
278    if (bootcode == NULL) {
279	perror("malloc");
280	exit(1);
281	}
282    memset(bootcode,0,bootbufsize);
283    if (read(fh,bootcode,bootsize) != bootsize) {
284	perror("read");
285	exit(1);
286	}
287
288    close(fh);
289
290    /*
291     * Construct the boot block
292     */
293
294
295    /* Checksum the boot code */
296    do_checksum(bootcode,bootbufsize,&datacsum,1);
297    bswap32(&datacsum);
298
299
300    /* fill in the boot block fields, and checksum the boot block */
301    bootblock.bb_magic = BOOT_MAGIC_NUMBER;
302    bootblock.bb_hdrinfo = (((uint64_t) BOOT_HDR_VERSION) << BOOT_HDR_VER_SHIFT);
303    bootblock.bb_secstart = (bootcode_offset * 512);
304    bootblock.bb_secsize = ((uint64_t) bootbufsize) |
305	(((uint64_t) datacsum) << BOOT_DATA_CHECKSUM_SHIFT);
306    bootblock.bb_archinfo = 0;
307
308    do_checksum(&(bootblock.bb_magic),BOOT_BLOCK_SIZE,&hdrcsum,0);
309    bootblock.bb_hdrinfo |= (uint64_t) hdrcsum;
310
311    if (verbose) dumpbootblock(&bootblock);
312
313    bswap_bootblock(&bootblock);
314
315    /*
316     * Now write the output file
317     */
318
319    fh = open(argv[2],O_RDWR|O_CREAT,S_IREAD|S_IWRITE);
320    if  (fh < 0) {
321	perror(argv[2]);
322	exit(1);
323	}
324
325    fprintf(stderr,"Installing boot block\n");
326    if (lseek(fh, bootsect_offset * 512, SEEK_SET) != (bootsect_offset * 512)) {
327        perror(argv[2]);
328	exit(1);
329        }
330    if (write(fh,&bootblock,sizeof(bootblock)) != sizeof(bootblock)) {
331	perror(argv[2]);
332	exit(1);
333	}
334    fprintf(stderr,"Installing bootstrap program\n");
335    if (lseek(fh, bootcode_offset * 512, SEEK_SET) != (bootcode_offset * 512)) {
336        perror(argv[2]);
337	exit(1);
338        }
339    if (write(fh,bootcode,bootbufsize) != bootbufsize) {
340	perror(argv[2]);
341	exit(1);
342	}
343
344    close(fh);
345
346    fprintf(stderr,"Done.  %s installed on %s\n",argv[1],argv[2]);
347
348    exit(0);
349
350
351}
352