blob: de0a628988863fc05a56b0c6e110a7ef0be6aa24 [file] [log] [blame]
AKASHI Takahirofab430b2020-11-30 18:12:15 +09001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018 Linaro Limited
4 * Author: AKASHI Takahiro
5 */
6
Simon Glassd428e812021-08-02 08:44:30 -06007#include <errno.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +09008#include <getopt.h>
9#include <malloc.h>
10#include <stdbool.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
Simon Glassd428e812021-08-02 08:44:30 -060014#include <unistd.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090015#include <linux/types.h>
Sughosh Ganu322c8132020-12-30 19:26:59 +053016
Simon Glassd428e812021-08-02 08:44:30 -060017#include <sys/mman.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090018#include <sys/stat.h>
19#include <sys/types.h>
20
Simon Glassd428e812021-08-02 08:44:30 -060021#include "fdt_host.h"
22
AKASHI Takahirofab430b2020-11-30 18:12:15 +090023typedef __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
Simon Glassd428e812021-08-02 08:44:30 -060032#define SIGNATURE_NODENAME "signature"
33#define OVERLAY_NODENAME "__overlay__"
34
AKASHI Takahirofab430b2020-11-30 18:12:15 +090035#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'},
Simon Glassd428e812021-08-02 08:44:30 -060055 {"dtb", required_argument, NULL, 'D'},
56 {"public key", required_argument, NULL, 'K'},
57 {"overlay", no_argument, NULL, 'O'},
AKASHI Takahirofab430b2020-11-30 18:12:15 +090058 {"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"
Sughosh Ganu322c8132020-12-30 19:26:59 +053066
Heinrich Schuchardt21640632021-04-08 22:02:29 +020067 "\t-f, --fit <fit image> new FIT image file\n"
68 "\t-r, --raw <raw image> new raw image file\n"
69 "\t-i, --index <index> update image index\n"
70 "\t-I, --instance <instance> update hardware instance\n"
Simon Glassd428e812021-08-02 08:44:30 -060071 "\t-K, --public-key <key file> public key esl file\n"
72 "\t-D, --dtb <dtb file> dtb file\n"
73 "\t-O, --overlay the dtb file is an overlay\n"
Heinrich Schuchardt21640632021-04-08 22:02:29 +020074 "\t-h, --help print a help message\n",
AKASHI Takahirofab430b2020-11-30 18:12:15 +090075 tool_name);
76}
77
Simon Glassd428e812021-08-02 08:44:30 -060078static 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 = -1;
141 int destfd = -1;
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 ret = -1;
154 goto err;
155 }
156
157 ret = fstat(srcfd, &pub_key);
158 if (ret == -1) {
159 fprintf(stderr, "%s: Can't stat %s: %s\n",
160 __func__, pkey_file, strerror(errno));
161 ret = -1;
162 goto err;
163 }
164
165 src_size = pub_key.st_size;
166
167 /* mmap the public key esl file */
168 sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);
169 if (sptr == MAP_FAILED) {
170 fprintf(stderr, "%s: Failed to mmap %s:%s\n",
171 __func__, pkey_file, strerror(errno));
172 ret = -1;
173 goto err;
174 }
175
176 /* Open the dest FDT */
177 destfd = open(dtb_file, O_RDWR);
178 if (destfd == -1) {
179 fprintf(stderr, "%s: Can't open %s: %s\n",
180 __func__, dtb_file, strerror(errno));
181 ret = -1;
182 goto err;
183 }
184
185 ret = fstat(destfd, &dtb);
186 if (ret == -1) {
187 fprintf(stderr, "%s: Can't stat %s: %s\n",
188 __func__, dtb_file, strerror(errno));
189 goto err;
190 }
191
192 dtb.st_size += src_size + 0x30;
193 if (ftruncate(destfd, dtb.st_size)) {
194 fprintf(stderr, "%s: Can't expand %s: %s\n",
195 __func__, dtb_file, strerror(errno));
196 ret = -1;
197 goto err;
198 }
199
200 errno = 0;
201 /* mmap the dtb file */
202 dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
203 destfd, 0);
204 if (dptr == MAP_FAILED) {
205 fprintf(stderr, "%s: Failed to mmap %s:%s\n",
206 __func__, dtb_file, strerror(errno));
207 ret = -1;
208 goto err;
209 }
210
211 if (fdt_check_header(dptr)) {
212 fprintf(stderr, "%s: Invalid FDT header\n", __func__);
213 ret = -1;
214 goto err;
215 }
216
217 ret = fdt_open_into(dptr, dptr, dtb.st_size);
218 if (ret) {
219 fprintf(stderr, "%s: Cannot expand FDT: %s\n",
220 __func__, fdt_strerror(ret));
221 ret = -1;
222 goto err;
223 }
224
225 /* Copy the esl file to the expanded FDT */
226 ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
227 if (ret < 0) {
228 fprintf(stderr, "%s: Unable to add public key to the FDT\n",
229 __func__);
230 ret = -1;
231 goto err;
232 }
233
234 ret = 0;
235
236err:
237 if (sptr)
238 munmap(sptr, src_size);
239
240 if (dptr)
241 munmap(dptr, dtb.st_size);
242
243 if (srcfd != -1)
244 close(srcfd);
245
246 if (destfd != -1)
247 close(destfd);
248
249 return ret;
250}
251
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900252static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
253 unsigned long index, unsigned long instance)
254{
255 struct efi_capsule_header header;
256 struct efi_firmware_management_capsule_header capsule;
257 struct efi_firmware_management_capsule_image_header image;
258 FILE *f, *g;
259 struct stat bin_stat;
260 u8 *data;
261 size_t size;
262 u64 offset;
263
264#ifdef DEBUG
265 printf("For output: %s\n", path);
Klaus Heinrich Kiwi95cacc82021-02-20 17:40:45 -0300266 printf("\tbin: %s\n\ttype: %pUl\n", bin, guid);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900267 printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
268#endif
269
270 g = fopen(bin, "r");
271 if (!g) {
272 printf("cannot open %s\n", bin);
273 return -1;
274 }
275 if (stat(bin, &bin_stat) < 0) {
276 printf("cannot determine the size of %s\n", bin);
277 goto err_1;
278 }
279 data = malloc(bin_stat.st_size);
280 if (!data) {
Simon Glassad090042021-02-07 14:27:01 -0700281 printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900282 goto err_1;
283 }
284 f = fopen(path, "w");
285 if (!f) {
286 printf("cannot open %s\n", path);
287 goto err_2;
288 }
289 header.capsule_guid = efi_guid_fm_capsule;
290 header.header_size = sizeof(header);
AKASHI Takahiro450596f2020-11-30 18:12:16 +0900291 /* TODO: The current implementation ignores flags */
292 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900293 header.capsule_image_size = sizeof(header)
294 + sizeof(capsule) + sizeof(u64)
295 + sizeof(image)
296 + bin_stat.st_size;
297
298 size = fwrite(&header, 1, sizeof(header), f);
299 if (size < sizeof(header)) {
Simon Glassad090042021-02-07 14:27:01 -0700300 printf("write failed (%zx)\n", size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900301 goto err_3;
302 }
303
304 capsule.version = 0x00000001;
305 capsule.embedded_driver_count = 0;
306 capsule.payload_item_count = 1;
307 size = fwrite(&capsule, 1, sizeof(capsule), f);
308 if (size < (sizeof(capsule))) {
Simon Glassad090042021-02-07 14:27:01 -0700309 printf("write failed (%zx)\n", size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900310 goto err_3;
311 }
312 offset = sizeof(capsule) + sizeof(u64);
313 size = fwrite(&offset, 1, sizeof(offset), f);
314 if (size < sizeof(offset)) {
Simon Glassad090042021-02-07 14:27:01 -0700315 printf("write failed (%zx)\n", size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900316 goto err_3;
317 }
318
319 image.version = 0x00000003;
320 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
321 image.update_image_index = index;
AKASHI Takahirof7cd8b72021-01-22 10:43:49 +0900322 image.reserved[0] = 0;
323 image.reserved[1] = 0;
324 image.reserved[2] = 0;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900325 image.update_image_size = bin_stat.st_size;
326 image.update_vendor_code_size = 0; /* none */
327 image.update_hardware_instance = instance;
328 image.image_capsule_support = 0;
329
330 size = fwrite(&image, 1, sizeof(image), f);
331 if (size < sizeof(image)) {
Simon Glassad090042021-02-07 14:27:01 -0700332 printf("write failed (%zx)\n", size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900333 goto err_3;
334 }
335 size = fread(data, 1, bin_stat.st_size, g);
336 if (size < bin_stat.st_size) {
Simon Glassad090042021-02-07 14:27:01 -0700337 printf("read failed (%zx)\n", size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900338 goto err_3;
339 }
340 size = fwrite(data, 1, bin_stat.st_size, f);
341 if (size < bin_stat.st_size) {
Simon Glassad090042021-02-07 14:27:01 -0700342 printf("write failed (%zx)\n", size);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900343 goto err_3;
344 }
345
346 fclose(f);
347 fclose(g);
348 free(data);
349
350 return 0;
351
352err_3:
353 fclose(f);
354err_2:
355 free(data);
356err_1:
357 fclose(g);
358
359 return -1;
360}
361
362/*
363 * Usage:
364 * $ mkeficapsule -f <firmware binary> <output file>
365 */
366int main(int argc, char **argv)
367{
368 char *file;
Simon Glassd428e812021-08-02 08:44:30 -0600369 char *pkey_file;
370 char *dtb_file;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900371 efi_guid_t *guid;
372 unsigned long index, instance;
373 int c, idx;
Simon Glassd428e812021-08-02 08:44:30 -0600374 int ret;
375 bool overlay = false;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900376
377 file = NULL;
Simon Glassd428e812021-08-02 08:44:30 -0600378 pkey_file = NULL;
379 dtb_file = NULL;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900380 guid = NULL;
381 index = 0;
382 instance = 0;
383 for (;;) {
Simon Glassd428e812021-08-02 08:44:30 -0600384 c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900385 if (c == -1)
386 break;
387
388 switch (c) {
389 case 'f':
390 if (file) {
391 printf("Image already specified\n");
392 return -1;
393 }
394 file = optarg;
395 guid = &efi_guid_image_type_uboot_fit;
396 break;
397 case 'r':
398 if (file) {
399 printf("Image already specified\n");
400 return -1;
401 }
402 file = optarg;
403 guid = &efi_guid_image_type_uboot_raw;
404 break;
405 case 'i':
406 index = strtoul(optarg, NULL, 0);
407 break;
408 case 'I':
409 instance = strtoul(optarg, NULL, 0);
410 break;
Simon Glassd428e812021-08-02 08:44:30 -0600411 case 'K':
412 if (pkey_file) {
413 printf("Public Key already specified\n");
414 return -1;
415 }
416 pkey_file = optarg;
417 break;
418 case 'D':
419 if (dtb_file) {
420 printf("DTB file already specified\n");
421 return -1;
422 }
423 dtb_file = optarg;
424 break;
425 case 'O':
426 overlay = true;
427 break;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900428 case 'h':
429 print_usage();
430 return 0;
431 }
432 }
433
Simon Glassd428e812021-08-02 08:44:30 -0600434 /* need a fit image file or raw image file */
435 if (!file && !pkey_file && !dtb_file) {
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900436 print_usage();
Sughosh Ganud33f3182021-01-22 20:34:56 +0530437 exit(EXIT_FAILURE);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900438 }
439
Simon Glassd428e812021-08-02 08:44:30 -0600440 if (pkey_file && dtb_file) {
441 ret = add_public_key(pkey_file, dtb_file, overlay);
442 if (ret == -1) {
443 printf("Adding public key to the dtb failed\n");
444 exit(EXIT_FAILURE);
445 } else {
446 exit(EXIT_SUCCESS);
447 }
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900448 }
449
450 if (create_fwbin(argv[optind], file, guid, index, instance)
451 < 0) {
452 printf("Creating firmware capsule failed\n");
Sughosh Ganud33f3182021-01-22 20:34:56 +0530453 exit(EXIT_FAILURE);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900454 }
455
Sughosh Ganud33f3182021-01-22 20:34:56 +0530456 exit(EXIT_SUCCESS);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900457}