| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * 'cedit' command | |
| * | |
| * Copyright 2023 Google LLC | |
| * Written by Simon Glass <sjg@chromium.org> | |
| */ | |
| #include <abuf.h> | |
| #include <cedit.h> | |
| #include <command.h> | |
| #include <dm.h> | |
| #include <expo.h> | |
| #include <fs.h> | |
| #include <malloc.h> | |
| #include <mapmem.h> | |
| #include <dm/ofnode.h> | |
| #include <linux/sizes.h> | |
| struct expo *cur_exp; | |
| static int check_cur_expo(void) | |
| { | |
| if (!cur_exp) { | |
| printf("No expo loaded\n"); | |
| return -ENOENT; | |
| } | |
| return 0; | |
| } | |
| static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| const char *fname; | |
| struct expo *exp; | |
| oftree tree; | |
| ulong size; | |
| void *buf; | |
| int ret; | |
| if (argc < 4) | |
| return CMD_RET_USAGE; | |
| fname = argv[3]; | |
| ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size); | |
| if (ret) { | |
| printf("File not found\n"); | |
| return CMD_RET_FAILURE; | |
| } | |
| tree = oftree_from_fdt(buf); | |
| if (!oftree_valid(tree)) { | |
| printf("Cannot create oftree\n"); | |
| return CMD_RET_FAILURE; | |
| } | |
| ret = expo_build(oftree_root(tree), &exp); | |
| oftree_dispose(tree); | |
| if (ret) { | |
| printf("Failed to build expo: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| cur_exp = exp; | |
| return 0; | |
| } | |
| #ifdef CONFIG_COREBOOT_SYSINFO | |
| static int do_cedit_cb_load(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| struct expo *exp; | |
| int ret; | |
| if (argc > 1) | |
| return CMD_RET_USAGE; | |
| ret = cb_expo_build(&exp); | |
| if (ret) { | |
| printf("Failed to build expo: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| cur_exp = exp; | |
| return 0; | |
| } | |
| #endif /* CONFIG_COREBOOT_SYSINFO */ | |
| static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| const char *fname; | |
| struct abuf buf; | |
| loff_t bytes; | |
| int ret; | |
| if (argc < 4) | |
| return CMD_RET_USAGE; | |
| fname = argv[3]; | |
| if (check_cur_expo()) | |
| return CMD_RET_FAILURE; | |
| ret = cedit_write_settings(cur_exp, &buf); | |
| if (ret) { | |
| printf("Failed to write settings: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY)) | |
| return CMD_RET_FAILURE; | |
| ret = fs_write(fname, map_to_sysmem(abuf_data(&buf)), 0, | |
| abuf_size(&buf), &bytes); | |
| if (ret) | |
| return CMD_RET_FAILURE; | |
| return 0; | |
| } | |
| static int do_cedit_read_fdt(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| const char *fname; | |
| void *buf; | |
| oftree tree; | |
| ulong size; | |
| int ret; | |
| if (argc < 4) | |
| return CMD_RET_USAGE; | |
| fname = argv[3]; | |
| ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size); | |
| if (ret) { | |
| printf("File not found\n"); | |
| return CMD_RET_FAILURE; | |
| } | |
| tree = oftree_from_fdt(buf); | |
| if (!oftree_valid(tree)) { | |
| free(buf); | |
| printf("Cannot create oftree\n"); | |
| return CMD_RET_FAILURE; | |
| } | |
| ret = cedit_read_settings(cur_exp, tree); | |
| oftree_dispose(tree); | |
| free(buf); | |
| if (ret) { | |
| printf("Failed to read settings: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| return 0; | |
| } | |
| static int do_cedit_write_env(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| bool verbose; | |
| int ret; | |
| if (check_cur_expo()) | |
| return CMD_RET_FAILURE; | |
| verbose = argc > 1 && !strcmp(argv[1], "-v"); | |
| ret = cedit_write_settings_env(cur_exp, verbose); | |
| if (ret) { | |
| printf("Failed to write settings to environment: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| return 0; | |
| } | |
| static int do_cedit_read_env(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| bool verbose; | |
| int ret; | |
| if (check_cur_expo()) | |
| return CMD_RET_FAILURE; | |
| verbose = argc > 1 && !strcmp(argv[1], "-v"); | |
| ret = cedit_read_settings_env(cur_exp, verbose); | |
| if (ret) { | |
| printf("Failed to read settings from environment: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| return 0; | |
| } | |
| static int do_cedit_write_cmos(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| struct udevice *dev; | |
| bool verbose = false; | |
| int ret; | |
| if (check_cur_expo()) | |
| return CMD_RET_FAILURE; | |
| if (argc > 1 && !strcmp(argv[1], "-v")) { | |
| verbose = true; | |
| argc--; | |
| argv++; | |
| } | |
| if (argc > 1) | |
| ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev); | |
| else | |
| ret = uclass_first_device_err(UCLASS_RTC, &dev); | |
| if (ret) { | |
| printf("Failed to get RTC device: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| if (cedit_write_settings_cmos(cur_exp, dev, verbose)) { | |
| printf("Failed to write settings to CMOS\n"); | |
| return CMD_RET_FAILURE; | |
| } | |
| return 0; | |
| } | |
| static int do_cedit_read_cmos(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| struct udevice *dev; | |
| bool verbose = false; | |
| int ret; | |
| if (check_cur_expo()) | |
| return CMD_RET_FAILURE; | |
| if (argc > 1 && !strcmp(argv[1], "-v")) { | |
| verbose = true; | |
| argc--; | |
| argv++; | |
| } | |
| if (argc > 1) | |
| ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev); | |
| else | |
| ret = uclass_first_device_err(UCLASS_RTC, &dev); | |
| if (ret) { | |
| printf("Failed to get RTC device: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| ret = cedit_read_settings_cmos(cur_exp, dev, verbose); | |
| if (ret) { | |
| printf("Failed to read settings from CMOS: %dE\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| return 0; | |
| } | |
| static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, | |
| char *const argv[]) | |
| { | |
| ofnode node; | |
| int ret; | |
| if (check_cur_expo()) | |
| return CMD_RET_FAILURE; | |
| node = ofnode_path("/bootstd/cedit-theme"); | |
| if (ofnode_valid(node)) { | |
| ret = expo_apply_theme(cur_exp, node); | |
| if (ret) | |
| return CMD_RET_FAILURE; | |
| } else { | |
| log_warning("No theme found\n"); | |
| } | |
| ret = cedit_run(cur_exp); | |
| if (ret) { | |
| log_err("Failed (err=%dE)\n", ret); | |
| return CMD_RET_FAILURE; | |
| } | |
| expo_destroy(cur_exp); | |
| cur_exp = NULL; | |
| return 0; | |
| } | |
| U_BOOT_LONGHELP(cedit, | |
| "load <interface> <dev[:part]> <filename> - load config editor\n" | |
| #ifdef CONFIG_COREBOOT_SYSINFO | |
| "cb_load - load coreboot CMOS editor\n" | |
| #endif | |
| "cedit read_fdt <i/f> <dev[:part]> <filename> - read settings\n" | |
| "cedit write_fdt <i/f> <dev[:part]> <filename> - write settings\n" | |
| "cedit read_env [-v] - read settings from env vars\n" | |
| "cedit write_env [-v] - write settings to env vars\n" | |
| "cedit read_cmos [-v] [dev] - read settings from CMOS RAM\n" | |
| "cedit write_cmos [-v] [dev] - write settings to CMOS RAM\n" | |
| "cedit run - run config editor"); | |
| U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, | |
| U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), | |
| #ifdef CONFIG_COREBOOT_SYSINFO | |
| U_BOOT_SUBCMD_MKENT(cb_load, 5, 1, do_cedit_cb_load), | |
| #endif | |
| U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt), | |
| U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), | |
| U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env), | |
| U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env), | |
| U_BOOT_SUBCMD_MKENT(read_cmos, 2, 1, do_cedit_read_cmos), | |
| U_BOOT_SUBCMD_MKENT(write_cmos, 2, 1, do_cedit_write_cmos), | |
| U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), | |
| ); |