blob: b22b61a9a5e1030fdd72c3a99690c1de5a4e3bd9 [file] [log] [blame]
AKASHI Takahiro19122aa2020-11-30 18:12:15 +09001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018 Linaro Limited
4 * Author: AKASHI Takahiro
5 */
6
7#include <getopt.h>
8#include <malloc.h>
9#include <stdbool.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <linux/types.h>
Sughosh Ganu079fcf22020-12-30 19:26:59 +053014
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090015#include <sys/stat.h>
16#include <sys/types.h>
17
18typedef __u8 u8;
19typedef __u16 u16;
20typedef __u32 u32;
21typedef __u64 u64;
22typedef __s16 s16;
23typedef __s32 s32;
24
25#define aligned_u64 __aligned_u64
26
27#ifndef __packed
28#define __packed __attribute__((packed))
29#endif
30
31#include <efi.h>
32#include <efi_api.h>
33
34static const char *tool_name = "mkeficapsule";
35
36efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
37efi_guid_t efi_guid_image_type_uboot_fit =
38 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
39efi_guid_t efi_guid_image_type_uboot_raw =
40 EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
41
42static struct option options[] = {
43 {"fit", required_argument, NULL, 'f'},
44 {"raw", required_argument, NULL, 'r'},
45 {"index", required_argument, NULL, 'i'},
46 {"instance", required_argument, NULL, 'I'},
47 {"help", no_argument, NULL, 'h'},
48 {NULL, 0, NULL, 0},
49};
50
51static void print_usage(void)
52{
53 printf("Usage: %s [options] <output file>\n"
54 "Options:\n"
Sughosh Ganu079fcf22020-12-30 19:26:59 +053055
Heinrich Schuchardt455219f2021-04-08 22:02:29 +020056 "\t-f, --fit <fit image> new FIT image file\n"
57 "\t-r, --raw <raw image> new raw image file\n"
58 "\t-i, --index <index> update image index\n"
59 "\t-I, --instance <instance> update hardware instance\n"
Heinrich Schuchardt455219f2021-04-08 22:02:29 +020060 "\t-h, --help print a help message\n",
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090061 tool_name);
62}
63
64static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
65 unsigned long index, unsigned long instance)
66{
67 struct efi_capsule_header header;
68 struct efi_firmware_management_capsule_header capsule;
69 struct efi_firmware_management_capsule_image_header image;
70 FILE *f, *g;
71 struct stat bin_stat;
72 u8 *data;
73 size_t size;
74 u64 offset;
75
76#ifdef DEBUG
77 printf("For output: %s\n", path);
Klaus Heinrich Kiwi2748fb62021-02-20 17:40:45 -030078 printf("\tbin: %s\n\ttype: %pUl\n", bin, guid);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090079 printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
80#endif
81
82 g = fopen(bin, "r");
83 if (!g) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +090084 fprintf(stderr, "cannot open %s\n", bin);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090085 return -1;
86 }
87 if (stat(bin, &bin_stat) < 0) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +090088 fprintf(stderr, "cannot determine the size of %s\n", bin);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090089 goto err_1;
90 }
91 data = malloc(bin_stat.st_size);
92 if (!data) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +090093 fprintf(stderr, "cannot allocate memory: %zx\n",
94 (size_t)bin_stat.st_size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +090095 goto err_1;
96 }
97 f = fopen(path, "w");
98 if (!f) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +090099 fprintf(stderr, "cannot open %s\n", path);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900100 goto err_2;
101 }
102 header.capsule_guid = efi_guid_fm_capsule;
103 header.header_size = sizeof(header);
AKASHI Takahiro0f626ce2020-11-30 18:12:16 +0900104 /* TODO: The current implementation ignores flags */
105 header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900106 header.capsule_image_size = sizeof(header)
107 + sizeof(capsule) + sizeof(u64)
108 + sizeof(image)
109 + bin_stat.st_size;
110
111 size = fwrite(&header, 1, sizeof(header), f);
112 if (size < sizeof(header)) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900113 fprintf(stderr, "write failed (%zx)\n", size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900114 goto err_3;
115 }
116
117 capsule.version = 0x00000001;
118 capsule.embedded_driver_count = 0;
119 capsule.payload_item_count = 1;
120 size = fwrite(&capsule, 1, sizeof(capsule), f);
121 if (size < (sizeof(capsule))) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900122 fprintf(stderr, "write failed (%zx)\n", size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900123 goto err_3;
124 }
125 offset = sizeof(capsule) + sizeof(u64);
126 size = fwrite(&offset, 1, sizeof(offset), f);
127 if (size < sizeof(offset)) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900128 fprintf(stderr, "write failed (%zx)\n", size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900129 goto err_3;
130 }
131
132 image.version = 0x00000003;
133 memcpy(&image.update_image_type_id, guid, sizeof(*guid));
134 image.update_image_index = index;
AKASHI Takahiroa4c14aa2021-01-22 10:43:49 +0900135 image.reserved[0] = 0;
136 image.reserved[1] = 0;
137 image.reserved[2] = 0;
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900138 image.update_image_size = bin_stat.st_size;
139 image.update_vendor_code_size = 0; /* none */
140 image.update_hardware_instance = instance;
141 image.image_capsule_support = 0;
142
143 size = fwrite(&image, 1, sizeof(image), f);
144 if (size < sizeof(image)) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900145 fprintf(stderr, "write failed (%zx)\n", size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900146 goto err_3;
147 }
148 size = fread(data, 1, bin_stat.st_size, g);
149 if (size < bin_stat.st_size) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900150 fprintf(stderr, "read failed (%zx)\n", size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900151 goto err_3;
152 }
153 size = fwrite(data, 1, bin_stat.st_size, f);
154 if (size < bin_stat.st_size) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900155 fprintf(stderr, "write failed (%zx)\n", size);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900156 goto err_3;
157 }
158
159 fclose(f);
160 fclose(g);
161 free(data);
162
163 return 0;
164
165err_3:
166 fclose(f);
167err_2:
168 free(data);
169err_1:
170 fclose(g);
171
172 return -1;
173}
174
175/*
176 * Usage:
177 * $ mkeficapsule -f <firmware binary> <output file>
178 */
179int main(int argc, char **argv)
180{
181 char *file;
182 efi_guid_t *guid;
183 unsigned long index, instance;
184 int c, idx;
185
186 file = NULL;
187 guid = NULL;
188 index = 0;
189 instance = 0;
190 for (;;) {
AKASHI Takahiro5b03cab2021-10-07 15:23:30 +0900191 c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900192 if (c == -1)
193 break;
194
195 switch (c) {
196 case 'f':
197 if (file) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900198 fprintf(stderr, "Image already specified\n");
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900199 return -1;
200 }
201 file = optarg;
202 guid = &efi_guid_image_type_uboot_fit;
203 break;
204 case 'r':
205 if (file) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900206 fprintf(stderr, "Image already specified\n");
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900207 return -1;
208 }
209 file = optarg;
210 guid = &efi_guid_image_type_uboot_raw;
211 break;
212 case 'i':
213 index = strtoul(optarg, NULL, 0);
214 break;
215 case 'I':
216 instance = strtoul(optarg, NULL, 0);
217 break;
218 case 'h':
219 print_usage();
220 return 0;
221 }
222 }
223
AKASHI Takahiro5b03cab2021-10-07 15:23:30 +0900224 /* need an output file */
225 if (argc != optind + 1) {
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900226 print_usage();
Sughosh Ganu14b44202021-01-22 20:34:56 +0530227 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900228 }
229
AKASHI Takahiro5b03cab2021-10-07 15:23:30 +0900230 /* need a fit image file or raw image file */
231 if (!file) {
232 print_usage();
233 exit(EXIT_SUCCESS);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900234 }
235
236 if (create_fwbin(argv[optind], file, guid, index, instance)
237 < 0) {
AKASHI Takahiro6cf40d42022-01-18 13:39:44 +0900238 fprintf(stderr, "Creating firmware capsule failed\n");
Sughosh Ganu14b44202021-01-22 20:34:56 +0530239 exit(EXIT_FAILURE);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900240 }
241
Sughosh Ganu14b44202021-01-22 20:34:56 +0530242 exit(EXIT_SUCCESS);
AKASHI Takahiro19122aa2020-11-30 18:12:15 +0900243}