1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2018 Linaro Limited
4 * Author: AKASHI Takahiro
15 #include <linux/types.h>
19 #include <sys/types.h>
30 #define aligned_u64 __aligned_u64
32 #define SIGNATURE_NODENAME "signature"
33 #define OVERLAY_NODENAME "__overlay__"
36 #define __packed __attribute__((packed))
42 static const char *tool_name = "mkeficapsule";
44 efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
45 efi_guid_t efi_guid_image_type_uboot_fit =
46 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
47 efi_guid_t efi_guid_image_type_uboot_raw =
48 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
50 static 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'},
55 {"dtb", required_argument, NULL, 'D'},
56 {"public key", required_argument, NULL, 'K'},
57 {"overlay", no_argument, NULL, 'O'},
58 {"help", no_argument, NULL, 'h'},
62 static void print_usage(void)
64 printf("Usage: %s [options] <output file>\n"
67 "\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"
71 "\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"
74 "\t-h, --help print a help message\n",
78 static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,
88 * The signature would be stored in the
89 * first fragment node of the overlay
91 frag_node = fdt_first_subnode(dptr, 0);
92 if (frag_node == -FDT_ERR_NOTFOUND) {
94 "Couldn't find the fragment node: %s\n",
95 fdt_strerror(frag_node));
99 ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);
100 if (ov_node == -FDT_ERR_NOTFOUND) {
102 "Couldn't find the __overlay__ node: %s\n",
103 fdt_strerror(ov_node));
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);
115 if (ret != -FDT_ERR_NOSPACE) {
117 "Couldn't create signature node: %s\n",
118 fdt_strerror(parent));
125 /* Write the key to the FDT node */
126 ret = fdt_setprop(dptr, parent, "capsule-key",
131 ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
136 static int add_public_key(const char *pkey_file, const char *dtb_file,
148 /* Find out the size of the public key */
149 srcfd = open(pkey_file, O_RDONLY);
151 fprintf(stderr, "%s: Can't open %s: %s\n",
152 __func__, pkey_file, strerror(errno));
157 ret = fstat(srcfd, &pub_key);
159 fprintf(stderr, "%s: Can't stat %s: %s\n",
160 __func__, pkey_file, strerror(errno));
165 src_size = pub_key.st_size;
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));
176 /* Open the dest FDT */
177 destfd = open(dtb_file, O_RDWR);
179 fprintf(stderr, "%s: Can't open %s: %s\n",
180 __func__, dtb_file, strerror(errno));
185 ret = fstat(destfd, &dtb);
187 fprintf(stderr, "%s: Can't stat %s: %s\n",
188 __func__, dtb_file, strerror(errno));
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));
201 /* mmap the dtb file */
202 dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
204 if (dptr == MAP_FAILED) {
205 fprintf(stderr, "%s: Failed to mmap %s:%s\n",
206 __func__, dtb_file, strerror(errno));
211 if (fdt_check_header(dptr)) {
212 fprintf(stderr, "%s: Invalid FDT header\n", __func__);
217 ret = fdt_open_into(dptr, dptr, dtb.st_size);
219 fprintf(stderr, "%s: Cannot expand FDT: %s\n",
220 __func__, fdt_strerror(ret));
225 /* Copy the esl file to the expanded FDT */
226 ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
228 fprintf(stderr, "%s: Unable to add public key to the FDT\n",
238 munmap(sptr, src_size);
241 munmap(dptr, dtb.st_size);
252 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
253 unsigned long index, unsigned long instance)
255 struct efi_capsule_header header;
256 struct efi_firmware_management_capsule_header capsule;
257 struct efi_firmware_management_capsule_image_header image;
259 struct stat bin_stat;
265 printf("For output: %s\n", path);
266 printf("\tbin: %s\n\ttype: %pUl\n", bin, guid);
267 printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
272 printf("cannot open %s\n", bin);
275 if (stat(bin, &bin_stat) < 0) {
276 printf("cannot determine the size of %s\n", bin);
279 data = malloc(bin_stat.st_size);
281 printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size);
284 f = fopen(path, "w");
286 printf("cannot open %s\n", path);
289 header.capsule_guid = efi_guid_fm_capsule;
290 header.header_size = sizeof(header);
291 /* TODO: The current implementation ignores flags */
292 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
293 header.capsule_image_size = sizeof(header)
294 + sizeof(capsule) + sizeof(u64)
298 size = fwrite(&header, 1, sizeof(header), f);
299 if (size < sizeof(header)) {
300 printf("write failed (%zx)\n", size);
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))) {
309 printf("write failed (%zx)\n", size);
312 offset = sizeof(capsule) + sizeof(u64);
313 size = fwrite(&offset, 1, sizeof(offset), f);
314 if (size < sizeof(offset)) {
315 printf("write failed (%zx)\n", size);
319 image.version = 0x00000003;
320 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
321 image.update_image_index = index;
322 image.reserved[0] = 0;
323 image.reserved[1] = 0;
324 image.reserved[2] = 0;
325 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;
330 size = fwrite(&image, 1, sizeof(image), f);
331 if (size < sizeof(image)) {
332 printf("write failed (%zx)\n", size);
335 size = fread(data, 1, bin_stat.st_size, g);
336 if (size < bin_stat.st_size) {
337 printf("read failed (%zx)\n", size);
340 size = fwrite(data, 1, bin_stat.st_size, f);
341 if (size < bin_stat.st_size) {
342 printf("write failed (%zx)\n", size);
364 * $ mkeficapsule -f <firmware binary> <output file>
366 int main(int argc, char **argv)
372 unsigned long index, instance;
375 bool overlay = false;
384 c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
391 printf("Image already specified\n");
395 guid = &efi_guid_image_type_uboot_fit;
399 printf("Image already specified\n");
403 guid = &efi_guid_image_type_uboot_raw;
406 index = strtoul(optarg, NULL, 0);
409 instance = strtoul(optarg, NULL, 0);
413 printf("Public Key already specified\n");
420 printf("DTB file already specified\n");
434 /* need a fit image file or raw image file */
435 if (!file && !pkey_file && !dtb_file) {
440 if (pkey_file && dtb_file) {
441 ret = add_public_key(pkey_file, dtb_file, overlay);
443 printf("Adding public key to the dtb failed\n");
450 if (create_fwbin(argv[optind], file, guid, index, instance)
452 printf("Creating firmware capsule failed\n");