xref: /openbsd-src/usr.sbin/mkuboot/mkuboot.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: mkuboot.c,v 1.6 2015/10/12 06:24:28 deraadt 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 
47 #define IH_TYPE_STANDALONE	1 /* Standalone */
48 #define IH_TYPE_KERNEL		2 /* OS Kernel Image */
49 #define IH_TYPE_SCRIPT		6 /* Script file */
50 
51 #define IH_COMP_NONE		0 /* No compression */
52 
53 #define IH_MAGIC		0x27051956	/* Image Magic Number */
54 #define IH_NMLEN		32 		/* Image Name Length */
55 
56 struct image_header {
57 	uint32_t	ih_magic;
58 	uint32_t	ih_hcrc;
59 	uint32_t	ih_time;
60 	uint32_t	ih_size;
61 	uint32_t	ih_load;
62 	uint32_t	ih_ep;
63 	uint32_t	ih_dcrc;
64 	uint8_t		ih_os;
65 	uint8_t		ih_arch;
66 	uint8_t		ih_type;
67 	uint8_t		ih_comp;
68 	uint8_t		ih_name[IH_NMLEN];
69 };
70 
71 extern char *__progname;
72 
73 extern u_long	elf32_copy_elf(int, const char *, int, const char *, u_long,
74 	    struct image_header *);
75 extern u_long	elf64_copy_elf(int, const char *, int, const char *, u_long,
76 	    struct image_header *);
77 
78 u_long	copy_data(int, const char *, int, const char *, u_long,
79 	    struct image_header *, Elf_Word);
80 u_long	(*copy_elf)(int, const char *, int, const char *, u_long,
81 	    struct image_header *);
82 
83 u_long	copy_mem(void *, int, const char *, u_long, struct image_header *,
84 	    Elf_Word);
85 u_long	copy_raw(int, const char *, int, const char *, u_long,
86 	    struct image_header *);
87 u_long	fill_zeroes(int, const char *, u_long, struct image_header *, Elf_Word);
88 int	is_elf(int, const char *);
89 void	usage(void);
90 
91 struct arch_map {
92 	int id;
93 	const char *arch;
94 };
95 
96 static const struct arch_map archmap[] = {
97     { IH_ARCH_ALPHA,	"alpha" },
98     { IH_ARCH_IA64,	"amd64" },
99     { IH_ARCH_ARM,	"arm" },
100     { IH_ARCH_I386,	"i386" },
101     { IH_ARCH_M68K,	"m68k" },
102     { IH_ARCH_MIPS,	"mips" },
103     { IH_ARCH_MIPS64,	"mips64" },
104     { IH_ARCH_PPC,	"powerpc" },
105     { IH_ARCH_SPARC,	"sparc" },
106     { IH_ARCH_SPARC64,	"sparc64" },
107     { IH_ARCH_SH,	"superh" },
108     { 0, NULL }
109 };
110 
111 struct type_map {
112 	int id;
113 	const char *type;
114 };
115 static const struct type_map typemap[] = {
116     { IH_TYPE_STANDALONE,	"standalone" },
117     { IH_TYPE_KERNEL,		"kernel" },
118     { IH_TYPE_SCRIPT,		"script" },
119     { 0, NULL }
120 };
121 
122 struct os_map {
123 	int id;
124 	const char *arch;
125 };
126 
127 static const struct os_map osmap[] = {
128     { IH_OS_OPENBSD,	"OpenBSD" },
129     { IH_OS_LINUX,	"Linux" },
130     { 0, NULL }
131 };
132 
133 
134 int
135 main(int argc, char *argv[])
136 {
137 	struct image_header ih;
138 	struct stat sb;
139 	const struct arch_map *mapptr;
140 	const struct os_map *osmapptr;
141 	const struct type_map *typemapptr;
142 	const char *iname, *oname;
143 	const char *arch = MACHINE_ARCH;
144 	const char *os = "OpenBSD";
145 	const char *type = "kernel";
146 	const char *imgname = "boot";
147 	int ifd, ofd;
148 	uint32_t fsize;
149 	u_long crc;
150 	int c, ep, load;
151 
152 	ep = load = 0;
153 	while ((c = getopt(argc, argv, "a:e:l:n:o:t:")) != -1) {
154 		switch (c) {
155 		case 'a':
156 			arch = optarg;
157 			break;
158 		case 'e':
159 			sscanf(optarg, "0x%x", &ep);
160 			break;
161 		case 'l':
162 			sscanf(optarg, "0x%x", &load);
163 			break;
164 		case 'n':
165 			imgname = optarg;
166 			break;
167 		case 'o':
168 			os = optarg;
169 			break;
170 		case 't':
171 			type = optarg;
172 			break;
173 		default:
174 			usage();
175 		}
176 	}
177 
178 	for (mapptr = archmap; mapptr->arch; mapptr++)
179 		if (strcasecmp(arch, mapptr->arch) == 0)
180 			break;
181 
182 	if (mapptr->arch == NULL) {
183 		printf("unknown arch '%s'\n", arch);
184 		usage();
185 	}
186 
187 	for (osmapptr = osmap; osmapptr->arch; osmapptr++)
188 		if (strcasecmp(os, osmapptr->arch) == 0)
189 			break;
190 
191 	if (osmapptr->arch == NULL) {
192 		printf("unknown OS '%s'\n", os);
193 		usage();
194 	}
195 
196 	for (typemapptr = typemap; typemapptr->type; typemapptr++)
197 		if (strcasecmp(type, typemapptr->type) == 0)
198 			break;
199 
200 	if (typemapptr->type == NULL) {
201 		printf("unknown type '%s'\n", os);
202 		usage();
203 	}
204 
205 	if (argc - optind != 2)
206 		usage();
207 
208 	iname = argv[optind++];
209 	oname = argv[optind++];
210 
211 	/* Initialize U-Boot header. */
212 	bzero(&ih, sizeof ih);
213 	ih.ih_magic = htobe32(IH_MAGIC);
214 	ih.ih_time = htobe32(time(NULL));
215 	ih.ih_load = htobe32(load);
216 	ih.ih_ep = htobe32(ep);
217 	ih.ih_os = osmapptr->id;
218 	ih.ih_arch = mapptr->id;
219 	ih.ih_type = typemapptr->id;
220 	ih.ih_comp = IH_COMP_NONE;
221 	strlcpy((char *)ih.ih_name, imgname, sizeof ih.ih_name);
222 
223 	ifd = open(iname, O_RDONLY);
224 	if (ifd < 0)
225 		err(1, "%s", iname);
226 	if (fstat(ifd, &sb) == -1)
227 		err(1, "%s", iname);
228 
229 	ofd = open(oname, O_RDWR | O_TRUNC | O_CREAT, 0644);
230 	if (ofd < 0)
231 		err(1, "%s", oname);
232 
233 	if (pledge("stdio", NULL) == -1)
234 		err(1, "pledge");
235 
236 	/* Write initial header. */
237 	if (write(ofd, &ih, sizeof ih) != sizeof ih)
238 		err(1, "%s", oname);
239 
240 	/* Write data, calculating the data CRC as we go. */
241 	crc = crc32(0L, Z_NULL, 0);
242 
243 	if (ih.ih_type == IH_TYPE_SCRIPT) {
244 		/* scripts have two extra words of size/pad */
245 		fsize = htobe32(sb.st_size);
246 		crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
247 		if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
248 			err(1, "%s", oname);
249 		fsize = 0;
250 		crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
251 		if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
252 			err(1, "%s", oname);
253 	}
254 
255 	if (is_elf(ifd, iname))
256 		crc = copy_elf(ifd, iname, ofd, oname, crc, &ih);
257 	else
258 		crc = copy_raw(ifd, iname, ofd, oname, crc, &ih);
259 	ih.ih_dcrc = htobe32(crc);
260 
261 	if (ih.ih_type == IH_TYPE_SCRIPT) {
262 		ih.ih_size += 8; /* two extra pad words */
263 	}
264 
265 	ih.ih_size = htobe32(ih.ih_size);
266 
267 	/* Calculate header CRC. */
268 	crc = crc32(0, (Bytef *)&ih, sizeof ih);
269 	ih.ih_hcrc = htobe32(crc);
270 
271 	/* Write finalized header. */
272 	if (lseek(ofd, 0, SEEK_SET) != 0)
273 		err(1, "%s", oname);
274 	if (write(ofd, &ih, sizeof ih) != sizeof ih)
275 		err(1, "%s", oname);
276 
277 	return(0);
278 }
279 
280 int
281 is_elf(int ifd, const char *iname)
282 {
283 	ssize_t nbytes;
284 	Elf_Ehdr ehdr;
285 
286 	nbytes = read(ifd, &ehdr, sizeof ehdr);
287 	if (nbytes == -1)
288 		err(1, "%s", iname);
289 	if (lseek(ifd, 0, SEEK_SET) != 0)
290 		err(1, "%s", iname);
291 
292 	if (nbytes != sizeof ehdr || !IS_ELF(ehdr))
293 		return 0;
294 
295 	if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
296 		copy_elf = elf32_copy_elf;
297 	else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
298 		copy_elf = elf64_copy_elf;
299 	else
300 		err(1, "%s: invalid elf, not 32 or 64 bit", iname);
301 	return 1;
302 }
303 
304 u_long
305 copy_data(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
306     struct image_header *ih, Elf_Word size)
307 {
308 	ssize_t nbytes, chunk;
309 	char buf[BUFSIZ];
310 
311 	while (size != 0) {
312 		chunk = size > BUFSIZ ? BUFSIZ : size;
313 		nbytes = read(ifd, buf, chunk);
314 		if (nbytes != chunk)
315 			err(1, "%s", iname);
316 		if (write(ofd, buf, nbytes) != nbytes)
317 			err(1, "%s", oname);
318 		crc = crc32(crc, (Bytef *)buf, nbytes);
319 		ih->ih_size += nbytes;
320 		size -= nbytes;
321 	}
322 
323 	return crc;
324 }
325 
326 u_long
327 copy_mem(void *mem, int ofd, const char *oname, u_long crc,
328     struct image_header *ih, Elf_Word size)
329 {
330 	ssize_t nbytes;
331 	char *memp = (char *)mem;
332 
333 	while (size != 0) {
334 		nbytes = size > BUFSIZ ? BUFSIZ : size;
335 		if (write(ofd, memp, nbytes) != nbytes)
336 			err(1, "%s", oname);
337 		crc = crc32(crc, (Bytef *)memp, nbytes);
338 		memp += nbytes;
339 		ih->ih_size += nbytes;
340 		size -= nbytes;
341 	}
342 
343 	return crc;
344 }
345 
346 u_long
347 fill_zeroes(int ofd, const char *oname, u_long crc, struct image_header *ih,
348     Elf_Word size)
349 {
350 	ssize_t nbytes, chunk;
351 	char buf[BUFSIZ];
352 
353 	memset(buf, 0, BUFSIZ);
354 	while (size != 0) {
355 		chunk = size > BUFSIZ ? BUFSIZ : size;
356 		nbytes = write(ofd, buf, chunk);
357 		if (nbytes != chunk)
358 			err(1, "%s", oname);
359 		crc = crc32(crc, (Bytef *)buf, nbytes);
360 		ih->ih_size += nbytes;
361 		size -= nbytes;
362 	}
363 
364 	return crc;
365 }
366 
367 u_long
368 copy_raw(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
369     struct image_header *ih)
370 {
371 	ssize_t nbytes;
372 	char buf[BUFSIZ];
373 
374 	while ((nbytes = read(ifd, buf, sizeof buf)) != 0) {
375 		if (nbytes == -1)
376 			err(1, "%s", iname);
377 		if (write(ofd, buf, nbytes) != nbytes)
378 			err(1, "%s", oname);
379 		crc = crc32(crc, (Bytef *)buf, nbytes);
380 		ih->ih_size += nbytes;
381 	}
382 
383 	return crc;
384 }
385 
386 void
387 usage(void)
388 {
389 	const struct arch_map *mapptr;
390 	const struct os_map *osmapptr;
391 
392 	(void)fprintf(stderr,
393 	    "usage: %s [-a arch] [-e entry] [-l loadaddr] [-n name] [-o os] "
394 	    "[-t type] infile outfile\n", __progname);
395 	(void)fprintf(stderr,
396 	    "arch is one of:");
397 	for (mapptr = archmap; mapptr->arch; mapptr++)
398 		(void)fprintf(stderr, " %s", mapptr->arch);
399 	(void)fprintf(stderr, "\n");
400 	(void)fprintf(stderr,
401 	    "os is one of:");
402 	for (osmapptr = osmap; osmapptr->arch; osmapptr++)
403 		(void)fprintf(stderr, " %s", osmapptr->arch);
404 	(void)fprintf(stderr, "\n");
405 
406 	exit(1);
407 }
408