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--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",
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));
156 ret = fstat(srcfd, &pub_key);
158 fprintf(stderr, "%s: Can't stat %s: %s\n",
159 __func__, pkey_file, strerror(errno));
163 src_size = pub_key.st_size;
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));
173 /* Open the dest FDT */
174 destfd = open(dtb_file, O_RDWR);
176 fprintf(stderr, "%s: Can't open %s: %s\n",
177 __func__, dtb_file, strerror(errno));
181 ret = fstat(destfd, &dtb);
183 fprintf(stderr, "%s: Can't stat %s: %s\n",
184 __func__, dtb_file, strerror(errno));
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));
196 /* mmap the dtb file */
197 dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
199 if ((dptr == MAP_FAILED) || (errno != 0)) {
200 fprintf(stderr, "%s: Failed to mmap %s:%s\n",
201 __func__, dtb_file, strerror(errno));
205 if (fdt_check_header(dptr)) {
206 fprintf(stderr, "%s: Invalid FDT header\n", __func__);
210 ret = fdt_open_into(dptr, dptr, dtb.st_size);
212 fprintf(stderr, "%s: Cannot expand FDT: %s\n",
213 __func__, fdt_strerror(ret));
217 /* Copy the esl file to the expanded FDT */
218 ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
220 fprintf(stderr, "%s: Unable to add public key to the FDT\n",
229 munmap(sptr, src_size);
232 munmap(dptr, dtb.st_size);
243 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
244 unsigned long index, unsigned long instance)
246 struct efi_capsule_header header;
247 struct efi_firmware_management_capsule_header capsule;
248 struct efi_firmware_management_capsule_image_header image;
250 struct stat bin_stat;
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);
263 printf("cannot open %s\n", bin);
266 if (stat(bin, &bin_stat) < 0) {
267 printf("cannot determine the size of %s\n", bin);
270 data = malloc(bin_stat.st_size);
272 printf("cannot allocate memory: %lx\n", bin_stat.st_size);
275 f = fopen(path, "w");
277 printf("cannot open %s\n", path);
280 header.capsule_guid = efi_guid_fm_capsule;
281 header.header_size = sizeof(header);
282 /* TODO: The current implementation ignores flags */
283 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
284 header.capsule_image_size = sizeof(header)
285 + sizeof(capsule) + sizeof(u64)
289 size = fwrite(&header, 1, sizeof(header), f);
290 if (size < sizeof(header)) {
291 printf("write failed (%lx)\n", size);
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);
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);
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;
318 size = fwrite(&image, 1, sizeof(image), f);
319 if (size < sizeof(image)) {
320 printf("write failed (%lx)\n", size);
323 size = fread(data, 1, bin_stat.st_size, g);
324 if (size < bin_stat.st_size) {
325 printf("read failed (%lx)\n", size);
328 size = fwrite(data, 1, bin_stat.st_size, f);
329 if (size < bin_stat.st_size) {
330 printf("write failed (%lx)\n", size);
352 * $ mkeficapsule -f <firmware binary> <output file>
354 int main(int argc, char **argv)
360 unsigned long index, instance;
363 bool overlay = false;
372 c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
379 printf("Image already specified\n");
383 guid = &efi_guid_image_type_uboot_fit;
387 printf("Image already specified\n");
391 guid = &efi_guid_image_type_uboot_raw;
394 index = strtoul(optarg, NULL, 0);
397 instance = strtoul(optarg, NULL, 0);
401 printf("Public Key already specified\n");
408 printf("DTB file already specified\n");
422 /* need a fit image file or raw image file */
423 if (!file && !pkey_file && !dtb_file) {
424 printf("%s: %d\n", __func__, __LINE__);
429 if (pkey_file && dtb_file) {
430 ret = add_public_key(pkey_file, dtb_file, overlay);
432 printf("Adding public key to the dtb failed\n");
439 if (create_fwbin(argv[optind], file, guid, index, instance)
441 printf("Creating firmware capsule failed\n");