1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /* Command-Line utility to exercise firmware interfaces */
17 
18 #define LOG_TAG "fwtool"
19 
20 #include <errno.h>
21 #include <inttypes.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "debug_cmd.h"
28 #include "flash_device.h"
29 #include "fmap.h"
30 #include "update_fw.h"
31 #include "update_log.h"
32 #include "vboot_interface.h"
33 
34 static void *spi;
35 static void *ec;
36 
get_spi(void)37 static void *get_spi(void)
38 {
39 	if (!spi)
40 		spi = flash_open("spi", NULL);
41 
42 	return spi;
43 }
44 
get_ec(void)45 static void *get_ec(void)
46 {
47 	if (!ec)
48 		ec = flash_open("ec", NULL);
49 
50 	return ec;
51 }
52 
dump_fmap(struct flash_device * dev)53 static void dump_fmap(struct flash_device *dev)
54 {
55 	int i;
56 	struct fmap *fmap;
57 
58 	fmap = flash_get_fmap(dev);
59 	if (!fmap)
60 		return;
61 
62 	printf("FMAP '%s' ver %d.%d base 0x%" PRIx64 " size 0x%x\n",
63 		fmap->name, fmap->ver_major, fmap->ver_minor,
64 		fmap->base, fmap->size);
65 	for (i = 0; i < fmap->nareas; i++) {
66 		struct fmap_area *a = fmap->areas+i;
67 		printf("%16s @%08x size 0x%08x %2s %s\n",
68 			a->name, a->offset, a->size,
69 			a->flags & FMAP_AREA_RO ? "RO" : "",
70 			a->flags & FMAP_AREA_STATIC ? "static" : "");
71 	}
72 }
73 
dump_section(struct flash_device * dev,const char * name)74 static void dump_section(struct flash_device *dev, const char *name)
75 {
76 	size_t size;
77 	off_t offset;
78 	char *content;
79 
80 	content = reinterpret_cast<char*>(fmap_read_section(dev, name, &size, &offset));
81 	if (content) {
82 		content[size - 1] = '\0';
83 		printf("[%s]@%lx={%s}\n", name, offset, content);
84 	}
85 }
86 
cmd_flash_fmap(int argc,const char ** argv)87 static int cmd_flash_fmap(int argc, const char **argv)
88 {
89 	if (!get_spi())
90 		return -ENODEV;
91 
92         struct flash_device* dev = reinterpret_cast<struct flash_device*>(spi);
93 	dump_fmap(dev);
94 	dump_section(dev, "RO_FRID");
95 	dump_section(dev, "RW_FWID_A");
96 	dump_section(dev, "RW_FWID_B");
97 	return 0;
98 }
99 
cmd_vboot(int argc,const char ** argv)100 static int cmd_vboot(int argc, const char **argv)
101 {
102 	char *hwid = fdt_read_string("hardware-id");
103 	char *version = fdt_read_string("firmware-version");
104 	char *ro_version = fdt_read_string("readonly-firmware-version");
105 	char *type = fdt_read_string("firmware-type");
106 	char *ec = fdt_read_string("active-ec-firmware");
107 	printf("HWID: %s\n", hwid);
108 	printf("Version: %s\n", version);
109 	printf("RO Version: %s\n", ro_version);
110 	printf("FW Type: %s\n", type);
111 	printf("EC: %s\n", ec);
112 	printf("FW partition: %c\n", vboot_get_mainfw_act());
113 	free(hwid);
114 	free(version);
115 	free(ro_version);
116 	free(type);
117 	free(ec);
118 
119 	return 0;
120 }
121 
cmd_update(int argc,const char ** argv)122 static int cmd_update(int argc, const char **argv)
123 {
124 	Value mainv, ecv;
125 	if (argc < 3)
126 		return -EINVAL;
127 
128 	printf("Updating using images main:%s and ec:%s ...\n", argv[1], argv[2]);
129 	mainv.type = VAL_STRING;
130 	mainv.data = const_cast<char*>(argv[1]);
131 	ecv.type = VAL_STRING;
132 	ecv.data = const_cast<char*>(argv[2]);
133 	update_fw(&mainv, &ecv, 1);
134 	printf("Done.\n");
135 
136 	return -ENOENT;
137 }
138 
cmd_vbnv_read(int argc,const char ** argv)139 static int cmd_vbnv_read(int argc, const char **argv)
140 {
141 	if (argc != 2) {
142 		printf("Usage: fwtool vbnv read <flag>\n");
143 		printf("where <flag> is one of the following:\n");
144 		vbnv_usage(0);
145 		return -EINVAL;
146 	}
147 
148 	if (!get_spi())
149 		return -ENODEV;
150 
151 	uint8_t val;
152 
153 	if (vbnv_get_flag(reinterpret_cast<struct flash_device*>(spi), argv[1], &val) == 0)
154 		printf("%s = %d\n", argv[1], val);
155 
156 	return 0;
157 }
158 
cmd_vbnv_write(int argc,const char ** argv)159 static int cmd_vbnv_write(int argc, const char **argv)
160 {
161 	if (argc != 3) {
162 		printf("Usage: fwtool vbnv write <flag> <val>\n");
163 		printf("where <flag> is one of the following:\n");
164 		vbnv_usage(1);
165 		return -EINVAL;
166 	}
167 
168 	if (!get_spi())
169 		return -ENODEV;
170 
171 	uint8_t val = atoi(argv[2]);
172 	vbnv_set_flag(reinterpret_cast<struct flash_device*>(spi), argv[1], val);
173 	return 0;
174 }
175 
sync_slots(void)176 static void sync_slots(void)
177 {
178 	static struct {
179 		char part;
180 		const char *name_str;
181 		const char *id_str;
182 	} part_list[] = {
183 		{'A', "RW_SECTION_A", "RW_FWID_A"},
184 		{'B', "RW_SECTION_B", "RW_FWID_B"},
185 	};
186 
187 
188 	char cur_part = vboot_get_mainfw_act();
189 	int cur_index;
190 
191 	if (cur_part == 'A')
192 		cur_index = 0;
193 	else if (cur_part == 'B')
194 		cur_index = 1;
195 	else {
196 		ALOGW("ERROR: Unexpected cur_part value\n");
197 		return;
198 	}
199 
200 	int old_index = cur_index ^ 1;
201 
202 	if (!get_spi()) {
203 		ALOGW("ERROR: get_spi failed.\n");
204 		return;
205 	}
206 
207 	size_t cur_id_size;
208         struct flash_device* dev = reinterpret_cast<struct flash_device*>(spi);
209 	char *cur_fwid = reinterpret_cast<char*>(fmap_read_section(dev,
210 		part_list[cur_index].id_str, &cur_id_size, NULL));
211 
212 	if ((cur_fwid == NULL) || (cur_id_size == 0)) {
213 		ALOGW("ERROR: Current FWID read error.\n");
214 		return;
215 	}
216 
217 	ALOGD("Cur fwid: %s\n", cur_fwid);
218 
219 	size_t old_id_size;
220 	char *old_fwid = reinterpret_cast<char*>(fmap_read_section(dev,
221 	        part_list[old_index].id_str, &old_id_size, NULL));
222 
223 	if ((old_fwid == NULL) || (old_id_size == 0))
224 		ALOGD("Old FWID read error or FW slot damaged.\n");
225 	else {
226 		ALOGD("Old fwid: %s\n", old_fwid);
227 
228 		if ((cur_id_size == old_id_size) &&
229 		    !strncmp(cur_fwid, old_fwid, cur_id_size)) {
230 			ALOGD("Slots already synced.\n");
231 			free(cur_fwid);
232 			free(old_fwid);
233 			return;
234 		}
235 	}
236 
237 	free(cur_fwid);
238 	free(old_fwid);
239 
240 	size_t sec_size;
241 	ALOGD("Reading current firmware slot.\n");
242 	uint8_t *cur_section = reinterpret_cast<uint8_t*>(fmap_read_section(dev,
243 	        part_list[cur_index].name_str, &sec_size, NULL));
244 	if (cur_section == NULL) {
245 		ALOGW("Error: Could not read current firmware slot.\n");
246 		return;
247 	}
248 
249 	off_t old_offset;
250 	ALOGD("Reading old firmware slot offset.\n");
251 	if (fmap_get_section_offset(dev,
252 				    part_list[old_index].name_str,
253 				    &old_offset) == -1) {
254 		ALOGW("Error: Could not read old firmware slot offset.\n");
255 		free(cur_section);
256 		return;
257 	}
258 
259 	ALOGD("Erasing old firmware slot.\n");
260 	if (flash_erase(dev, old_offset, sec_size)) {
261 		ALOGW("Error: Could not erase old firmware slot.\n");
262 		free(cur_section);
263 		return;
264 	}
265 
266 	ALOGD("Updating old firmware slot.\n");
267 	if (flash_write(dev, old_offset, cur_section, sec_size))
268 		ALOGW("Error: Could not update old firmware slot.\n");
269 	else
270 		ALOGD("Slot sync complete.\n");
271 
272 	free(cur_section);
273 }
274 
cmd_mark_boot(int argc,const char ** argv)275 static int cmd_mark_boot(int argc, const char **argv)
276 {
277 	if (argc != 2) {
278 		printf("Usage: fwtool mark_boot <status>\n");
279 		printf("    where status can be:\n");
280 		printf("    success: This boot was successful.\n");
281 		return -EINVAL;
282 	}
283 
284 	if (!get_spi())
285 		return -ENODEV;
286 
287 	if (strcmp(argv[1], "success") == 0) {
288 		vbnv_set_flag(reinterpret_cast<struct flash_device*>(spi), "boot_result",
289                               VB2_FW_RESULT_SUCCESS);
290 		vbnv_set_flag(reinterpret_cast<struct flash_device*>(spi), "try_count", 0);
291 		sync_slots();
292 	} else {
293 		printf("Invalid arg\n");
294 		return -EINVAL;
295 	}
296 
297 	return 0;
298 }
299 
300 static struct command subcmds_flash[] = {
301 	CMD(flash_fmap, "Dump FMAP information"),
302 	CMD_GUARD_LAST
303 };
304 
305 static struct command subcmds_vbnv[] = {
306 	CMD(vbnv_read, "Read flag from NvStorage"),
307 	CMD(vbnv_write, "Write flag from NvStorage"),
308 	CMD_GUARD_LAST,
309 };
310 
311 static struct command cmds[] = {
312 	SUBCMDS(ec,    "Send commands directly to the EC"),
313 	SUBCMDS(flash, "Read/Write/Dump flash"),
314 	CMD(update,    "Update the firmwares"),
315 	CMD(vboot,     "dump VBoot information"),
316 	SUBCMDS(vbnv,      "Vboot NvStorage"),
317 	CMD(mark_boot, "Mark boot result"),
318 	CMD_GUARD_LAST
319 };
320 
print_usage(struct command * commands,int idx,int prefix,int argc,const char ** argv)321 static void print_usage(struct command *commands, int idx, int prefix,
322 			int argc, const char **argv)
323 {
324 	int i;
325 	struct command *c = commands;
326 	fprintf(stderr, "Usage: ");
327 	for (i = 0; i <= idx; i++)
328 		fprintf(stderr,"%s ", argv[i]);
329 	fprintf(stderr, "\n");
330 	while (c->name) {
331 		fprintf(stderr, "\t\t%-12s: %s\n", c->name + prefix, c->help);
332 		c++;
333 	}
334 }
335 
run_cmd(struct command * commands,int idx,int prefix,int argc,const char ** argv)336 static int run_cmd(struct command *commands, int idx, int prefix,
337 		   int argc, const char **argv)
338 {
339 	struct command *c = commands;
340 	if (argc <= idx + 1)
341 		goto no_cmd;
342 
343 	idx += 1;
344 	while (c->name) {
345 		if (!strcmp(c->name + prefix, argv[idx])) {
346 			int nprefx = prefix + strlen(c->name) + 1;
347 			if (argc > 1 && c->subcmd)
348 				return run_cmd(c->subcmd, idx, nprefx,
349 						argc, argv);
350 			else if (c->handler)
351 				return c->handler(argc - idx, argv + idx);
352 			else
353 				print_usage(c->subcmd, idx, nprefx, argc, argv);
354 			return -EINVAL;
355 		}
356 		c++;
357 	}
358 	idx -= 1; /* last command word was unknown */
359 no_cmd:
360 	print_usage(commands, idx, prefix, argc, argv);
361 	return -ENOENT;
362 }
363 
main(int argc,const char ** argv)364 int main(int argc, const char **argv)
365 {
366 	int res = -EINVAL;
367 
368 	printf("Firmware debug Tool\n");
369 
370 	res = run_cmd(cmds, 0, 0, argc, argv);
371 
372 	/* Clean up our flash handlers */
373 	if (spi)
374 		flash_close(reinterpret_cast<struct flash_device*>(spi));
375 	if (ec)
376 		flash_close(reinterpret_cast<struct flash_device*>(ec));
377 
378 	return res;
379 }
380