1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Boot block generator			File: mkbootimage.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 sector_offset = 0;
72
73static void usage(void)
74{
75    fprintf(stderr,"usage: mkbootimage [-S <sector offset>] [-v] [-EB] [-EL] inputfile outputfile\n");
76    exit(1);
77}
78
79static void bswap32(uint32_t *ptr)
80{
81    unsigned char b;
82    unsigned char *bptr;
83
84    if (swapflg) {
85	bptr = (unsigned char *) ptr;
86	b = bptr[0]; bptr[0] = bptr[3]; bptr[3] = b;
87	b = bptr[1]; bptr[1] = bptr[2]; bptr[2] = b;
88	}
89}
90
91static void bswap64(uint64_t *ptr)
92{
93    unsigned char b;
94    unsigned char *bptr;
95
96    bptr = (unsigned char *) ptr;
97
98    if (swapflg) {
99	b = bptr[0]; bptr[0] = bptr[7]; bptr[7] = b;
100	b = bptr[1]; bptr[1] = bptr[6]; bptr[6] = b;
101	b = bptr[2]; bptr[2] = bptr[5]; bptr[5] = b;
102	b = bptr[3]; bptr[3] = bptr[4]; bptr[4] = b;
103	}
104}
105
106
107static void bswap_bootblock(struct boot_block *bb)
108{
109    int idx;
110
111    for (idx = 59; idx <= 63; idx++) {
112	bswap64(&(bb->bb_data[idx]));
113	}
114}
115
116static void do_checksum(void *ptr,int length,uint32_t *csptr,int swap)
117{
118    uint32_t *p;
119    uint32_t chksum = 0;
120    uint32_t d;
121
122    p = (uint32_t *) ptr;
123
124    length /= sizeof(uint32_t);
125
126    while (length) {
127	d = *p;
128	if (swap) bswap32(&d);
129	chksum += d;
130	p++;
131	length--;
132	}
133
134    if (swap) bswap32(&chksum);
135
136    *csptr = chksum;
137}
138
139
140static void dumpbootblock(struct boot_block *bb)
141{
142    int idx;
143
144    fprintf(stderr,"Magic Number:       %016llX\n",
145	    bb->bb_magic);
146    fprintf(stderr,"Boot code offset:   %llu\n",
147	    (unsigned long long)bb->bb_secstart);
148    fprintf(stderr,"Boot code size:     %lu\n",
149	    (unsigned long) (uint32_t) (bb->bb_secsize & BOOT_SECSIZE_MASK));
150    fprintf(stderr,"Header checksum:    %08lX\n",
151	    (unsigned long) (uint32_t) (bb->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK));
152    fprintf(stderr,"Header version:     %ld\n",
153	    (unsigned long) (uint32_t) ((bb->bb_hdrinfo  & BOOT_HDR_VER_MASK) >> BOOT_HDR_VER_SHIFT));
154    fprintf(stderr,"Data checksum:      %08lX\n",
155	    (unsigned long) (uint32_t) ((bb->bb_secsize & BOOT_DATA_CHECKSUM_MASK) >> BOOT_DATA_CHECKSUM_SHIFT));
156    fprintf(stderr,"Architecture info:  %08lX\n",
157	    (unsigned long) (uint32_t) (bb->bb_archinfo & BOOT_ARCHINFO_MASK));
158    fprintf(stderr,"\n");
159
160    for (idx = 59; idx <= 63; idx++) {
161	fprintf(stderr,"Word %d = %016llX\n",idx,bb->bb_data[idx]);
162	}
163}
164
165static int host_is_little(void)
166{
167    unsigned long var = 1;
168    unsigned char *pvar = (unsigned char *) &var;
169
170    return (*pvar == 1);
171}
172
173int main(int argc, char *argv[])
174{
175    int fh;
176    long bootsize;
177    long bootbufsize;
178    unsigned char *bootcode;
179    struct boot_block bootblock;
180    uint32_t datacsum,hdrcsum;
181    int host_le;
182
183    while ((argc > 1) && (argv[1][0] == '-')) {
184	if (strcmp(argv[1],"-v") == 0) {
185	    verbose = 1;
186	    }
187	else if (strcmp(argv[1],"-EB") == 0) {
188	    big_endian = 1;
189	    }
190	else if (strcmp(argv[1],"-EL") == 0) {
191	    big_endian = 0;
192	    }
193        else if (strcmp(argv[1],"-S") == 0) {
194	    char *tmp_ptr;
195	    argv++;
196	    argc--;
197	    if (argc == 1) {
198	    	fprintf(stderr,"-S requires an argument\n");
199	    	exit(1);
200	        }
201	    sector_offset = strtoul(argv[1], &tmp_ptr, 0);
202	    if (*tmp_ptr) {
203	    	fprintf(stderr,"Unable to parse %s as a sector offset\n", argv[1]);
204	    	exit(1);
205		}
206	    }
207	else {
208	    fprintf(stderr,"Invalid switch: %s\n",argv[1]);
209	    exit(1);
210	    }
211	argv++;
212	argc--;
213	}
214
215    /*
216     * We need to swap things around if the host and
217     * target are different endianness
218     */
219
220    swapflg = 0;
221    host_le = host_is_little();
222
223    if (big_endian && host_is_little()) swapflg = 1;
224    if ((big_endian == 0) && !(host_is_little())) swapflg = 1;
225
226    fprintf(stderr,"Host is %s-endian.\n",host_le ? "little" : "big");
227    fprintf(stderr,"Target is %s-endian.\n",big_endian ? "big" : "little");
228
229    if (argc != 3) {
230	usage();
231	}
232
233    /*
234     * Read in the boot file
235     */
236
237    fh = open(argv[1],O_RDONLY);
238    if (fh < 0) {
239	perror(argv[1]);
240	}
241
242    bootsize = lseek(fh,0L,SEEK_END);
243    lseek(fh,0L,SEEK_SET);
244
245    bootbufsize = roundup(bootsize,BOOT_BLOCK_BLOCKSIZE);
246
247    bootcode = malloc(bootbufsize);
248    if (bootcode == NULL) {
249	perror("malloc");
250	exit(1);
251	}
252    memset(bootcode,0,bootbufsize);
253    if (read(fh,bootcode,bootsize) != bootsize) {
254	perror("read");
255	exit(1);
256	}
257
258    close(fh);
259
260    /*
261     * Construct the boot block
262     */
263
264
265    /* Checksum the boot code */
266    do_checksum(bootcode,bootbufsize,&datacsum,1);
267    bswap32(&datacsum);
268
269
270    /* fill in the boot block fields, and checksum the boot block */
271    bootblock.bb_magic = BOOT_MAGIC_NUMBER;
272    bootblock.bb_hdrinfo = (((uint64_t) BOOT_HDR_VERSION) << BOOT_HDR_VER_SHIFT);
273    bootblock.bb_secstart = BOOT_BLOCK_BLOCKSIZE + (sector_offset * 512);
274    bootblock.bb_secsize = ((uint64_t) bootbufsize) |
275	(((uint64_t) datacsum) << BOOT_DATA_CHECKSUM_SHIFT);
276    bootblock.bb_archinfo = 0;		/* XXX */
277
278    do_checksum(&(bootblock.bb_magic),BOOT_BLOCK_SIZE,&hdrcsum,0);
279    bootblock.bb_hdrinfo |= (uint64_t) hdrcsum;
280
281    if (verbose) dumpbootblock(&bootblock);
282
283    bswap_bootblock(&bootblock);
284
285    /*
286     * Now write the output file
287     */
288
289    fh = open(argv[2],O_RDWR|O_CREAT,S_IREAD|S_IWRITE);
290    if  (fh < 0) {
291	perror(argv[2]);
292	exit(1);
293	}
294    if (lseek(fh, sector_offset * 512, SEEK_SET) != (sector_offset * 512)) {
295        perror(argv[2]);
296	exit(1);
297        }
298    if (write(fh,&bootblock,sizeof(bootblock)) != sizeof(bootblock)) {
299	perror(argv[2]);
300	exit(1);
301	}
302    if (write(fh,bootcode,bootbufsize) != bootbufsize) {
303	perror(argv[2]);
304	exit(1);
305	}
306
307    close(fh);
308
309    fprintf(stderr,"%s -> %s : OK\n",argv[1],argv[2]);
310
311    exit(0);
312
313
314}
315
316