mkuboot.c revision 1.7
1/*	$OpenBSD: mkuboot.c,v 1.7 2016/12/20 11:27:11 jsg Exp $	*/
2
3/*
4 * Copyright (c) 2008 Mark Kettenis
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <err.h>
22#include <fcntl.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <time.h>
28#include <unistd.h>
29#include <zlib.h>
30#include <sys/exec_elf.h>
31
32#define IH_OS_OPENBSD		1 /* OpenBSD */
33#define IH_OS_LINUX		5 /* Linux */
34
35#define IH_ARCH_ALPHA           1       /* Alpha        */
36#define IH_ARCH_ARM             2       /* ARM          */
37#define IH_ARCH_I386            3       /* Intel x86    */
38#define IH_ARCH_IA64            4       /* IA64         */
39#define IH_ARCH_MIPS            5       /* MIPS         */
40#define IH_ARCH_MIPS64          6       /* MIPS  64 Bit */
41#define IH_ARCH_PPC             7       /* PowerPC      */
42#define IH_ARCH_SH              9       /* SuperH       */
43#define IH_ARCH_SPARC           10      /* Sparc        */
44#define IH_ARCH_SPARC64         11      /* Sparc 64 Bit */
45#define IH_ARCH_M68K            12      /* M68K         */
46#define IH_ARCH_ARM64           22      /* AARCH64      */
47
48#define IH_TYPE_STANDALONE	1 /* Standalone */
49#define IH_TYPE_KERNEL		2 /* OS Kernel Image */
50#define IH_TYPE_SCRIPT		6 /* Script file */
51
52#define IH_COMP_NONE		0 /* No compression */
53
54#define IH_MAGIC		0x27051956	/* Image Magic Number */
55#define IH_NMLEN		32 		/* Image Name Length */
56
57struct image_header {
58	uint32_t	ih_magic;
59	uint32_t	ih_hcrc;
60	uint32_t	ih_time;
61	uint32_t	ih_size;
62	uint32_t	ih_load;
63	uint32_t	ih_ep;
64	uint32_t	ih_dcrc;
65	uint8_t		ih_os;
66	uint8_t		ih_arch;
67	uint8_t		ih_type;
68	uint8_t		ih_comp;
69	uint8_t		ih_name[IH_NMLEN];
70};
71
72extern char *__progname;
73
74extern u_long	elf32_copy_elf(int, const char *, int, const char *, u_long,
75	    struct image_header *);
76extern u_long	elf64_copy_elf(int, const char *, int, const char *, u_long,
77	    struct image_header *);
78
79u_long	copy_data(int, const char *, int, const char *, u_long,
80	    struct image_header *, Elf_Word);
81u_long	(*copy_elf)(int, const char *, int, const char *, u_long,
82	    struct image_header *);
83
84u_long	copy_mem(void *, int, const char *, u_long, struct image_header *,
85	    Elf_Word);
86u_long	copy_raw(int, const char *, int, const char *, u_long,
87	    struct image_header *);
88u_long	fill_zeroes(int, const char *, u_long, struct image_header *, Elf_Word);
89int	is_elf(int, const char *);
90void	usage(void);
91
92struct arch_map {
93	int id;
94	const char *arch;
95};
96
97static const struct arch_map archmap[] = {
98    { IH_ARCH_ARM64,	"aarch64" },
99    { IH_ARCH_ALPHA,	"alpha" },
100    { IH_ARCH_IA64,	"amd64" },
101    { IH_ARCH_ARM,	"arm" },
102    { IH_ARCH_I386,	"i386" },
103    { IH_ARCH_M68K,	"m68k" },
104    { IH_ARCH_MIPS,	"mips" },
105    { IH_ARCH_MIPS64,	"mips64" },
106    { IH_ARCH_PPC,	"powerpc" },
107    { IH_ARCH_SPARC,	"sparc" },
108    { IH_ARCH_SPARC64,	"sparc64" },
109    { IH_ARCH_SH,	"superh" },
110    { 0, NULL }
111};
112
113struct type_map {
114	int id;
115	const char *type;
116};
117static const struct type_map typemap[] = {
118    { IH_TYPE_STANDALONE,	"standalone" },
119    { IH_TYPE_KERNEL,		"kernel" },
120    { IH_TYPE_SCRIPT,		"script" },
121    { 0, NULL }
122};
123
124struct os_map {
125	int id;
126	const char *arch;
127};
128
129static const struct os_map osmap[] = {
130    { IH_OS_OPENBSD,	"OpenBSD" },
131    { IH_OS_LINUX,	"Linux" },
132    { 0, NULL }
133};
134
135
136int
137main(int argc, char *argv[])
138{
139	struct image_header ih;
140	struct stat sb;
141	const struct arch_map *mapptr;
142	const struct os_map *osmapptr;
143	const struct type_map *typemapptr;
144	const char *iname, *oname;
145	const char *arch = MACHINE_ARCH;
146	const char *os = "OpenBSD";
147	const char *type = "kernel";
148	const char *imgname = "boot";
149	int ifd, ofd;
150	uint32_t fsize;
151	u_long crc;
152	int c, ep, load;
153
154	ep = load = 0;
155	while ((c = getopt(argc, argv, "a:e:l:n:o:t:")) != -1) {
156		switch (c) {
157		case 'a':
158			arch = optarg;
159			break;
160		case 'e':
161			sscanf(optarg, "0x%x", &ep);
162			break;
163		case 'l':
164			sscanf(optarg, "0x%x", &load);
165			break;
166		case 'n':
167			imgname = optarg;
168			break;
169		case 'o':
170			os = optarg;
171			break;
172		case 't':
173			type = optarg;
174			break;
175		default:
176			usage();
177		}
178	}
179
180	for (mapptr = archmap; mapptr->arch; mapptr++)
181		if (strcasecmp(arch, mapptr->arch) == 0)
182			break;
183
184	if (mapptr->arch == NULL) {
185		printf("unknown arch '%s'\n", arch);
186		usage();
187	}
188
189	for (osmapptr = osmap; osmapptr->arch; osmapptr++)
190		if (strcasecmp(os, osmapptr->arch) == 0)
191			break;
192
193	if (osmapptr->arch == NULL) {
194		printf("unknown OS '%s'\n", os);
195		usage();
196	}
197
198	for (typemapptr = typemap; typemapptr->type; typemapptr++)
199		if (strcasecmp(type, typemapptr->type) == 0)
200			break;
201
202	if (typemapptr->type == NULL) {
203		printf("unknown type '%s'\n", os);
204		usage();
205	}
206
207	if (argc - optind != 2)
208		usage();
209
210	iname = argv[optind++];
211	oname = argv[optind++];
212
213	/* Initialize U-Boot header. */
214	bzero(&ih, sizeof ih);
215	ih.ih_magic = htobe32(IH_MAGIC);
216	ih.ih_time = htobe32(time(NULL));
217	ih.ih_load = htobe32(load);
218	ih.ih_ep = htobe32(ep);
219	ih.ih_os = osmapptr->id;
220	ih.ih_arch = mapptr->id;
221	ih.ih_type = typemapptr->id;
222	ih.ih_comp = IH_COMP_NONE;
223	strlcpy((char *)ih.ih_name, imgname, sizeof ih.ih_name);
224
225	ifd = open(iname, O_RDONLY);
226	if (ifd < 0)
227		err(1, "%s", iname);
228	if (fstat(ifd, &sb) == -1)
229		err(1, "%s", iname);
230
231	ofd = open(oname, O_RDWR | O_TRUNC | O_CREAT, 0644);
232	if (ofd < 0)
233		err(1, "%s", oname);
234
235	if (pledge("stdio", NULL) == -1)
236		err(1, "pledge");
237
238	/* Write initial header. */
239	if (write(ofd, &ih, sizeof ih) != sizeof ih)
240		err(1, "%s", oname);
241
242	/* Write data, calculating the data CRC as we go. */
243	crc = crc32(0L, Z_NULL, 0);
244
245	if (ih.ih_type == IH_TYPE_SCRIPT) {
246		/* scripts have two extra words of size/pad */
247		fsize = htobe32(sb.st_size);
248		crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
249		if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
250			err(1, "%s", oname);
251		fsize = 0;
252		crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
253		if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
254			err(1, "%s", oname);
255	}
256
257	if (is_elf(ifd, iname))
258		crc = copy_elf(ifd, iname, ofd, oname, crc, &ih);
259	else
260		crc = copy_raw(ifd, iname, ofd, oname, crc, &ih);
261	ih.ih_dcrc = htobe32(crc);
262
263	if (ih.ih_type == IH_TYPE_SCRIPT) {
264		ih.ih_size += 8; /* two extra pad words */
265	}
266
267	ih.ih_size = htobe32(ih.ih_size);
268
269	/* Calculate header CRC. */
270	crc = crc32(0, (Bytef *)&ih, sizeof ih);
271	ih.ih_hcrc = htobe32(crc);
272
273	/* Write finalized header. */
274	if (lseek(ofd, 0, SEEK_SET) != 0)
275		err(1, "%s", oname);
276	if (write(ofd, &ih, sizeof ih) != sizeof ih)
277		err(1, "%s", oname);
278
279	return(0);
280}
281
282int
283is_elf(int ifd, const char *iname)
284{
285	ssize_t nbytes;
286	Elf_Ehdr ehdr;
287
288	nbytes = read(ifd, &ehdr, sizeof ehdr);
289	if (nbytes == -1)
290		err(1, "%s", iname);
291	if (lseek(ifd, 0, SEEK_SET) != 0)
292		err(1, "%s", iname);
293
294	if (nbytes != sizeof ehdr || !IS_ELF(ehdr))
295		return 0;
296
297	if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
298		copy_elf = elf32_copy_elf;
299	else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
300		copy_elf = elf64_copy_elf;
301	else
302		err(1, "%s: invalid elf, not 32 or 64 bit", iname);
303	return 1;
304}
305
306u_long
307copy_data(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
308    struct image_header *ih, Elf_Word size)
309{
310	ssize_t nbytes, chunk;
311	char buf[BUFSIZ];
312
313	while (size != 0) {
314		chunk = size > BUFSIZ ? BUFSIZ : size;
315		nbytes = read(ifd, buf, chunk);
316		if (nbytes != chunk)
317			err(1, "%s", iname);
318		if (write(ofd, buf, nbytes) != nbytes)
319			err(1, "%s", oname);
320		crc = crc32(crc, (Bytef *)buf, nbytes);
321		ih->ih_size += nbytes;
322		size -= nbytes;
323	}
324
325	return crc;
326}
327
328u_long
329copy_mem(void *mem, int ofd, const char *oname, u_long crc,
330    struct image_header *ih, Elf_Word size)
331{
332	ssize_t nbytes;
333	char *memp = (char *)mem;
334
335	while (size != 0) {
336		nbytes = size > BUFSIZ ? BUFSIZ : size;
337		if (write(ofd, memp, nbytes) != nbytes)
338			err(1, "%s", oname);
339		crc = crc32(crc, (Bytef *)memp, nbytes);
340		memp += nbytes;
341		ih->ih_size += nbytes;
342		size -= nbytes;
343	}
344
345	return crc;
346}
347
348u_long
349fill_zeroes(int ofd, const char *oname, u_long crc, struct image_header *ih,
350    Elf_Word size)
351{
352	ssize_t nbytes, chunk;
353	char buf[BUFSIZ];
354
355	memset(buf, 0, BUFSIZ);
356	while (size != 0) {
357		chunk = size > BUFSIZ ? BUFSIZ : size;
358		nbytes = write(ofd, buf, chunk);
359		if (nbytes != chunk)
360			err(1, "%s", oname);
361		crc = crc32(crc, (Bytef *)buf, nbytes);
362		ih->ih_size += nbytes;
363		size -= nbytes;
364	}
365
366	return crc;
367}
368
369u_long
370copy_raw(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
371    struct image_header *ih)
372{
373	ssize_t nbytes;
374	char buf[BUFSIZ];
375
376	while ((nbytes = read(ifd, buf, sizeof buf)) != 0) {
377		if (nbytes == -1)
378			err(1, "%s", iname);
379		if (write(ofd, buf, nbytes) != nbytes)
380			err(1, "%s", oname);
381		crc = crc32(crc, (Bytef *)buf, nbytes);
382		ih->ih_size += nbytes;
383	}
384
385	return crc;
386}
387
388void
389usage(void)
390{
391	const struct arch_map *mapptr;
392	const struct os_map *osmapptr;
393
394	(void)fprintf(stderr,
395	    "usage: %s [-a arch] [-e entry] [-l loadaddr] [-n name] [-o os] "
396	    "[-t type] infile outfile\n", __progname);
397	(void)fprintf(stderr,
398	    "arch is one of:");
399	for (mapptr = archmap; mapptr->arch; mapptr++)
400		(void)fprintf(stderr, " %s", mapptr->arch);
401	(void)fprintf(stderr, "\n");
402	(void)fprintf(stderr,
403	    "os is one of:");
404	for (osmapptr = osmap; osmapptr->arch; osmapptr++)
405		(void)fprintf(stderr, " %s", osmapptr->arch);
406	(void)fprintf(stderr, "\n");
407
408	exit(1);
409}
410