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