]> Git Repo - J-u-boot.git/blame - tools/mkeficapsule.c
tools: mkeficapsule: fill reserved members of structure
[J-u-boot.git] / tools / mkeficapsule.c
CommitLineData
fab430be
AT
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018 Linaro Limited
4 * Author: AKASHI Takahiro
5 */
6
322c813f 7#include <errno.h>
fab430be
AT
8#include <getopt.h>
9#include <malloc.h>
10#include <stdbool.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
322c813f 14#include <unistd.h>
fab430be 15#include <linux/types.h>
322c813f
SG
16
17#include <sys/mman.h>
fab430be
AT
18#include <sys/stat.h>
19#include <sys/types.h>
20
322c813f
SG
21#include "fdt_host.h"
22
fab430be
AT
23typedef __u8 u8;
24typedef __u16 u16;
25typedef __u32 u32;
26typedef __u64 u64;
27typedef __s16 s16;
28typedef __s32 s32;
29
30#define aligned_u64 __aligned_u64
31
322c813f
SG
32#define SIGNATURE_NODENAME "signature"
33#define OVERLAY_NODENAME "__overlay__"
34
fab430be
AT
35#ifndef __packed
36#define __packed __attribute__((packed))
37#endif
38
39#include <efi.h>
40#include <efi_api.h>
41
42static const char *tool_name = "mkeficapsule";
43
44efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
45efi_guid_t efi_guid_image_type_uboot_fit =
46 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
47efi_guid_t efi_guid_image_type_uboot_raw =
48 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
49
50static struct option options[] = {
51 {"fit", required_argument, NULL, 'f'},
52 {"raw", required_argument, NULL, 'r'},
53 {"index", required_argument, NULL, 'i'},
54 {"instance", required_argument, NULL, 'I'},
322c813f
SG
55 {"dtb", required_argument, NULL, 'D'},
56 {"public key", required_argument, NULL, 'K'},
57 {"overlay", no_argument, NULL, 'O'},
fab430be
AT
58 {"help", no_argument, NULL, 'h'},
59 {NULL, 0, NULL, 0},
60};
61
62static void print_usage(void)
63{
64 printf("Usage: %s [options] <output file>\n"
65 "Options:\n"
322c813f
SG
66
67 "\t--fit <fit image> new FIT image file\n"
68 "\t--raw <raw image> new raw image file\n"
69 "\t--index <index> update image index\n"
70 "\t--instance <instance> update hardware instance\n"
71 "\t--public-key <key file> public key esl file\n"
72 "\t--dtb <dtb file> dtb file\n"
73 "\t--overlay the dtb file is an overlay\n"
74 "\t--help print a help message\n",
fab430be
AT
75 tool_name);
76}
77
322c813f
SG
78static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,
79 bool overlay)
80{
81 int parent;
82 int ov_node;
83 int frag_node;
84 int ret = 0;
85
86 if (overlay) {
87 /*
88 * The signature would be stored in the
89 * first fragment node of the overlay
90 */
91 frag_node = fdt_first_subnode(dptr, 0);
92 if (frag_node == -FDT_ERR_NOTFOUND) {
93 fprintf(stderr,
94 "Couldn't find the fragment node: %s\n",
95 fdt_strerror(frag_node));
96 goto done;
97 }
98
99 ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);
100 if (ov_node == -FDT_ERR_NOTFOUND) {
101 fprintf(stderr,
102 "Couldn't find the __overlay__ node: %s\n",
103 fdt_strerror(ov_node));
104 goto done;
105 }
106 } else {
107 ov_node = 0;
108 }
109
110 parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME);
111 if (parent == -FDT_ERR_NOTFOUND) {
112 parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME);
113 if (parent < 0) {
114 ret = parent;
115 if (ret != -FDT_ERR_NOSPACE) {
116 fprintf(stderr,
117 "Couldn't create signature node: %s\n",
118 fdt_strerror(parent));
119 }
120 }
121 }
122 if (ret)
123 goto done;
124
125 /* Write the key to the FDT node */
126 ret = fdt_setprop(dptr, parent, "capsule-key",
127 sptr, key_size);
128
129done:
130 if (ret)
131 ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
132
133 return ret;
134}
135
136static int add_public_key(const char *pkey_file, const char *dtb_file,
137 bool overlay)
138{
139 int ret;
140 int srcfd = 0;
141 int destfd = 0;
142 void *sptr = NULL;
143 void *dptr = NULL;
144 off_t src_size;
145 struct stat pub_key;
146 struct stat dtb;
147
148 /* Find out the size of the public key */
149 srcfd = open(pkey_file, O_RDONLY);
150 if (srcfd == -1) {
151 fprintf(stderr, "%s: Can't open %s: %s\n",
152 __func__, pkey_file, strerror(errno));
153 goto err;
154 }
155
156 ret = fstat(srcfd, &pub_key);
157 if (ret == -1) {
158 fprintf(stderr, "%s: Can't stat %s: %s\n",
159 __func__, pkey_file, strerror(errno));
160 goto err;
161 }
162
163 src_size = pub_key.st_size;
164
165 /* mmap the public key esl file */
166 sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);
167 if ((sptr == MAP_FAILED) || (errno != 0)) {
168 fprintf(stderr, "%s: Failed to mmap %s:%s\n",
169 __func__, pkey_file, strerror(errno));
170 goto err;
171 }
172
173 /* Open the dest FDT */
174 destfd = open(dtb_file, O_RDWR);
175 if (destfd == -1) {
176 fprintf(stderr, "%s: Can't open %s: %s\n",
177 __func__, dtb_file, strerror(errno));
178 goto err;
179 }
180
181 ret = fstat(destfd, &dtb);
182 if (ret == -1) {
183 fprintf(stderr, "%s: Can't stat %s: %s\n",
184 __func__, dtb_file, strerror(errno));
185 goto err;
186 }
187
188 dtb.st_size += src_size + 0x30;
189 if (ftruncate(destfd, dtb.st_size)) {
190 fprintf(stderr, "%s: Can't expand %s: %s\n",
191 __func__, dtb_file, strerror(errno));
192 goto err;;
193 }
194
195 errno = 0;
196 /* mmap the dtb file */
197 dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
198 destfd, 0);
199 if ((dptr == MAP_FAILED) || (errno != 0)) {
200 fprintf(stderr, "%s: Failed to mmap %s:%s\n",
201 __func__, dtb_file, strerror(errno));
202 goto err;
203 }
204
205 if (fdt_check_header(dptr)) {
206 fprintf(stderr, "%s: Invalid FDT header\n", __func__);
207 goto err;
208 }
209
210 ret = fdt_open_into(dptr, dptr, dtb.st_size);
211 if (ret) {
212 fprintf(stderr, "%s: Cannot expand FDT: %s\n",
213 __func__, fdt_strerror(ret));
214 goto err;
215 }
216
217 /* Copy the esl file to the expanded FDT */
218 ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
219 if (ret < 0) {
220 fprintf(stderr, "%s: Unable to add public key to the FDT\n",
221 __func__);
222 goto err;
223 }
224
225 return 0;
226
227err:
228 if (sptr)
229 munmap(sptr, src_size);
230
231 if (dptr)
232 munmap(dptr, dtb.st_size);
233
234 if (srcfd >= 0)
235 close(srcfd);
236
237 if (destfd >= 0)
238 close(destfd);
239
240 return -1;
241}
242
fab430be
AT
243static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
244 unsigned long index, unsigned long instance)
245{
246 struct efi_capsule_header header;
247 struct efi_firmware_management_capsule_header capsule;
248 struct efi_firmware_management_capsule_image_header image;
249 FILE *f, *g;
250 struct stat bin_stat;
251 u8 *data;
252 size_t size;
253 u64 offset;
254
255#ifdef DEBUG
256 printf("For output: %s\n", path);
257 printf("\tbin: %s\n\ttype: %pUl\n" bin, guid);
258 printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
259#endif
260
261 g = fopen(bin, "r");
262 if (!g) {
263 printf("cannot open %s\n", bin);
264 return -1;
265 }
266 if (stat(bin, &bin_stat) < 0) {
267 printf("cannot determine the size of %s\n", bin);
268 goto err_1;
269 }
270 data = malloc(bin_stat.st_size);
271 if (!data) {
272 printf("cannot allocate memory: %lx\n", bin_stat.st_size);
273 goto err_1;
274 }
275 f = fopen(path, "w");
276 if (!f) {
277 printf("cannot open %s\n", path);
278 goto err_2;
279 }
280 header.capsule_guid = efi_guid_fm_capsule;
281 header.header_size = sizeof(header);
450596f2
AT
282 /* TODO: The current implementation ignores flags */
283 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
fab430be
AT
284 header.capsule_image_size = sizeof(header)
285 + sizeof(capsule) + sizeof(u64)
286 + sizeof(image)
287 + bin_stat.st_size;
288
289 size = fwrite(&header, 1, sizeof(header), f);
290 if (size < sizeof(header)) {
291 printf("write failed (%lx)\n", size);
292 goto err_3;
293 }
294
295 capsule.version = 0x00000001;
296 capsule.embedded_driver_count = 0;
297 capsule.payload_item_count = 1;
298 size = fwrite(&capsule, 1, sizeof(capsule), f);
299 if (size < (sizeof(capsule))) {
300 printf("write failed (%lx)\n", size);
301 goto err_3;
302 }
303 offset = sizeof(capsule) + sizeof(u64);
304 size = fwrite(&offset, 1, sizeof(offset), f);
305 if (size < sizeof(offset)) {
306 printf("write failed (%lx)\n", size);
307 goto err_3;
308 }
309
310 image.version = 0x00000003;
311 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
312 image.update_image_index = index;
f7cd8b7b
AT
313 image.reserved[0] = 0;
314 image.reserved[1] = 0;
315 image.reserved[2] = 0;
fab430be
AT
316 image.update_image_size = bin_stat.st_size;
317 image.update_vendor_code_size = 0; /* none */
318 image.update_hardware_instance = instance;
319 image.image_capsule_support = 0;
320
321 size = fwrite(&image, 1, sizeof(image), f);
322 if (size < sizeof(image)) {
323 printf("write failed (%lx)\n", size);
324 goto err_3;
325 }
326 size = fread(data, 1, bin_stat.st_size, g);
327 if (size < bin_stat.st_size) {
328 printf("read failed (%lx)\n", size);
329 goto err_3;
330 }
331 size = fwrite(data, 1, bin_stat.st_size, f);
332 if (size < bin_stat.st_size) {
333 printf("write failed (%lx)\n", size);
334 goto err_3;
335 }
336
337 fclose(f);
338 fclose(g);
339 free(data);
340
341 return 0;
342
343err_3:
344 fclose(f);
345err_2:
346 free(data);
347err_1:
348 fclose(g);
349
350 return -1;
351}
352
353/*
354 * Usage:
355 * $ mkeficapsule -f <firmware binary> <output file>
356 */
357int main(int argc, char **argv)
358{
359 char *file;
322c813f
SG
360 char *pkey_file;
361 char *dtb_file;
fab430be
AT
362 efi_guid_t *guid;
363 unsigned long index, instance;
364 int c, idx;
322c813f
SG
365 int ret;
366 bool overlay = false;
fab430be
AT
367
368 file = NULL;
322c813f
SG
369 pkey_file = NULL;
370 dtb_file = NULL;
fab430be
AT
371 guid = NULL;
372 index = 0;
373 instance = 0;
374 for (;;) {
322c813f 375 c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
fab430be
AT
376 if (c == -1)
377 break;
378
379 switch (c) {
380 case 'f':
381 if (file) {
382 printf("Image already specified\n");
383 return -1;
384 }
385 file = optarg;
386 guid = &efi_guid_image_type_uboot_fit;
387 break;
388 case 'r':
389 if (file) {
390 printf("Image already specified\n");
391 return -1;
392 }
393 file = optarg;
394 guid = &efi_guid_image_type_uboot_raw;
395 break;
396 case 'i':
397 index = strtoul(optarg, NULL, 0);
398 break;
399 case 'I':
400 instance = strtoul(optarg, NULL, 0);
401 break;
322c813f
SG
402 case 'K':
403 if (pkey_file) {
404 printf("Public Key already specified\n");
405 return -1;
406 }
407 pkey_file = optarg;
408 break;
409 case 'D':
410 if (dtb_file) {
411 printf("DTB file already specified\n");
412 return -1;
413 }
414 dtb_file = optarg;
415 break;
416 case 'O':
417 overlay = true;
418 break;
fab430be
AT
419 case 'h':
420 print_usage();
421 return 0;
422 }
423 }
424
322c813f
SG
425 /* need a fit image file or raw image file */
426 if (!file && !pkey_file && !dtb_file) {
427 printf("%s: %d\n", __func__, __LINE__);
fab430be
AT
428 print_usage();
429 return -1;
430 }
431
322c813f
SG
432 if (pkey_file && dtb_file) {
433 ret = add_public_key(pkey_file, dtb_file, overlay);
434 if (ret == -1) {
435 printf("Adding public key to the dtb failed\n");
436 return -1;
437 } else {
438 return 0;
439 }
fab430be
AT
440 }
441
442 if (create_fwbin(argv[optind], file, guid, index, instance)
443 < 0) {
444 printf("Creating firmware capsule failed\n");
445 return -1;
446 }
447
448 return 0;
449}
This page took 0.069668 seconds and 4 git commands to generate.