arch/arm64: Support FEAT_CCIDX
[coreboot2.git] / util / smmstoretool / main.c
blob4857b624ba64e2461a44f5c16328d746a7e8fb31
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <unistd.h>
5 #include <errno.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
11 #include <commonlib/bsd/helpers.h>
13 #include "data.h"
14 #include "guids.h"
15 #include "storage.h"
16 #include "udk2017.h"
17 #include "vs.h"
19 struct subcommand_t {
20 const char *name;
21 const char *description;
22 void (*print_help)(FILE *f, const struct subcommand_t *info);
23 int (*process)(int argc, char *argv[], const char store_file[]);
26 static void help_get(FILE *f, const struct subcommand_t *info);
27 static void help_guids(FILE *f, const struct subcommand_t *info);
28 static void help_help(FILE *f, const struct subcommand_t *info);
29 static void help_list(FILE *f, const struct subcommand_t *info);
30 static void help_remove(FILE *f, const struct subcommand_t *info);
31 static void help_set(FILE *f, const struct subcommand_t *info);
32 static int process_get(int argc, char *argv[], const char store_file[]);
33 static int process_guids(int argc, char *argv[], const char store_file[]);
34 static int process_help(int argc, char *argv[], const char store_file[]);
35 static int process_list(int argc, char *argv[], const char store_file[]);
36 static int process_remove(int argc, char *argv[], const char store_file[]);
37 static int process_set(int argc, char *argv[], const char store_file[]);
39 static const struct subcommand_t sub_commands[] = {
41 .name = "get",
42 .description = "display current value of a variable",
43 .print_help = &help_get,
44 .process = &process_get,
47 .name = "guids",
48 .description = "show GUID to alias mapping",
49 .print_help = &help_guids,
50 .process = &process_guids,
53 .name = "help",
54 .description = "provide built-in help",
55 .print_help = &help_help,
56 .process = &process_help,
59 .name = "list",
60 .description = "list variables present in the store",
61 .print_help = &help_list,
62 .process = &process_list,
65 .name = "remove",
66 .description = "remove a variable from the store",
67 .print_help = &help_remove,
68 .process = &process_remove,
71 .name = "set",
72 .description = "add or updates a variable in the store",
73 .print_help = &help_set,
74 .process = &process_set,
78 static const int sub_command_count = ARRAY_SIZE(sub_commands);
80 static const char *USAGE_FMT = "Usage: %s smm-store-file|rom sub-command\n"
81 " %s -h|--help\n";
83 static const char *program_name;
85 static void print_program_usage(void)
87 fprintf(stderr, USAGE_FMT, program_name, program_name);
88 exit(EXIT_FAILURE);
91 static void print_sub_command_usage(const char sub_command[])
93 fprintf(stderr, "\n");
94 fprintf(stderr, USAGE_FMT, program_name, program_name);
95 fprintf(stderr, "\n");
97 for (int i = 0; i < sub_command_count; ++i) {
98 const struct subcommand_t *cmd = &sub_commands[i];
99 if (!str_eq(cmd->name, sub_command))
100 continue;
102 cmd->print_help(stderr, cmd);
103 break;
106 exit(EXIT_FAILURE);
109 static void print_help(void)
111 printf(USAGE_FMT, program_name, program_name);
113 printf("\n");
114 printf("Sub-commands:\n");
115 for (int i = 0; i < sub_command_count; ++i) {
116 const struct subcommand_t *cmd = &sub_commands[i];
117 printf(" * %-6s - %s\n", cmd->name, cmd->description);
121 static void print_types(FILE *f)
123 fprintf(f, "Types and their values:\n");
124 fprintf(f, " * bool (true, false)\n");
125 fprintf(f, " * uint8 (0-255)\n");
126 fprintf(f, " * ascii (NUL-terminated)\n");
127 fprintf(f, " * unicode (widened and NUL-terminated)\n");
128 fprintf(f, " * raw (output only; raw bytes on output)\n");
131 static void help_set(FILE *f, const struct subcommand_t *info)
133 fprintf(f, "Create or update a variable:\n");
134 fprintf(f, " %s smm-store-file|rom %s \\\n", program_name, info->name);
135 fprintf(f, " -g vendor-guid \\\n");
136 fprintf(f, " -n variable-name \\\n");
137 fprintf(f, " -t variable-type \\\n");
138 fprintf(f, " -v value\n");
139 fprintf(f, "\n");
140 print_types(f);
143 static int process_set(int argc, char *argv[], const char store_file[])
145 const char *name = NULL;
146 const char *value = NULL;
147 const char *type_str = NULL;
148 const char *guid_str = NULL;
149 int opt;
150 while ((opt = getopt(argc, argv, "n:t:v:g:")) != -1) {
151 switch (opt) {
152 case 'n':
153 name = optarg;
154 break;
155 case 't':
156 type_str = optarg;
157 break;
158 case 'v':
159 value = optarg;
160 break;
161 case 'g':
162 guid_str = optarg;
163 break;
165 case '?': /* parsing error */
166 print_sub_command_usage(argv[0]);
170 if (argv[optind] != NULL) {
171 fprintf(stderr, "First unexpected positional argument: %s\n",
172 argv[optind]);
173 print_sub_command_usage(argv[0]);
176 if (name == NULL || value == NULL || type_str == NULL ||
177 guid_str == NULL) {
178 fprintf(stderr, "All options are required\n");
179 print_sub_command_usage(argv[0]);
182 if (name[0] == '\0') {
183 fprintf(stderr, "Variable name can't be empty\n");
184 print_sub_command_usage(argv[0]);
187 EFI_GUID guid;
188 if (!parse_guid(guid_str, &guid)) {
189 fprintf(stderr, "Failed to parse GUID: %s\n", guid_str);
190 return EXIT_FAILURE;
193 enum data_type type;
194 if (!parse_data_type(type_str, &type)) {
195 fprintf(stderr, "Failed to parse type: %s\n", type_str);
196 return EXIT_FAILURE;
199 size_t data_size;
200 void *data = make_data(value, &data_size, type);
201 if (data == NULL) {
202 fprintf(stderr, "Failed to parse value \"%s\" as %s\n",
203 value, type_str);
204 return EXIT_FAILURE;
207 struct storage_t storage;
208 if (!storage_open(store_file, &storage, /*rw=*/true)) {
209 free(data);
210 return EXIT_FAILURE;
213 struct var_t *var = vs_find(&storage.vs, name, &guid);
214 if (var == NULL) {
215 var = vs_new_var(&storage.vs);
216 var->name = to_uchars(name, &var->name_size);
217 var->data = data;
218 var->data_size = data_size;
219 var->guid = guid;
220 } else {
221 free(var->data);
222 var->data = data;
223 var->data_size = data_size;
226 return storage_write_back(&storage) ? EXIT_SUCCESS : EXIT_FAILURE;
229 static void help_list(FILE *f, const struct subcommand_t *info)
231 fprintf(f, "List variables in the store:\n");
232 fprintf(f, " %s smm-store-file|rom %s\n", program_name, info->name);
235 static int process_list(int argc, char *argv[], const char store_file[])
237 if (argc != 1) {
238 fprintf(stderr, "Invalid invocation\n");
239 print_sub_command_usage(argv[0]);
242 struct storage_t storage;
243 if (!storage_open(store_file, &storage, /*rw=*/false))
244 return EXIT_FAILURE;
246 for (struct var_t *v = storage.vs.vars; v != NULL; v = v->next) {
247 char *name = to_chars(v->name, v->name_size);
248 char *guid = format_guid(&v->guid, /*use_alias=*/true);
250 printf("%-*s:%s (%zu %s)\n", GUID_LEN, guid, name, v->data_size,
251 v->data_size == 1 ? "byte" : "bytes");
253 free(name);
254 free(guid);
257 storage_drop(&storage);
258 return EXIT_SUCCESS;
261 static void help_get(FILE *f, const struct subcommand_t *info)
263 fprintf(f, "Read variable's value:\n");
264 fprintf(f, " %s smm-store-file|rom %s \\\n", program_name, info->name);
265 fprintf(f, " -g vendor-guid \\\n");
266 fprintf(f, " -n variable-name \\\n");
267 fprintf(f, " -t variable-type\n");
268 fprintf(f, "\n");
269 print_types(f);
272 static int process_get(int argc, char *argv[], const char store_file[])
274 const char *name = NULL;
275 const char *type_str = NULL;
276 const char *guid_str = NULL;
277 int opt;
278 while ((opt = getopt(argc, argv, "n:g:t:")) != -1) {
279 switch (opt) {
280 case 'n':
281 name = optarg;
282 break;
283 case 'g':
284 guid_str = optarg;
285 break;
286 case 't':
287 type_str = optarg;
288 break;
290 case '?': /* parsing error */
291 print_sub_command_usage(argv[0]);
295 if (name == NULL || type_str == NULL || guid_str == NULL) {
296 fprintf(stderr, "All options are required\n");
297 print_sub_command_usage(argv[0]);
300 EFI_GUID guid;
301 if (!parse_guid(guid_str, &guid)) {
302 fprintf(stderr, "Failed to parse GUID: %s\n", guid_str);
303 return EXIT_FAILURE;
306 enum data_type type;
307 if (!parse_data_type(type_str, &type)) {
308 fprintf(stderr, "Failed to parse type: %s\n", type_str);
309 return EXIT_FAILURE;
312 struct storage_t storage;
313 if (!storage_open(store_file, &storage, /*rw=*/false))
314 return EXIT_FAILURE;
316 int result = EXIT_SUCCESS;
318 struct var_t *var = vs_find(&storage.vs, name, &guid);
319 if (var == NULL) {
320 result = EXIT_FAILURE;
321 fprintf(stderr, "Couldn't find variable \"%s:%s\"\n",
322 guid_str, name);
323 } else if (var->data_size == 0) {
324 fprintf(stderr, "There is no data to show.\n");
325 result = EXIT_FAILURE;
326 } else {
327 print_data(var->data, var->data_size, type);
330 storage_drop(&storage);
331 return result;
334 static void help_help(FILE *f, const struct subcommand_t *info)
336 fprintf(f, "Display generic help:\n");
337 fprintf(f, " %s smm-store-file|rom %s\n", program_name, info->name);
338 fprintf(f, "\n");
339 fprintf(f, "Display sub-command help:\n");
340 fprintf(f, " %s smm-store-file|rom %s sub-command\n",
341 program_name, info->name);
344 static int process_help(int argc, char *argv[], const char store_file[])
346 (void)store_file;
348 if (argc == 1) {
349 print_help();
350 return EXIT_SUCCESS;
353 if (argc != 2) {
354 fprintf(stderr, "Invalid invocation\n");
355 print_sub_command_usage(argv[0]);
356 return EXIT_FAILURE;
359 const char *sub_command = argv[1];
361 for (int i = 0; i < sub_command_count; ++i) {
362 const struct subcommand_t *cmd = &sub_commands[i];
363 if (!str_eq(cmd->name, sub_command))
364 continue;
366 cmd->print_help(stdout, cmd);
367 return EXIT_SUCCESS;
370 fprintf(stderr, "Unknown sub-command: %s\n", sub_command);
371 print_help();
372 return EXIT_FAILURE;
375 static void help_remove(FILE *f, const struct subcommand_t *info)
377 fprintf(f, "Remove a variable:\n");
378 fprintf(f, " %s smm-store-file|rom %s \\\n", program_name, info->name);
379 fprintf(f, " -g vendor-guid \\\n");
380 fprintf(f, " -n variable-name\n");
383 static int process_remove(int argc, char *argv[], const char store_file[])
385 const char *name = NULL;
386 const char *guid_str = NULL;
387 int opt;
388 while ((opt = getopt(argc, argv, "n:g:")) != -1) {
389 switch (opt) {
390 case 'n':
391 name = optarg;
392 break;
393 case 'g':
394 guid_str = optarg;
395 break;
397 case '?': /* parsing error */
398 print_sub_command_usage(argv[0]);
402 if (name == NULL || guid_str == NULL) {
403 fprintf(stderr, "All options are required\n");
404 print_sub_command_usage(argv[0]);
407 EFI_GUID guid;
408 if (!parse_guid(guid_str, &guid)) {
409 fprintf(stderr, "Failed to parse GUID: %s\n", guid_str);
410 return EXIT_FAILURE;
413 struct storage_t storage;
414 if (!storage_open(store_file, &storage, /*rw=*/true))
415 return EXIT_FAILURE;
417 int result = EXIT_SUCCESS;
419 struct var_t *var = vs_find(&storage.vs, name, &guid);
420 if (var == NULL) {
421 result = EXIT_FAILURE;
422 fprintf(stderr, "Couldn't find variable \"%s:%s\"\n",
423 guid_str, name);
424 } else {
425 vs_delete(&storage.vs, var);
428 storage_write_back(&storage);
429 return result;
432 static void help_guids(FILE *f, const struct subcommand_t *info)
434 fprintf(f, "List recognized GUIDS:\n");
435 fprintf(f, " %s smm-store-file|rom %s\n", program_name, info->name);
438 static int process_guids(int argc, char *argv[], const char store_file[])
440 (void)store_file;
442 if (argc != 1) {
443 fprintf(stderr, "Invalid invocation\n");
444 print_sub_command_usage(argv[0]);
447 for (int i = 0; i < known_guid_count; ++i) {
448 char *guid = format_guid(&known_guids[i].guid,
449 /*use_alias=*/false);
450 printf("%-10s -> %s\n", known_guids[i].alias, guid);
451 free(guid);
453 return EXIT_SUCCESS;
456 int main(int argc, char *argv[])
458 program_name = argv[0];
460 if (argc > 1 && (str_eq(argv[1], "-h") || str_eq(argv[1], "--help"))) {
461 print_help();
462 exit(EXIT_SUCCESS);
465 if (argc < 3)
466 print_program_usage();
468 const char *store_file = argv[1];
469 const char *sub_command = argv[2];
471 int sub_command_argc = argc - 2;
472 char **sub_command_argv = argv + 2;
474 for (int i = 0; i < sub_command_count; ++i) {
475 const struct subcommand_t *cmd = &sub_commands[i];
476 if (!str_eq(cmd->name, sub_command))
477 continue;
479 return cmd->process(sub_command_argc,
480 sub_command_argv,
481 store_file);
484 fprintf(stderr, "Unknown sub-command: %s\n", sub_command);
485 print_help();
486 return EXIT_FAILURE;