| @@ -1,610 +1,608 @@ | | | @@ -1,610 +1,608 @@ |
1 | /* $NetBSD: mkubootimage.c,v 1.26 2019/12/04 14:09:47 jmcneill Exp $ */ | | 1 | /* $NetBSD: mkubootimage.c,v 1.27 2019/12/07 12:34:17 wiz Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca> | | 4 | * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. The name of the author may not be used to endorse or promote products | | 12 | * 2. The name of the author may not be used to endorse or promote products |
13 | * derived from this software without specific prior written permission. | | 13 | * derived from this software without specific prior written permission. |
14 | * | | 14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
20 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 20 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
22 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 22 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | * SUCH DAMAGE. | | 25 | * SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | #if HAVE_NBTOOL_CONFIG_H | | 28 | #if HAVE_NBTOOL_CONFIG_H |
29 | #include "nbtool_config.h" | | 29 | #include "nbtool_config.h" |
30 | #endif | | 30 | #endif |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __RCSID("$NetBSD: mkubootimage.c,v 1.26 2019/12/04 14:09:47 jmcneill Exp $"); | | 33 | __RCSID("$NetBSD: mkubootimage.c,v 1.27 2019/12/07 12:34:17 wiz Exp $"); |
34 | | | 34 | |
35 | #include <sys/mman.h> | | 35 | #include <sys/mman.h> |
36 | #include <sys/stat.h> | | 36 | #include <sys/stat.h> |
37 | #include <sys/endian.h> | | 37 | #include <sys/endian.h> |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/uio.h> | | 39 | #include <sys/uio.h> |
40 | #include <err.h> | | 40 | #include <err.h> |
41 | #include <errno.h> | | 41 | #include <errno.h> |
42 | #include <fcntl.h> | | 42 | #include <fcntl.h> |
43 | #include <inttypes.h> | | 43 | #include <inttypes.h> |
44 | #include <limits.h> | | 44 | #include <limits.h> |
45 | #include <stdint.h> | | 45 | #include <stdint.h> |
46 | #include <stdio.h> | | 46 | #include <stdio.h> |
47 | #include <stdlib.h> | | 47 | #include <stdlib.h> |
48 | #include <string.h> | | 48 | #include <string.h> |
49 | #include <time.h> | | 49 | #include <time.h> |
50 | #include <unistd.h> | | 50 | #include <unistd.h> |
51 | | | 51 | |
52 | #include "uboot.h" | | 52 | #include "uboot.h" |
53 | #include "arm64.h" | | 53 | #include "arm64.h" |
54 | | | 54 | |
55 | #ifndef __arraycount | | 55 | #ifndef __arraycount |
56 | #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) | | 56 | #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) |
57 | #endif | | 57 | #endif |
58 | | | 58 | |
59 | enum image_format { | | 59 | enum image_format { |
60 | FMT_UNKNOWN, | | 60 | FMT_UNKNOWN, |
61 | FMT_UIMG, /* Legacy U-Boot image */ | | 61 | FMT_UIMG, /* Legacy U-Boot image */ |
62 | FMT_ARM64, /* Linux ARM64 image (booti) */ | | 62 | FMT_ARM64, /* Linux ARM64 image (booti) */ |
63 | }; | | 63 | }; |
64 | | | 64 | |
65 | extern uint32_t crc32(const void *, size_t); | | 65 | extern uint32_t crc32(const void *, size_t); |
66 | extern uint32_t crc32v(const struct iovec *, int); | | 66 | extern uint32_t crc32v(const struct iovec *, int); |
67 | | | 67 | |
68 | static enum uboot_image_os image_os = IH_OS_NETBSD; | | 68 | static enum uboot_image_os image_os = IH_OS_NETBSD; |
69 | static enum uboot_image_arch image_arch = IH_ARCH_UNKNOWN; | | 69 | static enum uboot_image_arch image_arch = IH_ARCH_UNKNOWN; |
70 | static enum uboot_image_type image_type = IH_TYPE_UNKNOWN; | | 70 | static enum uboot_image_type image_type = IH_TYPE_UNKNOWN; |
71 | static enum uboot_image_comp image_comp = IH_COMP_NONE; | | 71 | static enum uboot_image_comp image_comp = IH_COMP_NONE; |
72 | static uint32_t image_loadaddr = 0; | | 72 | static uint32_t image_loadaddr = 0; |
73 | static uint32_t image_entrypoint = 0; | | 73 | static uint32_t image_entrypoint = 0; |
74 | static char *image_name; | | 74 | static char *image_name; |
75 | static uint32_t image_magic = IH_MAGIC; | | 75 | static uint32_t image_magic = IH_MAGIC; |
76 | static enum image_format image_format = FMT_UIMG; | | 76 | static enum image_format image_format = FMT_UIMG; |
77 | static int update_image = 0; | | 77 | static int update_image = 0; |
78 | | | 78 | |
79 | static const struct uboot_image_format { | | 79 | static const struct uboot_image_format { |
80 | enum image_format format; | | 80 | enum image_format format; |
81 | const char *name; | | 81 | const char *name; |
82 | } uboot_image_format[] = { | | 82 | } uboot_image_format[] = { |
83 | { FMT_UIMG, "uimg" }, | | 83 | { FMT_UIMG, "uimg" }, |
84 | { FMT_ARM64, "arm64" }, | | 84 | { FMT_ARM64, "arm64" }, |
85 | }; | | 85 | }; |
86 | | | 86 | |
87 | static enum image_format | | 87 | static enum image_format |
88 | get_image_format(const char *name) | | 88 | get_image_format(const char *name) |
89 | { | | 89 | { |
90 | unsigned int i; | | 90 | unsigned int i; |
91 | | | 91 | |
92 | for (i = 0; i < __arraycount(uboot_image_format); i++) { | | 92 | for (i = 0; i < __arraycount(uboot_image_format); i++) { |
93 | if (strcmp(uboot_image_format[i].name, name) == 0) | | 93 | if (strcmp(uboot_image_format[i].name, name) == 0) |
94 | return uboot_image_format[i].format; | | 94 | return uboot_image_format[i].format; |
95 | } | | 95 | } |
96 | | | 96 | |
97 | return FMT_UNKNOWN; | | 97 | return FMT_UNKNOWN; |
98 | } | | 98 | } |
99 | | | 99 | |
100 | static const char * | | 100 | static const char * |
101 | get_image_format_name(enum image_format format) | | 101 | get_image_format_name(enum image_format format) |
102 | { | | 102 | { |
103 | unsigned int i; | | 103 | unsigned int i; |
104 | | | 104 | |
105 | for (i = 0; i < __arraycount(uboot_image_format); i++) { | | 105 | for (i = 0; i < __arraycount(uboot_image_format); i++) { |
106 | if (uboot_image_format[i].format == format) | | 106 | if (uboot_image_format[i].format == format) |
107 | return uboot_image_format[i].name; | | 107 | return uboot_image_format[i].name; |
108 | } | | 108 | } |
109 | | | 109 | |
110 | return "Unknown"; | | 110 | return "Unknown"; |
111 | } | | 111 | } |
112 | | | 112 | |
113 | static const struct uboot_os { | | 113 | static const struct uboot_os { |
114 | enum uboot_image_os os; | | 114 | enum uboot_image_os os; |
115 | const char *name; | | 115 | const char *name; |
116 | } uboot_os[] = { | | 116 | } uboot_os[] = { |
117 | { IH_OS_OPENBSD, "openbsd" }, | | 117 | { IH_OS_OPENBSD, "openbsd" }, |
118 | { IH_OS_NETBSD, "netbsd" }, | | 118 | { IH_OS_NETBSD, "netbsd" }, |
119 | { IH_OS_FREEBSD, "freebsd" }, | | 119 | { IH_OS_FREEBSD, "freebsd" }, |
120 | { IH_OS_LINUX, "linux" }, | | 120 | { IH_OS_LINUX, "linux" }, |
121 | }; | | 121 | }; |
122 | | | 122 | |
123 | static enum uboot_image_os | | 123 | static enum uboot_image_os |
124 | get_os(const char *name) | | 124 | get_os(const char *name) |
125 | { | | 125 | { |
126 | unsigned int i; | | 126 | unsigned int i; |
127 | | | 127 | |
128 | for (i = 0; i < __arraycount(uboot_os); i++) { | | 128 | for (i = 0; i < __arraycount(uboot_os); i++) { |
129 | if (strcmp(uboot_os[i].name, name) == 0) | | 129 | if (strcmp(uboot_os[i].name, name) == 0) |
130 | return uboot_os[i].os; | | 130 | return uboot_os[i].os; |
131 | } | | 131 | } |
132 | | | 132 | |
133 | return IH_OS_UNKNOWN; | | 133 | return IH_OS_UNKNOWN; |
134 | } | | 134 | } |
135 | | | 135 | |
136 | static const char * | | 136 | static const char * |
137 | get_os_name(enum uboot_image_os os) | | 137 | get_os_name(enum uboot_image_os os) |
138 | { | | 138 | { |
139 | unsigned int i; | | 139 | unsigned int i; |
140 | | | 140 | |
141 | for (i = 0; i < __arraycount(uboot_os); i++) { | | 141 | for (i = 0; i < __arraycount(uboot_os); i++) { |
142 | if (uboot_os[i].os == os) | | 142 | if (uboot_os[i].os == os) |
143 | return uboot_os[i].name; | | 143 | return uboot_os[i].name; |
144 | } | | 144 | } |
145 | | | 145 | |
146 | return "Unknown"; | | 146 | return "Unknown"; |
147 | } | | 147 | } |
148 | | | 148 | |
149 | static const struct uboot_arch { | | 149 | static const struct uboot_arch { |
150 | enum uboot_image_arch arch; | | 150 | enum uboot_image_arch arch; |
151 | const char *name; | | 151 | const char *name; |
152 | } uboot_arch[] = { | | 152 | } uboot_arch[] = { |
153 | { IH_ARCH_ARM, "arm" }, | | 153 | { IH_ARCH_ARM, "arm" }, |
154 | { IH_ARCH_ARM64, "arm64" }, | | 154 | { IH_ARCH_ARM64, "arm64" }, |
155 | { IH_ARCH_I386, "i386" }, | | 155 | { IH_ARCH_I386, "i386" }, |
156 | { IH_ARCH_MIPS, "mips" }, | | 156 | { IH_ARCH_MIPS, "mips" }, |
157 | { IH_ARCH_MIPS64, "mips64" }, | | 157 | { IH_ARCH_MIPS64, "mips64" }, |
158 | { IH_ARCH_PPC, "powerpc" }, | | 158 | { IH_ARCH_PPC, "powerpc" }, |
159 | { IH_ARCH_OPENRISC, "or1k" }, | | 159 | { IH_ARCH_OPENRISC, "or1k" }, |
160 | { IH_ARCH_SH, "sh" }, | | 160 | { IH_ARCH_SH, "sh" }, |
161 | }; | | 161 | }; |
162 | | | 162 | |
163 | static enum uboot_image_arch | | 163 | static enum uboot_image_arch |
164 | get_arch(const char *name) | | 164 | get_arch(const char *name) |
165 | { | | 165 | { |
166 | unsigned int i; | | 166 | unsigned int i; |
167 | | | 167 | |
168 | for (i = 0; i < __arraycount(uboot_arch); i++) { | | 168 | for (i = 0; i < __arraycount(uboot_arch); i++) { |
169 | if (strcmp(uboot_arch[i].name, name) == 0) | | 169 | if (strcmp(uboot_arch[i].name, name) == 0) |
170 | return uboot_arch[i].arch; | | 170 | return uboot_arch[i].arch; |
171 | } | | 171 | } |
172 | | | 172 | |
173 | return IH_ARCH_UNKNOWN; | | 173 | return IH_ARCH_UNKNOWN; |
174 | } | | 174 | } |
175 | | | 175 | |
176 | static const char * | | 176 | static const char * |
177 | get_arch_name(enum uboot_image_arch arch) | | 177 | get_arch_name(enum uboot_image_arch arch) |
178 | { | | 178 | { |
179 | unsigned int i; | | 179 | unsigned int i; |
180 | | | 180 | |
181 | for (i = 0; i < __arraycount(uboot_arch); i++) { | | 181 | for (i = 0; i < __arraycount(uboot_arch); i++) { |
182 | if (uboot_arch[i].arch == arch) | | 182 | if (uboot_arch[i].arch == arch) |
183 | return uboot_arch[i].name; | | 183 | return uboot_arch[i].name; |
184 | } | | 184 | } |
185 | | | 185 | |
186 | return "Unknown"; | | 186 | return "Unknown"; |
187 | } | | 187 | } |
188 | | | 188 | |
189 | static const struct uboot_type { | | 189 | static const struct uboot_type { |
190 | enum uboot_image_type type; | | 190 | enum uboot_image_type type; |
191 | const char *name; | | 191 | const char *name; |
192 | } uboot_type[] = { | | 192 | } uboot_type[] = { |
193 | { IH_TYPE_STANDALONE, "standalone" }, | | 193 | { IH_TYPE_STANDALONE, "standalone" }, |
194 | { IH_TYPE_KERNEL, "kernel" }, | | 194 | { IH_TYPE_KERNEL, "kernel" }, |
195 | { IH_TYPE_KERNEL_NOLOAD, "kernel_noload" }, | | 195 | { IH_TYPE_KERNEL_NOLOAD, "kernel_noload" }, |
196 | { IH_TYPE_RAMDISK, "ramdisk" }, | | 196 | { IH_TYPE_RAMDISK, "ramdisk" }, |
197 | { IH_TYPE_FILESYSTEM, "fs" }, | | 197 | { IH_TYPE_FILESYSTEM, "fs" }, |
198 | { IH_TYPE_SCRIPT, "script" }, | | 198 | { IH_TYPE_SCRIPT, "script" }, |
199 | }; | | 199 | }; |
200 | | | 200 | |
201 | static enum uboot_image_type | | 201 | static enum uboot_image_type |
202 | get_type(const char *name) | | 202 | get_type(const char *name) |
203 | { | | 203 | { |
204 | unsigned int i; | | 204 | unsigned int i; |
205 | | | 205 | |
206 | for (i = 0; i < __arraycount(uboot_type); i++) { | | 206 | for (i = 0; i < __arraycount(uboot_type); i++) { |
207 | if (strcmp(uboot_type[i].name, name) == 0) | | 207 | if (strcmp(uboot_type[i].name, name) == 0) |
208 | return uboot_type[i].type; | | 208 | return uboot_type[i].type; |
209 | } | | 209 | } |
210 | | | 210 | |
211 | return IH_TYPE_UNKNOWN; | | 211 | return IH_TYPE_UNKNOWN; |
212 | } | | 212 | } |
213 | | | 213 | |
214 | static const char * | | 214 | static const char * |
215 | get_type_name(enum uboot_image_type type) | | 215 | get_type_name(enum uboot_image_type type) |
216 | { | | 216 | { |
217 | unsigned int i; | | 217 | unsigned int i; |
218 | | | 218 | |
219 | for (i = 0; i < __arraycount(uboot_type); i++) { | | 219 | for (i = 0; i < __arraycount(uboot_type); i++) { |
220 | if (uboot_type[i].type == type) | | 220 | if (uboot_type[i].type == type) |
221 | return uboot_type[i].name; | | 221 | return uboot_type[i].name; |
222 | } | | 222 | } |
223 | | | 223 | |
224 | return "Unknown"; | | 224 | return "Unknown"; |
225 | } | | 225 | } |
226 | | | 226 | |
227 | static const struct uboot_comp { | | 227 | static const struct uboot_comp { |
228 | enum uboot_image_comp comp; | | 228 | enum uboot_image_comp comp; |
229 | const char *name; | | 229 | const char *name; |
230 | } uboot_comp[] = { | | 230 | } uboot_comp[] = { |
231 | { IH_COMP_NONE, "none" }, | | 231 | { IH_COMP_NONE, "none" }, |
232 | { IH_COMP_GZIP, "gz" }, | | 232 | { IH_COMP_GZIP, "gz" }, |
233 | { IH_COMP_BZIP2, "bz2" }, | | 233 | { IH_COMP_BZIP2, "bz2" }, |
234 | { IH_COMP_LZMA, "lzma" }, | | 234 | { IH_COMP_LZMA, "lzma" }, |
235 | { IH_COMP_LZO, "lzo" }, | | 235 | { IH_COMP_LZO, "lzo" }, |
236 | }; | | 236 | }; |
237 | | | 237 | |
238 | static enum uboot_image_comp | | 238 | static enum uboot_image_comp |
239 | get_comp(const char *name) | | 239 | get_comp(const char *name) |
240 | { | | 240 | { |
241 | unsigned int i; | | 241 | unsigned int i; |
242 | | | 242 | |
243 | for (i = 0; i < __arraycount(uboot_comp); i++) { | | 243 | for (i = 0; i < __arraycount(uboot_comp); i++) { |
244 | if (strcmp(uboot_comp[i].name, name) == 0) | | 244 | if (strcmp(uboot_comp[i].name, name) == 0) |
245 | return uboot_comp[i].comp; | | 245 | return uboot_comp[i].comp; |
246 | } | | 246 | } |
247 | | | 247 | |
248 | return IH_COMP_NONE; | | 248 | return IH_COMP_NONE; |
249 | } | | 249 | } |
250 | | | 250 | |
251 | static const char * | | 251 | static const char * |
252 | get_comp_name(enum uboot_image_comp comp) | | 252 | get_comp_name(enum uboot_image_comp comp) |
253 | { | | 253 | { |
254 | unsigned int i; | | 254 | unsigned int i; |
255 | | | 255 | |
256 | for (i = 0; i < __arraycount(uboot_comp); i++) { | | 256 | for (i = 0; i < __arraycount(uboot_comp); i++) { |
257 | if (uboot_comp[i].comp == comp) | | 257 | if (uboot_comp[i].comp == comp) |
258 | return uboot_comp[i].name; | | 258 | return uboot_comp[i].name; |
259 | } | | 259 | } |
260 | | | 260 | |
261 | return "Unknown"; | | 261 | return "Unknown"; |
262 | } | | 262 | } |
263 | | | 263 | |
264 | __dead static void | | 264 | __dead static void |
265 | usage(void) | | 265 | usage(void) |
266 | { | | 266 | { |
267 | fprintf(stderr, "usage: mkubootimage -A " | | 267 | fprintf(stderr, "usage: mkubootimage [-hu] -A " |
268 | "<arm|arm64|i386|mips|mips64|or1k|powerpc|sh>"); | | 268 | "<arm|arm64|i386|mips|mips64|or1k|powerpc|sh> -a address\n"); |
269 | fprintf(stderr, " -C <none|bz2|gz|lzma|lzo>"); | | 269 | fprintf(stderr, "\t-C <bz2|gz|lzma|lzo|none> [-E address] [-e address]\n"); |
270 | fprintf(stderr, " -O <openbsd|netbsd|freebsd|linux>"); | | 270 | fprintf(stderr, "\t[-f <arm64|uimg>] [-m magic] -n image -O <freebsd|linux|netbsd|openbsd>\n"); |
271 | fprintf(stderr, " -T <standalone|kernel|kernel_noload|ramdisk|fs|script>"); | | 271 | fprintf(stderr, "\t-T <fs|kernel|kernel_noload|ramdisk|script|standalone>\n"); |
272 | fprintf(stderr, " -a <addr> [-e <ep>] [-m <magic>] -n <name>"); | | 272 | fprintf(stderr, "\tsource destination\n"); |
273 | fprintf(stderr, " [-f <uimg|arm64>] [-u]"); | | | |
274 | fprintf(stderr, " <srcfile> <dstfile>\n"); | | | |
275 | | | 273 | |
276 | exit(EXIT_FAILURE); | | 274 | exit(EXIT_FAILURE); |
277 | } | | 275 | } |
278 | | | 276 | |
279 | static void | | 277 | static void |
280 | dump_header_uimg(struct uboot_image_header *hdr) | | 278 | dump_header_uimg(struct uboot_image_header *hdr) |
281 | { | | 279 | { |
282 | time_t tm = ntohl(hdr->ih_time); | | 280 | time_t tm = ntohl(hdr->ih_time); |
283 | | | 281 | |
284 | printf(" magic: 0x%08x\n", ntohl(hdr->ih_magic)); | | 282 | printf(" magic: 0x%08x\n", ntohl(hdr->ih_magic)); |
285 | printf(" time: %s", ctime(&tm)); | | 283 | printf(" time: %s", ctime(&tm)); |
286 | printf(" size: %u\n", ntohl(hdr->ih_size)); | | 284 | printf(" size: %u\n", ntohl(hdr->ih_size)); |
287 | printf(" load addr: 0x%08x\n", ntohl(hdr->ih_load)); | | 285 | printf(" load addr: 0x%08x\n", ntohl(hdr->ih_load)); |
288 | printf(" entry point: 0x%08x\n", ntohl(hdr->ih_ep)); | | 286 | printf(" entry point: 0x%08x\n", ntohl(hdr->ih_ep)); |
289 | printf(" data crc: 0x%08x\n", ntohl(hdr->ih_dcrc)); | | 287 | printf(" data crc: 0x%08x\n", ntohl(hdr->ih_dcrc)); |
290 | printf(" os: %d (%s)\n", hdr->ih_os, | | 288 | printf(" os: %d (%s)\n", hdr->ih_os, |
291 | get_os_name(hdr->ih_os)); | | 289 | get_os_name(hdr->ih_os)); |
292 | printf(" arch: %d (%s)\n", hdr->ih_arch, | | 290 | printf(" arch: %d (%s)\n", hdr->ih_arch, |
293 | get_arch_name(hdr->ih_arch)); | | 291 | get_arch_name(hdr->ih_arch)); |
294 | printf(" type: %d (%s)\n", hdr->ih_type, | | 292 | printf(" type: %d (%s)\n", hdr->ih_type, |
295 | get_type_name(hdr->ih_type)); | | 293 | get_type_name(hdr->ih_type)); |
296 | printf(" comp: %d (%s)\n", hdr->ih_comp, | | 294 | printf(" comp: %d (%s)\n", hdr->ih_comp, |
297 | get_comp_name(hdr->ih_comp)); | | 295 | get_comp_name(hdr->ih_comp)); |
298 | printf(" name: %s\n", hdr->ih_name); | | 296 | printf(" name: %s\n", hdr->ih_name); |
299 | printf(" header crc: 0x%08x\n", hdr->ih_hcrc); | | 297 | printf(" header crc: 0x%08x\n", hdr->ih_hcrc); |
300 | } | | 298 | } |
301 | | | 299 | |
302 | static int | | 300 | static int |
303 | generate_header_uimg(struct uboot_image_header *hdr, int kernel_fd) | | 301 | generate_header_uimg(struct uboot_image_header *hdr, int kernel_fd) |
304 | { | | 302 | { |
305 | uint8_t *p; | | 303 | uint8_t *p; |
306 | struct stat st; | | 304 | struct stat st; |
307 | uint32_t crc, dsize, size_buf[2]; | | 305 | uint32_t crc, dsize, size_buf[2]; |
308 | int error; | | 306 | int error; |
309 | | | 307 | |
310 | error = fstat(kernel_fd, &st); | | 308 | error = fstat(kernel_fd, &st); |
311 | if (error == -1) { | | 309 | if (error == -1) { |
312 | perror("stat"); | | 310 | perror("stat"); |
313 | return errno; | | 311 | return errno; |
314 | } | | 312 | } |
315 | | | 313 | |
316 | if (st.st_size + sizeof(*hdr) > UINT32_MAX) { | | 314 | if (st.st_size + sizeof(*hdr) > UINT32_MAX) { |
317 | fprintf(stderr, "fatal: kernel too big\n"); | | 315 | fprintf(stderr, "fatal: kernel too big\n"); |
318 | return EINVAL; | | 316 | return EINVAL; |
319 | } | | 317 | } |
320 | | | 318 | |
321 | p = mmap(0, st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, kernel_fd, 0); | | 319 | p = mmap(0, st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, kernel_fd, 0); |
322 | if (p == MAP_FAILED) { | | 320 | if (p == MAP_FAILED) { |
323 | perror("mmap kernel"); | | 321 | perror("mmap kernel"); |
324 | return EINVAL; | | 322 | return EINVAL; |
325 | } | | 323 | } |
326 | if (image_type == IH_TYPE_SCRIPT) { | | 324 | if (image_type == IH_TYPE_SCRIPT) { |
327 | struct iovec iov[3]; | | 325 | struct iovec iov[3]; |
328 | dsize = st.st_size + (sizeof(uint32_t) * 2); | | 326 | dsize = st.st_size + (sizeof(uint32_t) * 2); |
329 | size_buf[0] = htonl(st.st_size); | | 327 | size_buf[0] = htonl(st.st_size); |
330 | size_buf[1] = htonl(0); | | 328 | size_buf[1] = htonl(0); |
331 | iov[0].iov_base = &size_buf[0]; | | 329 | iov[0].iov_base = &size_buf[0]; |
332 | iov[0].iov_len = sizeof(size_buf[0]); | | 330 | iov[0].iov_len = sizeof(size_buf[0]); |
333 | iov[1].iov_base = &size_buf[1]; | | 331 | iov[1].iov_base = &size_buf[1]; |
334 | iov[1].iov_len = sizeof(size_buf[1]); | | 332 | iov[1].iov_len = sizeof(size_buf[1]); |
335 | iov[2].iov_base = p; | | 333 | iov[2].iov_base = p; |
336 | iov[2].iov_len = st.st_size; | | 334 | iov[2].iov_len = st.st_size; |
337 | crc = crc32v(iov, 3); | | 335 | crc = crc32v(iov, 3); |
338 | } else { | | 336 | } else { |
339 | dsize = st.st_size; | | 337 | dsize = st.st_size; |
340 | crc = crc32(p, st.st_size); | | 338 | crc = crc32(p, st.st_size); |
341 | } | | 339 | } |
342 | munmap(p, st.st_size); | | 340 | munmap(p, st.st_size); |
343 | | | 341 | |
344 | memset(hdr, 0, sizeof(*hdr)); | | 342 | memset(hdr, 0, sizeof(*hdr)); |
345 | hdr->ih_magic = htonl(image_magic); | | 343 | hdr->ih_magic = htonl(image_magic); |
346 | hdr->ih_time = htonl(st.st_mtime); | | 344 | hdr->ih_time = htonl(st.st_mtime); |
347 | hdr->ih_size = htonl(dsize); | | 345 | hdr->ih_size = htonl(dsize); |
348 | hdr->ih_load = htonl(image_loadaddr); | | 346 | hdr->ih_load = htonl(image_loadaddr); |
349 | hdr->ih_ep = htonl(image_entrypoint); | | 347 | hdr->ih_ep = htonl(image_entrypoint); |
350 | hdr->ih_dcrc = htonl(crc); | | 348 | hdr->ih_dcrc = htonl(crc); |
351 | hdr->ih_os = image_os; | | 349 | hdr->ih_os = image_os; |
352 | hdr->ih_arch = image_arch; | | 350 | hdr->ih_arch = image_arch; |
353 | hdr->ih_type = image_type; | | 351 | hdr->ih_type = image_type; |
354 | hdr->ih_comp = image_comp; | | 352 | hdr->ih_comp = image_comp; |
355 | strlcpy((char *)hdr->ih_name, image_name, sizeof(hdr->ih_name)); | | 353 | strlcpy((char *)hdr->ih_name, image_name, sizeof(hdr->ih_name)); |
356 | crc = crc32((void *)hdr, sizeof(*hdr)); | | 354 | crc = crc32((void *)hdr, sizeof(*hdr)); |
357 | hdr->ih_hcrc = htonl(crc); | | 355 | hdr->ih_hcrc = htonl(crc); |
358 | | | 356 | |
359 | dump_header_uimg(hdr); | | 357 | dump_header_uimg(hdr); |
360 | | | 358 | |
361 | return 0; | | 359 | return 0; |
362 | } | | 360 | } |
363 | | | 361 | |
364 | static void | | 362 | static void |
365 | dump_header_arm64(struct arm64_image_header *hdr) | | 363 | dump_header_arm64(struct arm64_image_header *hdr) |
366 | { | | 364 | { |
367 | printf(" magic: 0x%" PRIx32 "\n", le32toh(hdr->magic)); | | 365 | printf(" magic: 0x%" PRIx32 "\n", le32toh(hdr->magic)); |
368 | printf(" text offset: 0x%" PRIx64 "\n", le64toh(hdr->text_offset)); | | 366 | printf(" text offset: 0x%" PRIx64 "\n", le64toh(hdr->text_offset)); |
369 | printf(" image size: %" PRIu64 "\n", le64toh(hdr->image_size)); | | 367 | printf(" image size: %" PRIu64 "\n", le64toh(hdr->image_size)); |
370 | printf(" flags: 0x%" PRIx64 "\n", le64toh(hdr->flags)); | | 368 | printf(" flags: 0x%" PRIx64 "\n", le64toh(hdr->flags)); |
371 | } | | 369 | } |
372 | | | 370 | |
373 | static int | | 371 | static int |
374 | generate_header_arm64(struct arm64_image_header *hdr, int kernel_fd) | | 372 | generate_header_arm64(struct arm64_image_header *hdr, int kernel_fd) |
375 | { | | 373 | { |
376 | struct stat st; | | 374 | struct stat st; |
377 | uint32_t flags; | | 375 | uint32_t flags; |
378 | int error; | | 376 | int error; |
379 | | | 377 | |
380 | error = fstat(kernel_fd, &st); | | 378 | error = fstat(kernel_fd, &st); |
381 | if (error == -1) { | | 379 | if (error == -1) { |
382 | perror("stat"); | | 380 | perror("stat"); |
383 | return errno; | | 381 | return errno; |
384 | } | | 382 | } |
385 | | | 383 | |
386 | flags = 0; | | 384 | flags = 0; |
387 | flags |= ARM64_FLAGS_PAGE_SIZE_4K; | | 385 | flags |= ARM64_FLAGS_PAGE_SIZE_4K; |
388 | #if 0 | | 386 | #if 0 |
389 | flags |= ARM64_FLAGS_PHYS_PLACEMENT_ANY; | | 387 | flags |= ARM64_FLAGS_PHYS_PLACEMENT_ANY; |
390 | #endif | | 388 | #endif |
391 | | | 389 | |
392 | memset(hdr, 0, sizeof(*hdr)); | | 390 | memset(hdr, 0, sizeof(*hdr)); |
393 | hdr->code0 = htole32(ARM64_CODE0); | | 391 | hdr->code0 = htole32(ARM64_CODE0); |
394 | hdr->text_offset = htole64(image_entrypoint); | | 392 | hdr->text_offset = htole64(image_entrypoint); |
395 | hdr->image_size = htole64(st.st_size + sizeof(*hdr)); | | 393 | hdr->image_size = htole64(st.st_size + sizeof(*hdr)); |
396 | hdr->flags = htole32(flags); | | 394 | hdr->flags = htole32(flags); |
397 | hdr->magic = htole32(ARM64_MAGIC); | | 395 | hdr->magic = htole32(ARM64_MAGIC); |
398 | | | 396 | |
399 | dump_header_arm64(hdr); | | 397 | dump_header_arm64(hdr); |
400 | | | 398 | |
401 | return 0; | | 399 | return 0; |
402 | } | | 400 | } |
403 | | | 401 | |
404 | static int | | 402 | static int |
405 | write_image(void *hdr, size_t hdrlen, int kernel_fd, int image_fd) | | 403 | write_image(void *hdr, size_t hdrlen, int kernel_fd, int image_fd) |
406 | { | | 404 | { |
407 | uint8_t buf[4096]; | | 405 | uint8_t buf[4096]; |
408 | ssize_t rlen, wlen; | | 406 | ssize_t rlen, wlen; |
409 | struct stat st; | | 407 | struct stat st; |
410 | uint32_t size_buf[2]; | | 408 | uint32_t size_buf[2]; |
411 | int error; | | 409 | int error; |
412 | | | 410 | |
413 | error = fstat(kernel_fd, &st); | | 411 | error = fstat(kernel_fd, &st); |
414 | if (error == -1) { | | 412 | if (error == -1) { |
415 | perror("stat"); | | 413 | perror("stat"); |
416 | return errno; | | 414 | return errno; |
417 | } | | 415 | } |
418 | | | 416 | |
419 | wlen = write(image_fd, hdr, hdrlen); | | 417 | wlen = write(image_fd, hdr, hdrlen); |
420 | if (wlen != (ssize_t)hdrlen) { | | 418 | if (wlen != (ssize_t)hdrlen) { |
421 | perror("short write"); | | 419 | perror("short write"); |
422 | return errno; | | 420 | return errno; |
423 | } | | 421 | } |
424 | | | 422 | |
425 | if (image_type == IH_TYPE_SCRIPT) { | | 423 | if (image_type == IH_TYPE_SCRIPT) { |
426 | size_buf[0] = htonl(st.st_size); | | 424 | size_buf[0] = htonl(st.st_size); |
427 | size_buf[1] = htonl(0); | | 425 | size_buf[1] = htonl(0); |
428 | wlen = write(image_fd, &size_buf, sizeof(size_buf)); | | 426 | wlen = write(image_fd, &size_buf, sizeof(size_buf)); |
429 | if (wlen != sizeof(size_buf)) { | | 427 | if (wlen != sizeof(size_buf)) { |
430 | perror("short write"); | | 428 | perror("short write"); |
431 | return errno; | | 429 | return errno; |
432 | } | | 430 | } |
433 | } | | 431 | } |
434 | | | 432 | |
435 | if (update_image) { | | 433 | if (update_image) { |
436 | if (lseek(kernel_fd, hdrlen, SEEK_SET) != (off_t)hdrlen) { | | 434 | if (lseek(kernel_fd, hdrlen, SEEK_SET) != (off_t)hdrlen) { |
437 | perror("seek failed"); | | 435 | perror("seek failed"); |
438 | return errno; | | 436 | return errno; |
439 | } | | 437 | } |
440 | } | | 438 | } |
441 | | | 439 | |
442 | while ((rlen = read(kernel_fd, buf, sizeof(buf))) > 0) { | | 440 | while ((rlen = read(kernel_fd, buf, sizeof(buf))) > 0) { |
443 | wlen = write(image_fd, buf, rlen); | | 441 | wlen = write(image_fd, buf, rlen); |
444 | if (wlen != rlen) { | | 442 | if (wlen != rlen) { |
445 | perror("short write"); | | 443 | perror("short write"); |
446 | return errno; | | 444 | return errno; |
447 | } | | 445 | } |
448 | } | | 446 | } |
449 | | | 447 | |
450 | return 0; | | 448 | return 0; |
451 | } | | 449 | } |
452 | | | 450 | |
453 | int | | 451 | int |
454 | main(int argc, char *argv[]) | | 452 | main(int argc, char *argv[]) |
455 | { | | 453 | { |
456 | struct uboot_image_header hdr_uimg; | | 454 | struct uboot_image_header hdr_uimg; |
457 | struct arm64_image_header hdr_arm64; | | 455 | struct arm64_image_header hdr_arm64; |
458 | const char *src, *dest; | | 456 | const char *src, *dest; |
459 | char *ep; | | 457 | char *ep; |
460 | int kernel_fd, image_fd; | | 458 | int kernel_fd, image_fd; |
461 | int ch; | | 459 | int ch; |
462 | unsigned long long num; | | 460 | unsigned long long num; |
463 | | | 461 | |
464 | while ((ch = getopt(argc, argv, "A:C:E:O:T:a:e:f:hm:n:u")) != -1) { | | 462 | while ((ch = getopt(argc, argv, "A:C:E:O:T:a:e:f:hm:n:u")) != -1) { |
465 | switch (ch) { | | 463 | switch (ch) { |
466 | case 'A': /* arch */ | | 464 | case 'A': /* arch */ |
467 | image_arch = get_arch(optarg); | | 465 | image_arch = get_arch(optarg); |
468 | break; | | 466 | break; |
469 | case 'C': /* comp */ | | 467 | case 'C': /* comp */ |
470 | image_comp = get_comp(optarg); | | 468 | image_comp = get_comp(optarg); |
471 | break; | | 469 | break; |
472 | case 'O': /* os */ | | 470 | case 'O': /* os */ |
473 | image_os = get_os(optarg); | | 471 | image_os = get_os(optarg); |
474 | break; | | 472 | break; |
475 | case 'T': /* type */ | | 473 | case 'T': /* type */ |
476 | image_type = get_type(optarg); | | 474 | image_type = get_type(optarg); |
477 | break; | | 475 | break; |
478 | case 'a': /* addr */ | | 476 | case 'a': /* addr */ |
479 | errno = 0; | | 477 | errno = 0; |
480 | num = strtoull(optarg, &ep, 0); | | 478 | num = strtoull(optarg, &ep, 0); |
481 | if (*ep != '\0' || (errno == ERANGE && | | 479 | if (*ep != '\0' || (errno == ERANGE && |
482 | (num == ULLONG_MAX || num == 0)) || | | 480 | (num == ULLONG_MAX || num == 0)) || |
483 | ((signed long long)num != (int32_t)num && | | 481 | ((signed long long)num != (int32_t)num && |
484 | num != (uint32_t)num)) | | 482 | num != (uint32_t)num)) |
485 | errx(1, "illegal number -- %s", optarg); | | 483 | errx(1, "illegal number -- %s", optarg); |
486 | image_loadaddr = (uint32_t)num; | | 484 | image_loadaddr = (uint32_t)num; |
487 | break; | | 485 | break; |
488 | case 'E': /* ep (byte swapped) */ | | 486 | case 'E': /* ep (byte swapped) */ |
489 | case 'e': /* ep */ | | 487 | case 'e': /* ep */ |
490 | errno = 0; | | 488 | errno = 0; |
491 | num = strtoull(optarg, &ep, 0); | | 489 | num = strtoull(optarg, &ep, 0); |
492 | if (*ep != '\0' || (errno == ERANGE && | | 490 | if (*ep != '\0' || (errno == ERANGE && |
493 | (num == ULLONG_MAX || num == 0)) || | | 491 | (num == ULLONG_MAX || num == 0)) || |
494 | ((signed long long)num != (int32_t)num && | | 492 | ((signed long long)num != (int32_t)num && |
495 | num != (uint32_t)num)) | | 493 | num != (uint32_t)num)) |
496 | errx(1, "illegal number -- %s", optarg); | | 494 | errx(1, "illegal number -- %s", optarg); |
497 | image_entrypoint = (uint32_t)num; | | 495 | image_entrypoint = (uint32_t)num; |
498 | if (ch == 'E') | | 496 | if (ch == 'E') |
499 | image_entrypoint = bswap32(image_entrypoint); | | 497 | image_entrypoint = bswap32(image_entrypoint); |
500 | break; | | 498 | break; |
501 | case 'f': /* image format */ | | 499 | case 'f': /* image format */ |
502 | image_format = get_image_format(optarg); | | 500 | image_format = get_image_format(optarg); |
503 | break; | | 501 | break; |
504 | case 'm': /* magic */ | | 502 | case 'm': /* magic */ |
505 | errno = 0; | | 503 | errno = 0; |
506 | num = strtoul(optarg, &ep, 0); | | 504 | num = strtoul(optarg, &ep, 0); |
507 | if (*ep != '\0' || (errno == ERANGE && | | 505 | if (*ep != '\0' || (errno == ERANGE && |
508 | (num == ULONG_MAX || num == 0))) | | 506 | (num == ULONG_MAX || num == 0))) |
509 | errx(1, "illegal number -- %s", optarg); | | 507 | errx(1, "illegal number -- %s", optarg); |
510 | image_magic = (uint32_t)num; | | 508 | image_magic = (uint32_t)num; |
511 | break; | | 509 | break; |
512 | case 'n': /* name */ | | 510 | case 'n': /* name */ |
513 | image_name = strdup(optarg); | | 511 | image_name = strdup(optarg); |
514 | break; | | 512 | break; |
515 | case 'u': /* update image */ | | 513 | case 'u': /* update image */ |
516 | update_image = 1; | | 514 | update_image = 1; |
517 | break; | | 515 | break; |
518 | case 'h': | | 516 | case 'h': |
519 | default: | | 517 | default: |
520 | usage(); | | 518 | usage(); |
521 | /* NOTREACHED */ | | 519 | /* NOTREACHED */ |
522 | } | | 520 | } |
523 | } | | 521 | } |
524 | argc -= optind; | | 522 | argc -= optind; |
525 | argv += optind; | | 523 | argv += optind; |
526 | | | 524 | |
527 | if (argc != 2) | | 525 | if (argc != 2) |
528 | usage(); | | 526 | usage(); |
529 | | | 527 | |
530 | if (image_entrypoint == 0) | | 528 | if (image_entrypoint == 0) |
531 | image_entrypoint = image_loadaddr; | | 529 | image_entrypoint = image_loadaddr; |
532 | | | 530 | |
533 | switch (image_format) { | | 531 | switch (image_format) { |
534 | case FMT_UIMG: | | 532 | case FMT_UIMG: |
535 | if (image_arch == IH_ARCH_UNKNOWN || | | 533 | if (image_arch == IH_ARCH_UNKNOWN || |
536 | image_type == IH_TYPE_UNKNOWN || | | 534 | image_type == IH_TYPE_UNKNOWN || |
537 | image_name == NULL) | | 535 | image_name == NULL) |
538 | usage(); | | 536 | usage(); |
539 | /* NOTREACHED */ | | 537 | /* NOTREACHED */ |
540 | | | 538 | |
541 | switch (image_type) { | | 539 | switch (image_type) { |
542 | case IH_TYPE_SCRIPT: | | 540 | case IH_TYPE_SCRIPT: |
543 | case IH_TYPE_RAMDISK: | | 541 | case IH_TYPE_RAMDISK: |
544 | case IH_TYPE_KERNEL_NOLOAD: | | 542 | case IH_TYPE_KERNEL_NOLOAD: |
545 | break; | | 543 | break; |
546 | default: | | 544 | default: |
547 | if (image_loadaddr == 0) | | 545 | if (image_loadaddr == 0) |
548 | usage(); | | 546 | usage(); |
549 | /* NOTREACHED */ | | 547 | /* NOTREACHED */ |
550 | break; | | 548 | break; |
551 | } | | 549 | } |
552 | break; | | 550 | break; |
553 | | | 551 | |
554 | case FMT_ARM64: | | 552 | case FMT_ARM64: |
555 | if (image_arch != IH_ARCH_UNKNOWN && | | 553 | if (image_arch != IH_ARCH_UNKNOWN && |
556 | image_arch != IH_ARCH_ARM64) | | 554 | image_arch != IH_ARCH_ARM64) |
557 | usage(); | | 555 | usage(); |
558 | /* NOTREACHED */ | | 556 | /* NOTREACHED */ |
559 | | | 557 | |
560 | break; | | 558 | break; |
561 | | | 559 | |
562 | default: | | 560 | default: |
563 | usage(); | | 561 | usage(); |
564 | /* NOTREACHED */ | | 562 | /* NOTREACHED */ |
565 | } | | 563 | } |
566 | | | 564 | |
567 | src = argv[0]; | | 565 | src = argv[0]; |
568 | dest = argv[1]; | | 566 | dest = argv[1]; |
569 | | | 567 | |
570 | kernel_fd = open(src, O_RDONLY); | | 568 | kernel_fd = open(src, O_RDONLY); |
571 | if (kernel_fd == -1) { | | 569 | if (kernel_fd == -1) { |
572 | perror("open kernel"); | | 570 | perror("open kernel"); |
573 | return EXIT_FAILURE; | | 571 | return EXIT_FAILURE; |
574 | } | | 572 | } |
575 | image_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0666); | | 573 | image_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0666); |
576 | if (image_fd == -1) { | | 574 | if (image_fd == -1) { |
577 | perror("open image"); | | 575 | perror("open image"); |
578 | return EXIT_FAILURE; | | 576 | return EXIT_FAILURE; |
579 | } | | 577 | } |
580 | | | 578 | |
581 | printf(" image type: %s\n", get_image_format_name(image_format)); | | 579 | printf(" image type: %s\n", get_image_format_name(image_format)); |
582 | | | 580 | |
583 | switch (image_format) { | | 581 | switch (image_format) { |
584 | case FMT_UIMG: | | 582 | case FMT_UIMG: |
585 | if (generate_header_uimg(&hdr_uimg, kernel_fd) != 0) | | 583 | if (generate_header_uimg(&hdr_uimg, kernel_fd) != 0) |
586 | return EXIT_FAILURE; | | 584 | return EXIT_FAILURE; |
587 | | | 585 | |
588 | if (write_image(&hdr_uimg, sizeof(hdr_uimg), | | 586 | if (write_image(&hdr_uimg, sizeof(hdr_uimg), |
589 | kernel_fd, image_fd) != 0) | | 587 | kernel_fd, image_fd) != 0) |
590 | return EXIT_FAILURE; | | 588 | return EXIT_FAILURE; |
591 | | | 589 | |
592 | break; | | 590 | break; |
593 | case FMT_ARM64: | | 591 | case FMT_ARM64: |
594 | if (generate_header_arm64(&hdr_arm64, kernel_fd) != 0) | | 592 | if (generate_header_arm64(&hdr_arm64, kernel_fd) != 0) |
595 | return EXIT_FAILURE; | | 593 | return EXIT_FAILURE; |
596 | | | 594 | |
597 | if (write_image(&hdr_arm64, sizeof(hdr_arm64), | | 595 | if (write_image(&hdr_arm64, sizeof(hdr_arm64), |
598 | kernel_fd, image_fd) != 0) | | 596 | kernel_fd, image_fd) != 0) |
599 | return EXIT_FAILURE; | | 597 | return EXIT_FAILURE; |
600 | | | 598 | |
601 | break; | | 599 | break; |
602 | default: | | 600 | default: |
603 | break; | | 601 | break; |
604 | } | | 602 | } |
605 | | | 603 | |
606 | close(image_fd); | | 604 | close(image_fd); |
607 | close(kernel_fd); | | 605 | close(kernel_fd); |
608 | | | 606 | |
609 | return EXIT_SUCCESS; | | 607 | return EXIT_SUCCESS; |
610 | } | | 608 | } |