Home | History | Annotate | Download | only in updater
      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 	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 
    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 
    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 
    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 
    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 
    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 
    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 
    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