1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * 'cedit' command
4  *
5  * Copyright 2023 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #include <abuf.h>
10 #include <cedit.h>
11 #include <command.h>
12 #include <dm.h>
13 #include <expo.h>
14 #include <fs.h>
15 #include <malloc.h>
16 #include <mapmem.h>
17 #include <dm/ofnode.h>
18 #include <linux/sizes.h>
19 
20 struct expo *cur_exp;
21 
check_cur_expo(void)22 static int check_cur_expo(void)
23 {
24 	if (!cur_exp) {
25 		printf("No expo loaded\n");
26 		return -ENOENT;
27 	}
28 
29 	return 0;
30 }
31 
do_cedit_load(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])32 static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc,
33 			 char *const argv[])
34 {
35 	const char *fname;
36 	struct expo *exp;
37 	oftree tree;
38 	ulong size;
39 	void *buf;
40 	int ret;
41 
42 	if (argc < 4)
43 		return CMD_RET_USAGE;
44 	fname = argv[3];
45 
46 	ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size);
47 	if (ret) {
48 		printf("File not found\n");
49 		return CMD_RET_FAILURE;
50 	}
51 
52 	tree = oftree_from_fdt(buf);
53 	if (!oftree_valid(tree)) {
54 		printf("Cannot create oftree\n");
55 		return CMD_RET_FAILURE;
56 	}
57 
58 	ret = expo_build(oftree_root(tree), &exp);
59 	oftree_dispose(tree);
60 	if (ret) {
61 		printf("Failed to build expo: %dE\n", ret);
62 		return CMD_RET_FAILURE;
63 	}
64 
65 	cur_exp = exp;
66 
67 	return 0;
68 }
69 
70 #ifdef CONFIG_COREBOOT_SYSINFO
do_cedit_cb_load(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])71 static int do_cedit_cb_load(struct cmd_tbl *cmdtp, int flag, int argc,
72 			    char *const argv[])
73 {
74 	struct expo *exp;
75 	int ret;
76 
77 	if (argc > 1)
78 		return CMD_RET_USAGE;
79 
80 	ret = cb_expo_build(&exp);
81 	if (ret) {
82 		printf("Failed to build expo: %dE\n", ret);
83 		return CMD_RET_FAILURE;
84 	}
85 
86 	cur_exp = exp;
87 
88 	return 0;
89 }
90 #endif /* CONFIG_COREBOOT_SYSINFO */
91 
do_cedit_write_fdt(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])92 static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc,
93 			      char *const argv[])
94 {
95 	const char *fname;
96 	struct abuf buf;
97 	loff_t bytes;
98 	int ret;
99 
100 	if (argc < 4)
101 		return CMD_RET_USAGE;
102 	fname = argv[3];
103 
104 	if (check_cur_expo())
105 		return CMD_RET_FAILURE;
106 
107 	ret = cedit_write_settings(cur_exp, &buf);
108 	if (ret) {
109 		printf("Failed to write settings: %dE\n", ret);
110 		return CMD_RET_FAILURE;
111 	}
112 
113 	if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
114 		return CMD_RET_FAILURE;
115 
116 	ret = fs_write(fname, map_to_sysmem(abuf_data(&buf)), 0,
117 		       abuf_size(&buf), &bytes);
118 	if (ret)
119 		return CMD_RET_FAILURE;
120 
121 	return 0;
122 }
123 
do_cedit_read_fdt(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])124 static int do_cedit_read_fdt(struct cmd_tbl *cmdtp, int flag, int argc,
125 			     char *const argv[])
126 {
127 	const char *fname;
128 	void *buf;
129 	oftree tree;
130 	ulong size;
131 	int ret;
132 
133 	if (argc < 4)
134 		return CMD_RET_USAGE;
135 	fname = argv[3];
136 
137 	ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size);
138 	if (ret) {
139 		printf("File not found\n");
140 		return CMD_RET_FAILURE;
141 	}
142 
143 	tree = oftree_from_fdt(buf);
144 	if (!oftree_valid(tree)) {
145 		free(buf);
146 		printf("Cannot create oftree\n");
147 		return CMD_RET_FAILURE;
148 	}
149 
150 	ret = cedit_read_settings(cur_exp, tree);
151 	oftree_dispose(tree);
152 	free(buf);
153 	if (ret) {
154 		printf("Failed to read settings: %dE\n", ret);
155 		return CMD_RET_FAILURE;
156 	}
157 
158 	return 0;
159 }
160 
do_cedit_write_env(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])161 static int do_cedit_write_env(struct cmd_tbl *cmdtp, int flag, int argc,
162 			      char *const argv[])
163 {
164 	bool verbose;
165 	int ret;
166 
167 	if (check_cur_expo())
168 		return CMD_RET_FAILURE;
169 
170 	verbose = argc > 1 && !strcmp(argv[1], "-v");
171 
172 	ret = cedit_write_settings_env(cur_exp, verbose);
173 	if (ret) {
174 		printf("Failed to write settings to environment: %dE\n", ret);
175 		return CMD_RET_FAILURE;
176 	}
177 
178 	return 0;
179 }
180 
do_cedit_read_env(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])181 static int do_cedit_read_env(struct cmd_tbl *cmdtp, int flag, int argc,
182 			     char *const argv[])
183 {
184 	bool verbose;
185 	int ret;
186 
187 	if (check_cur_expo())
188 		return CMD_RET_FAILURE;
189 
190 	verbose = argc > 1 && !strcmp(argv[1], "-v");
191 
192 	ret = cedit_read_settings_env(cur_exp, verbose);
193 	if (ret) {
194 		printf("Failed to read settings from environment: %dE\n", ret);
195 		return CMD_RET_FAILURE;
196 	}
197 
198 	return 0;
199 }
200 
do_cedit_write_cmos(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])201 static int do_cedit_write_cmos(struct cmd_tbl *cmdtp, int flag, int argc,
202 			       char *const argv[])
203 {
204 	struct udevice *dev;
205 	bool verbose = false;
206 	int ret;
207 
208 	if (check_cur_expo())
209 		return CMD_RET_FAILURE;
210 
211 	if (argc > 1 && !strcmp(argv[1], "-v")) {
212 		verbose = true;
213 		argc--;
214 		argv++;
215 	}
216 
217 	if (argc > 1)
218 		ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev);
219 	else
220 		ret = uclass_first_device_err(UCLASS_RTC, &dev);
221 	if (ret) {
222 		printf("Failed to get RTC device: %dE\n", ret);
223 		return CMD_RET_FAILURE;
224 	}
225 
226 	if (cedit_write_settings_cmos(cur_exp, dev, verbose)) {
227 		printf("Failed to write settings to CMOS\n");
228 		return CMD_RET_FAILURE;
229 	}
230 
231 	return 0;
232 }
233 
do_cedit_read_cmos(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])234 static int do_cedit_read_cmos(struct cmd_tbl *cmdtp, int flag, int argc,
235 			      char *const argv[])
236 {
237 	struct udevice *dev;
238 	bool verbose = false;
239 	int ret;
240 
241 	if (check_cur_expo())
242 		return CMD_RET_FAILURE;
243 
244 	if (argc > 1 && !strcmp(argv[1], "-v")) {
245 		verbose = true;
246 		argc--;
247 		argv++;
248 	}
249 
250 	if (argc > 1)
251 		ret = uclass_get_device_by_name(UCLASS_RTC, argv[1], &dev);
252 	else
253 		ret = uclass_first_device_err(UCLASS_RTC, &dev);
254 	if (ret) {
255 		printf("Failed to get RTC device: %dE\n", ret);
256 		return CMD_RET_FAILURE;
257 	}
258 
259 	ret = cedit_read_settings_cmos(cur_exp, dev, verbose);
260 	if (ret) {
261 		printf("Failed to read settings from CMOS: %dE\n", ret);
262 		return CMD_RET_FAILURE;
263 	}
264 
265 	return 0;
266 }
267 
do_cedit_run(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])268 static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
269 			char *const argv[])
270 {
271 	ofnode node;
272 	int ret;
273 
274 	if (check_cur_expo())
275 		return CMD_RET_FAILURE;
276 
277 	node = ofnode_path("/bootstd/cedit-theme");
278 	if (ofnode_valid(node)) {
279 		ret = expo_apply_theme(cur_exp, node);
280 		if (ret)
281 			return CMD_RET_FAILURE;
282 	} else {
283 		log_warning("No theme found\n");
284 	}
285 	ret = cedit_run(cur_exp);
286 	if (ret) {
287 		log_err("Failed (err=%dE)\n", ret);
288 		return CMD_RET_FAILURE;
289 	}
290 	expo_destroy(cur_exp);
291 	cur_exp = NULL;
292 
293 	return 0;
294 }
295 
296 U_BOOT_LONGHELP(cedit,
297 	"load <interface> <dev[:part]> <filename>   - load config editor\n"
298 #ifdef CONFIG_COREBOOT_SYSINFO
299 	"cb_load                                          - load coreboot CMOS editor\n"
300 #endif
301 	"cedit read_fdt <i/f> <dev[:part]> <filename>     - read settings\n"
302 	"cedit write_fdt <i/f> <dev[:part]> <filename>    - write settings\n"
303 	"cedit read_env [-v]                              - read settings from env vars\n"
304 	"cedit write_env [-v]                             - write settings to env vars\n"
305 	"cedit read_cmos [-v] [dev]                       - read settings from CMOS RAM\n"
306 	"cedit write_cmos [-v] [dev]                      - write settings to CMOS RAM\n"
307 	"cedit run                                        - run config editor");
308 
309 U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text,
310 	U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load),
311 #ifdef CONFIG_COREBOOT_SYSINFO
312 	U_BOOT_SUBCMD_MKENT(cb_load, 5, 1, do_cedit_cb_load),
313 #endif
314 	U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt),
315 	U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt),
316 	U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env),
317 	U_BOOT_SUBCMD_MKENT(write_env, 2, 1, do_cedit_write_env),
318 	U_BOOT_SUBCMD_MKENT(read_cmos, 2, 1, do_cedit_read_cmos),
319 	U_BOOT_SUBCMD_MKENT(write_cmos, 2, 1, do_cedit_write_cmos),
320 	U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run),
321 );
322