blob: 270943fc90aee0f578ba68265814c388ad01ec18 [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
Sughosh Ganu322c8132020-12-30 19:26:59 +05307#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>
Sughosh Ganu322c8132020-12-30 19:26:59 +053014#include <unistd.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090015#include <linux/types.h>
Sughosh Ganu322c8132020-12-30 19:26:59 +053016
17#include <sys/mman.h>
AKASHI Takahirofab430b2020-11-30 18:12:15 +090018#include <sys/stat.h>
19#include <sys/types.h>
20
Sughosh Ganu322c8132020-12-30 19:26:59 +053021#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
Sughosh Ganu322c8132020-12-30 19:26:59 +053032#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'},
Sughosh Ganu322c8132020-12-30 19:26:59 +053055 {"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
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",
AKASHI Takahirofab430b2020-11-30 18:12:15 +090075 tool_name);
76}
77
Sughosh Ganu322c8132020-12-30 19:26:59 +053078static 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
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900243static 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);
AKASHI Takahiro450596f2020-11-30 18:12:16 +0900282 /* TODO: The current implementation ignores flags */
283 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900284 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;
313 image.update_image_size = bin_stat.st_size;
314 image.update_vendor_code_size = 0; /* none */
315 image.update_hardware_instance = instance;
316 image.image_capsule_support = 0;
317
318 size = fwrite(&image, 1, sizeof(image), f);
319 if (size < sizeof(image)) {
320 printf("write failed (%lx)\n", size);
321 goto err_3;
322 }
323 size = fread(data, 1, bin_stat.st_size, g);
324 if (size < bin_stat.st_size) {
325 printf("read failed (%lx)\n", size);
326 goto err_3;
327 }
328 size = fwrite(data, 1, bin_stat.st_size, f);
329 if (size < bin_stat.st_size) {
330 printf("write failed (%lx)\n", size);
331 goto err_3;
332 }
333
334 fclose(f);
335 fclose(g);
336 free(data);
337
338 return 0;
339
340err_3:
341 fclose(f);
342err_2:
343 free(data);
344err_1:
345 fclose(g);
346
347 return -1;
348}
349
350/*
351 * Usage:
352 * $ mkeficapsule -f <firmware binary> <output file>
353 */
354int main(int argc, char **argv)
355{
356 char *file;
Sughosh Ganu322c8132020-12-30 19:26:59 +0530357 char *pkey_file;
358 char *dtb_file;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900359 efi_guid_t *guid;
360 unsigned long index, instance;
361 int c, idx;
Sughosh Ganu322c8132020-12-30 19:26:59 +0530362 int ret;
363 bool overlay = false;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900364
365 file = NULL;
Sughosh Ganu322c8132020-12-30 19:26:59 +0530366 pkey_file = NULL;
367 dtb_file = NULL;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900368 guid = NULL;
369 index = 0;
370 instance = 0;
371 for (;;) {
Sughosh Ganu322c8132020-12-30 19:26:59 +0530372 c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900373 if (c == -1)
374 break;
375
376 switch (c) {
377 case 'f':
378 if (file) {
379 printf("Image already specified\n");
380 return -1;
381 }
382 file = optarg;
383 guid = &efi_guid_image_type_uboot_fit;
384 break;
385 case 'r':
386 if (file) {
387 printf("Image already specified\n");
388 return -1;
389 }
390 file = optarg;
391 guid = &efi_guid_image_type_uboot_raw;
392 break;
393 case 'i':
394 index = strtoul(optarg, NULL, 0);
395 break;
396 case 'I':
397 instance = strtoul(optarg, NULL, 0);
398 break;
Sughosh Ganu322c8132020-12-30 19:26:59 +0530399 case 'K':
400 if (pkey_file) {
401 printf("Public Key already specified\n");
402 return -1;
403 }
404 pkey_file = optarg;
405 break;
406 case 'D':
407 if (dtb_file) {
408 printf("DTB file already specified\n");
409 return -1;
410 }
411 dtb_file = optarg;
412 break;
413 case 'O':
414 overlay = true;
415 break;
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900416 case 'h':
417 print_usage();
418 return 0;
419 }
420 }
421
Sughosh Ganu322c8132020-12-30 19:26:59 +0530422 /* need a fit image file or raw image file */
423 if (!file && !pkey_file && !dtb_file) {
424 printf("%s: %d\n", __func__, __LINE__);
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900425 print_usage();
426 return -1;
427 }
428
Sughosh Ganu322c8132020-12-30 19:26:59 +0530429 if (pkey_file && dtb_file) {
430 ret = add_public_key(pkey_file, dtb_file, overlay);
431 if (ret == -1) {
432 printf("Adding public key to the dtb failed\n");
433 return -1;
434 } else {
435 return 0;
436 }
AKASHI Takahirofab430b2020-11-30 18:12:15 +0900437 }
438
439 if (create_fwbin(argv[optind], file, guid, index, instance)
440 < 0) {
441 printf("Creating firmware capsule failed\n");
442 return -1;
443 }
444
445 return 0;
446}