1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Boot program installer			File: installboot.c
5    *
6    *  Author:  Mitch Lichtenberg
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#include <unistd.h>
64
65#define roundup(x,align) (((x)+(align)-1)&~((align)-1))
66#define howmany(x,align) (((x)+(align)-1)/(align))
67
68static int verbose = 0;
69static int big_endian = 1;
70static int swapflg = 1;
71static unsigned long bootcode_offset = 2;
72static unsigned long bootsect_offset = 1;
73
74static void usage(void)
75{
76    fprintf(stderr,"usage: installboot [-bootsect <sector offset>] [-bootcode <sector offset>]\n"
77	           "                   [-v] [-EB] [-EL] bootloaderfile.bin devicefile\n\n");
78    fprintf(stderr,"This program installs a boot block onto a disk.  Typically, installboot\n"
79	           "is used to install sibyl or other OS bootloaders.  The binary you install\n"
80	           "should be a raw program (not ELF) located to run in CFE's boot area\n"
81	           "at address 0x2000_0000.  The devicefile should be the name of the raw device\n"
82	           "such as /dev/hda on Linux.\n\n"
83	           "Care must be taken when choosing the values for -bootsect and -bootcode\n"
84	           "not to interfere with other partitions on your disk.   When partitioning,\n"
85	           "it's a good idea to reserve 3 cylinders at the beginning of the disk for\n"
86	           "the boot loader.\n\n"
87	           "-bootsect nn    specifies that the boot sector will be placed on sector 'nn'\n"
88	           "-bootcode nn    specifies that the boot program itself will be placed\n"
89	           "                on sectors starting with 'nn'.  The boot sector will point\n"
90	           "                to this sector.\n");
91
92    exit(1);
93}
94
95static void bswap32(uint32_t *ptr)
96{
97    unsigned char b;
98    unsigned char *bptr;
99
100    if (swapflg) {
101	bptr = (unsigned char *) ptr;
102	b = bptr[0]; bptr[0] = bptr[3]; bptr[3] = b;
103	b = bptr[1]; bptr[1] = bptr[2]; bptr[2] = b;
104	}
105}
106
107static void bswap64(uint64_t *ptr)
108{
109    unsigned char b;
110    unsigned char *bptr;
111
112    bptr = (unsigned char *) ptr;
113
114    if (swapflg) {
115	b = bptr[0]; bptr[0] = bptr[7]; bptr[7] = b;
116	b = bptr[1]; bptr[1] = bptr[6]; bptr[6] = b;
117	b = bptr[2]; bptr[2] = bptr[5]; bptr[5] = b;
118	b = bptr[3]; bptr[3] = bptr[4]; bptr[4] = b;
119	}
120}
121
122
123static void bswap_bootblock(struct boot_block *bb)
124{
125    int idx;
126
127    for (idx = 59; idx <= 63; idx++) {
128	bswap64(&(bb->bb_data[idx]));
129	}
130}
131
132static void do_checksum(void *ptr,int length,uint32_t *csptr,int swap)
133{
134    uint32_t *p;
135    uint32_t chksum = 0;
136    uint32_t d;
137
138    p = (uint32_t *) ptr;
139
140    length /= sizeof(uint32_t);
141
142    while (length) {
143	d = *p;
144	if (swap) bswap32(&d);
145	chksum += d;
146	p++;
147	length--;
148	}
149
150    if (swap) bswap32(&chksum);
151
152    *csptr = chksum;
153}
154
155
156static void dumpbootblock(struct boot_block *bb)
157{
158    int idx;
159
160    fprintf(stderr,"Magic Number:       %016llX\n",
161	    bb->bb_magic);
162    fprintf(stderr,"Boot code offset:   %llu\n",
163	    (unsigned long long)bb->bb_secstart);
164    fprintf(stderr,"Boot code size:     %lu\n",
165	    (unsigned long) (uint32_t) (bb->bb_secsize & BOOT_SECSIZE_MASK));
166    fprintf(stderr,"Header checksum:    %08lX\n",
167	    (unsigned long) (uint32_t) (bb->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK));
168    fprintf(stderr,"Header version:     %ld\n",
169	    (unsigned long) (uint32_t) ((bb->bb_hdrinfo  & BOOT_HDR_VER_MASK) >> BOOT_HDR_VER_SHIFT));
170    fprintf(stderr,"Data checksum:      %08lX\n",
171	    (unsigned long) (uint32_t) ((bb->bb_secsize & BOOT_DATA_CHECKSUM_MASK) >> BOOT_DATA_CHECKSUM_SHIFT));
172    fprintf(stderr,"Architecture info:  %08lX\n",
173	    (unsigned long) (uint32_t) (bb->bb_archinfo & BOOT_ARCHINFO_MASK));
174    fprintf(stderr,"\n");
175
176    for (idx = 59; idx <= 63; idx++) {
177	fprintf(stderr,"Word %d = %016llX\n",idx,bb->bb_data[idx]);
178	}
179}
180
181static int host_is_little(void)
182{
183    unsigned long var = 1;
184    unsigned char *pvar = (unsigned char *) &var;
185
186    return (*pvar == 1);
187}
188
189int main(int argc, char *argv[])
190{
191    int fh;
192    long bootsize;
193    long bootbufsize;
194    unsigned char *bootcode;
195    struct boot_block bootblock;
196    uint32_t datacsum,hdrcsum;
197    int host_le;
198
199    while ((argc > 1) && (argv[1][0] == '-')) {
200	if (strcmp(argv[1],"-v") == 0) {
201	    verbose = 1;
202	    }
203	else if (strcmp(argv[1],"-EB") == 0) {
204	    big_endian = 1;
205	    }
206	else if (strcmp(argv[1],"-EL") == 0) {
207	    big_endian = 0;
208	    }
209        else if (strcmp(argv[1],"-bootsect") == 0) {
210	    char *tmp_ptr;
211	    argv++;
212	    argc--;
213	    if (argc == 1) {
214	    	fprintf(stderr,"-bootsect requires an argument\n");
215	    	exit(1);
216	        }
217	    bootsect_offset = strtoul(argv[1], &tmp_ptr, 0);
218	    bootcode_offset = bootsect_offset + 1;	/* default if -bootcode not specified */
219	    if (*tmp_ptr) {
220	    	fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]);
221	    	exit(1);
222		}
223	    }
224        else if (strcmp(argv[1],"-bootcode") == 0) {
225	    char *tmp_ptr;
226	    argv++;
227	    argc--;
228	    if (argc == 1) {
229	    	fprintf(stderr,"-bootcode requires an argument\n");
230	    	exit(1);
231	        }
232	    bootcode_offset = strtoul(argv[1], &tmp_ptr, 0);
233	    if (*tmp_ptr) {
234	    	fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]);
235	    	exit(1);
236		}
237	    }
238	else {
239	    fprintf(stderr,"Invalid switch: %s\n",argv[1]);
240	    exit(1);
241	    }
242	argv++;
243	argc--;
244	}
245
246    /*
247     * We need to swap things around if the host and
248     * target are different endianness
249     */
250
251    swapflg = 0;
252    host_le = host_is_little();
253
254    if (big_endian && host_is_little()) swapflg = 1;
255    if ((big_endian == 0) && !(host_is_little())) swapflg = 1;
256
257    fprintf(stderr,"Host is %s-endian.\n",host_le ? "little" : "big");
258    fprintf(stderr,"Target is %s-endian.\n",big_endian ? "big" : "little");
259
260    if (argc != 3) {
261	usage();
262	}
263
264    /*
265     * Read in the boot file
266     */
267
268    fh = open(argv[1],O_RDONLY);
269    if (fh < 0) {
270	perror(argv[1]);
271	}
272
273    bootsize = lseek(fh,0L,SEEK_END);
274    lseek(fh,0L,SEEK_SET);
275
276    bootbufsize = roundup(bootsize,BOOT_BLOCK_BLOCKSIZE);
277
278    bootcode = malloc(bootbufsize);
279    if (bootcode == NULL) {
280	perror("malloc");
281	exit(1);
282	}
283    memset(bootcode,0,bootbufsize);
284    if (read(fh,bootcode,bootsize) != bootsize) {
285	perror("read");
286	exit(1);
287	}
288
289    close(fh);
290
291    /*
292     * Construct the boot block
293     */
294
295
296    /* Checksum the boot code */
297    do_checksum(bootcode,bootbufsize,&datacsum,1);
298    bswap32(&datacsum);
299
300
301    /* fill in the boot block fields, and checksum the boot block */
302    bootblock.bb_magic = BOOT_MAGIC_NUMBER;
303    bootblock.bb_hdrinfo = (((uint64_t) BOOT_HDR_VERSION) << BOOT_HDR_VER_SHIFT);
304    bootblock.bb_secstart = (bootcode_offset * 512);
305    bootblock.bb_secsize = ((uint64_t) bootbufsize) |
306	(((uint64_t) datacsum) << BOOT_DATA_CHECKSUM_SHIFT);
307    bootblock.bb_archinfo = 0;		/* XXX */
308
309    do_checksum(&(bootblock.bb_magic),BOOT_BLOCK_SIZE,&hdrcsum,0);
310    bootblock.bb_hdrinfo |= (uint64_t) hdrcsum;
311
312    if (verbose) dumpbootblock(&bootblock);
313
314    bswap_bootblock(&bootblock);
315
316    /*
317     * Now write the output file
318     */
319
320    fh = open(argv[2],O_RDWR|O_CREAT,S_IREAD|S_IWRITE);
321    if  (fh < 0) {
322	perror(argv[2]);
323	exit(1);
324	}
325
326    fprintf(stderr,"Installing boot block\n");
327    if (lseek(fh, bootsect_offset * 512, SEEK_SET) != (bootsect_offset * 512)) {
328        perror(argv[2]);
329	exit(1);
330        }
331    if (write(fh,&bootblock,sizeof(bootblock)) != sizeof(bootblock)) {
332	perror(argv[2]);
333	exit(1);
334	}
335    fprintf(stderr,"Installing bootstrap program\n");
336    if (lseek(fh, bootcode_offset * 512, SEEK_SET) != (bootcode_offset * 512)) {
337        perror(argv[2]);
338	exit(1);
339        }
340    if (write(fh,bootcode,bootbufsize) != bootbufsize) {
341	perror(argv[2]);
342	exit(1);
343	}
344
345    close(fh);
346
347    fprintf(stderr,"Done.  %s installed on %s\n",argv[1],argv[2]);
348
349    exit(0);
350
351
352}
353
354