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 37 static void *get_spi(void) 38 { 39 if (!spi) 40 spi = flash_open("spi", NULL); 41 42 return spi; 43 } 44 45 static void *get_ec(void) 46 { 47 if (!ec) 48 ec = flash_open("ec", NULL); 49 50 return ec; 51 } 52 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 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 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 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 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 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 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 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 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 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 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 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