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 	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