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 if (argc < 3)
125 return -EINVAL;
126
127 printf("Updating using images main:%s and ec:%s ...\n", argv[1], argv[2]);
128 Value mainv(VAL_STRING, argv[1]);
129 Value ecv(VAL_STRING, argv[2]);
130 update_fw(&mainv, &ecv, 1);
131 printf("Done.\n");
132
133 return -ENOENT;
134 }
135
cmd_vbnv_read(int argc,const char ** argv)136 static int cmd_vbnv_read(int argc, const char **argv)
137 {
138 if (argc != 2) {
139 printf("Usage: fwtool vbnv read <flag>\n");
140 printf("where <flag> is one of the following:\n");
141 vbnv_usage(0);
142 return -EINVAL;
143 }
144
145 if (!get_spi())
146 return -ENODEV;
147
148 uint8_t val;
149
150 if (vbnv_get_flag(reinterpret_cast<struct flash_device*>(spi), argv[1], &val) == 0)
151 printf("%s = %d\n", argv[1], val);
152
153 return 0;
154 }
155
cmd_vbnv_write(int argc,const char ** argv)156 static int cmd_vbnv_write(int argc, const char **argv)
157 {
158 if (argc != 3) {
159 printf("Usage: fwtool vbnv write <flag> <val>\n");
160 printf("where <flag> is one of the following:\n");
161 vbnv_usage(1);
162 return -EINVAL;
163 }
164
165 if (!get_spi())
166 return -ENODEV;
167
168 uint8_t val = atoi(argv[2]);
169 vbnv_set_flag(reinterpret_cast<struct flash_device*>(spi), argv[1], val);
170 return 0;
171 }
172
sync_slots(void)173 static void sync_slots(void)
174 {
175 static struct {
176 char part;
177 const char *name_str;
178 const char *id_str;
179 } part_list[] = {
180 {'A', "RW_SECTION_A", "RW_FWID_A"},
181 {'B', "RW_SECTION_B", "RW_FWID_B"},
182 };
183
184
185 char cur_part = vboot_get_mainfw_act();
186 int cur_index;
187
188 if (cur_part == 'A')
189 cur_index = 0;
190 else if (cur_part == 'B')
191 cur_index = 1;
192 else {
193 ALOGW("ERROR: Unexpected cur_part value\n");
194 return;
195 }
196
197 int old_index = cur_index ^ 1;
198
199 if (!get_spi()) {
200 ALOGW("ERROR: get_spi failed.\n");
201 return;
202 }
203
204 size_t cur_id_size;
205 struct flash_device* dev = reinterpret_cast<struct flash_device*>(spi);
206 char *cur_fwid = reinterpret_cast<char*>(fmap_read_section(dev,
207 part_list[cur_index].id_str, &cur_id_size, NULL));
208
209 if ((cur_fwid == NULL) || (cur_id_size == 0)) {
210 ALOGW("ERROR: Current FWID read error.\n");
211 return;
212 }
213
214 ALOGD("Cur fwid: %s\n", cur_fwid);
215
216 size_t old_id_size;
217 char *old_fwid = reinterpret_cast<char*>(fmap_read_section(dev,
218 part_list[old_index].id_str, &old_id_size, NULL));
219
220 if ((old_fwid == NULL) || (old_id_size == 0))
221 ALOGD("Old FWID read error or FW slot damaged.\n");
222 else {
223 ALOGD("Old fwid: %s\n", old_fwid);
224
225 if ((cur_id_size == old_id_size) &&
226 !strncmp(cur_fwid, old_fwid, cur_id_size)) {
227 ALOGD("Slots already synced.\n");
228 free(cur_fwid);
229 free(old_fwid);
230 return;
231 }
232 }
233
234 free(cur_fwid);
235 free(old_fwid);
236
237 size_t sec_size;
238 ALOGD("Reading current firmware slot.\n");
239 uint8_t *cur_section = reinterpret_cast<uint8_t*>(fmap_read_section(dev,
240 part_list[cur_index].name_str, &sec_size, NULL));
241 if (cur_section == NULL) {
242 ALOGW("Error: Could not read current firmware slot.\n");
243 return;
244 }
245
246 off_t old_offset;
247 ALOGD("Reading old firmware slot offset.\n");
248 if (fmap_get_section_offset(dev,
249 part_list[old_index].name_str,
250 &old_offset) == -1) {
251 ALOGW("Error: Could not read old firmware slot offset.\n");
252 free(cur_section);
253 return;
254 }
255
256 ALOGD("Erasing old firmware slot.\n");
257 if (flash_erase(dev, old_offset, sec_size)) {
258 ALOGW("Error: Could not erase old firmware slot.\n");
259 free(cur_section);
260 return;
261 }
262
263 ALOGD("Updating old firmware slot.\n");
264 if (flash_write(dev, old_offset, cur_section, sec_size))
265 ALOGW("Error: Could not update old firmware slot.\n");
266 else
267 ALOGD("Slot sync complete.\n");
268
269 free(cur_section);
270 }
271
cmd_mark_boot(int argc,const char ** argv)272 static int cmd_mark_boot(int argc, const char **argv)
273 {
274 if (argc != 2) {
275 printf("Usage: fwtool mark_boot <status>\n");
276 printf(" where status can be:\n");
277 printf(" success: This boot was successful.\n");
278 return -EINVAL;
279 }
280
281 if (!get_spi())
282 return -ENODEV;
283
284 if (strcmp(argv[1], "success") == 0) {
285 vbnv_set_flag(reinterpret_cast<struct flash_device*>(spi), "boot_result",
286 VB2_FW_RESULT_SUCCESS);
287 vbnv_set_flag(reinterpret_cast<struct flash_device*>(spi), "try_count", 0);
288 sync_slots();
289 } else {
290 printf("Invalid arg\n");
291 return -EINVAL;
292 }
293
294 return 0;
295 }
296
297 static struct command subcmds_flash[] = {
298 CMD(flash_fmap, "Dump FMAP information"),
299 CMD_GUARD_LAST
300 };
301
302 static struct command subcmds_vbnv[] = {
303 CMD(vbnv_read, "Read flag from NvStorage"),
304 CMD(vbnv_write, "Write flag from NvStorage"),
305 CMD_GUARD_LAST,
306 };
307
308 static struct command cmds[] = {
309 SUBCMDS(ec, "Send commands directly to the EC"),
310 SUBCMDS(flash, "Read/Write/Dump flash"),
311 CMD(update, "Update the firmwares"),
312 CMD(vboot, "dump VBoot information"),
313 SUBCMDS(vbnv, "Vboot NvStorage"),
314 CMD(mark_boot, "Mark boot result"),
315 CMD_GUARD_LAST
316 };
317
print_usage(struct command * commands,int idx,int prefix,int argc,const char ** argv)318 static void print_usage(struct command *commands, int idx, int prefix,
319 int argc, const char **argv)
320 {
321 int i;
322 struct command *c = commands;
323 fprintf(stderr, "Usage: ");
324 for (i = 0; i <= idx; i++)
325 fprintf(stderr,"%s ", argv[i]);
326 fprintf(stderr, "\n");
327 while (c->name) {
328 fprintf(stderr, "\t\t%-12s: %s\n", c->name + prefix, c->help);
329 c++;
330 }
331 }
332
run_cmd(struct command * commands,int idx,int prefix,int argc,const char ** argv)333 static int run_cmd(struct command *commands, int idx, int prefix,
334 int argc, const char **argv)
335 {
336 struct command *c = commands;
337 if (argc <= idx + 1)
338 goto no_cmd;
339
340 idx += 1;
341 while (c->name) {
342 if (!strcmp(c->name + prefix, argv[idx])) {
343 int nprefx = prefix + strlen(c->name) + 1;
344 if (argc > 1 && c->subcmd)
345 return run_cmd(c->subcmd, idx, nprefx,
346 argc, argv);
347 else if (c->handler)
348 return c->handler(argc - idx, argv + idx);
349 else
350 print_usage(c->subcmd, idx, nprefx, argc, argv);
351 return -EINVAL;
352 }
353 c++;
354 }
355 idx -= 1; /* last command word was unknown */
356 no_cmd:
357 print_usage(commands, idx, prefix, argc, argv);
358 return -ENOENT;
359 }
360
main(int argc,const char ** argv)361 int main(int argc, const char **argv)
362 {
363 int res = -EINVAL;
364
365 printf("Firmware debug Tool\n");
366
367 res = run_cmd(cmds, 0, 0, argc, argv);
368
369 /* Clean up our flash handlers */
370 if (spi)
371 flash_close(reinterpret_cast<struct flash_device*>(spi));
372 if (ec)
373 flash_close(reinterpret_cast<struct flash_device*>(ec));
374
375 return res;
376 }
377