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