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