From fbfd828b9a28f4e91fc100ef9e474f590acc7989 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 30 May 2012 20:14:14 +0000 Subject: simple and self-contained EC flashing tool This produces a host binary running on the application processor and which is able to re-flash th EC firmware over the AP-to-EC link (either LPC or I2C). The payload (ie the EC firmware) to use is embedded inside the flasher binary. This is just aimed at testing and developer upgrade. The auto-update flow is using flashrom. Signed-off-by: Vincent Palatin BUG=None TEST=build for link/daisy/snow/bds and tests On Snow, run burn_my_ec from the serial console and see that the EC was correctly re-flashed. Change-Id: I7f90e773678a7ef3d8dc6dbacf54e80f3294607b Reviewed-on: https://gerrit.chromium.org/gerrit/24236 Reviewed-by: David Hendricks Tested-by: Vincent Palatin Reviewed-by: Randall Spangler Commit-Ready: Vincent Palatin --- Makefile.rules | 6 ++- Makefile.toolchain | 3 +- util/build.mk | 2 +- util/burn_my_ec.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 util/burn_my_ec.c diff --git a/Makefile.rules b/Makefile.rules index 152a50e6e9..7b3274f914 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -30,14 +30,14 @@ cmd_lds = $(CPP) -P -C -MMD -MF $@.d -MT $@ $(CPPFLAGS) \ -DSECTION=$(call section,$*) $< -o $@ cmd_obj_to_bin = $(OBJCOPY) --gap-fill=0xff -O binary $^ $@ cmd_flat_to_obj = $(CC) -T $(out)/firmware_image.lds -nostdlib $(CPPFLAGS) \ - -DPROJECT=$* -Wl,--build-id=none -o $@ $< + -Wl,--build-id=none -o $@ $< cmd_elf_to_flat = $(OBJCOPY) -O binary $^ $@ cmd_elf_to_dis = $(OBJDUMP) -D $< > $@ cmd_elf = $(LD) $(LDFLAGS) $(objs) -o $@ -T $< -Map $(out)/$*.map cmd_c_to_o = $(CC) $(CFLAGS) -MMD -MF $@.d -c $< -o $@ cmd_c_to_build = $(BUILDCC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) \ -MMD -MF $@.d $< -o $@ -cmd_c_to_host = $(HOSTCC) $(HOST_CFLAGS) -MMD -MF $@.d $^ -o $@ +cmd_c_to_host = $(HOSTCC) $(HOST_CFLAGS) -MMD -MF $@.d $(filter %.c, $^) -o $@ cmd_qemu = ./util/run_qemu_test --image=build/$(BOARD)/$*/$*.bin test/$*.py \ $(silent) cmd_version = ./util/getversion.sh > $@ @@ -123,6 +123,8 @@ $(build-utils): $(out)/%:%.c $(host-utils): $(out)/%:%.c $(foreach u,$(host-util-common),util/$(u).c) $(call quiet,c_to_host,HOSTCC ) +$(out)/util/burn_my_ec: $(out)/$(PROJECT).bin + .PHONY: clean clean: -rm -rf $(out) diff --git a/Makefile.toolchain b/Makefile.toolchain index 49912e090d..ddf8452210 100644 --- a/Makefile.toolchain +++ b/Makefile.toolchain @@ -27,7 +27,8 @@ CFLAGS_DEBUG= -g CFLAGS_INCLUDE=$(foreach i,$(includes),-I$(i) ) CFLAGS_DEFINE=-DOUTDIR=$(out) -DCHIP=$(CHIP) -DTASKFILE=$(PROJECT).tasklist \ -DBOARD=$(BOARD) -DBOARD_$(BOARD) -DCORE=$(CORE) -DCHIP_$(CHIP) \ - -DCHIP_VARIANT=$(CHIP_VARIANT) -DCHIP_VARIANT_$(CHIP_VARIANT) + -DCHIP_VARIANT=$(CHIP_VARIANT) -DCHIP_VARIANT_$(CHIP_VARIANT) \ + -DPROJECT=$(PROJECT) CPPFLAGS=$(CFLAGS_DEFINE) $(CFLAGS_INCLUDE) $(EXTRA_CFLAGS) CFLAGS=$(CPPFLAGS) $(CFLAGS_CPU) $(CFLAGS_DEBUG) $(CFLAGS_WARN) $(CFLAGS_y) BUILD_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN) diff --git a/util/build.mk b/util/build.mk index 28257b5903..fc021471f2 100644 --- a/util/build.mk +++ b/util/build.mk @@ -6,7 +6,7 @@ # Host tools build # -host-util-bin=ectool lbplay +host-util-bin=ectool lbplay burn_my_ec ifeq ($(CONFIG_LPC),y) host-util-common=comm-lpc else diff --git a/util/burn_my_ec.c b/util/burn_my_ec.c new file mode 100644 index 0000000000..27a921123a --- /dev/null +++ b/util/burn_my_ec.c @@ -0,0 +1,148 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "comm-host.h" +#include "ec_commands.h" +#include "system.h" + +#define STR0(name) #name +#define STR(name) STR0(name) + +static const char * const part_name[] = {"unknown", "RO", "A", "B"}; + +enum ec_current_image get_version(void) +{ + struct ec_response_get_version r; + struct ec_response_get_build_info r2; + int res; + + res = ec_command(EC_CMD_GET_VERSION, NULL, 0, &r, sizeof(r)); + if (res) + return res; + res = ec_command(EC_CMD_GET_BUILD_INFO, + NULL, 0, &r2, sizeof(r2)); + if (res) + return res; + + /* Ensure versions are null-terminated before we print them */ + r.version_string_ro[sizeof(r.version_string_ro) - 1] = '\0'; + r.version_string_rw_a[sizeof(r.version_string_rw_a) - 1] = '\0'; + r.version_string_rw_b[sizeof(r.version_string_rw_b) - 1] = '\0'; + r2.build_string[sizeof(r2.build_string) - 1] = '\0'; + + /* Print versions */ + printf("RO version: %s\n", r.version_string_ro); + printf("RW-A version: %s\n", r.version_string_rw_a); + printf("RW-B version: %s\n", r.version_string_rw_b); + printf("Firmware copy: %s\n", + (r.current_image < sizeof(part_name)/sizeof(part_name[0]) ? + part_name[r.current_image] : "?")); + printf("Build info: %s\n", r2.build_string); + + return r.current_image; +} + +int flash_partition(enum ec_current_image part, const uint8_t *payload, + uint32_t offset, uint32_t size) +{ + struct ec_params_reboot_ec rst_req; + struct ec_params_flash_erase er_req; + struct ec_params_flash_write wr_req; + struct ec_params_flash_read rd_req; + struct ec_response_flash_read rd_resp; + int res; + uint32_t i; + enum ec_current_image current; + + current = get_version(); + if (current == part) { + rst_req.target = part == EC_IMAGE_RO ? + EC_IMAGE_RW_A : EC_IMAGE_RO; + ec_command(EC_CMD_REBOOT_EC, &rst_req, sizeof(rst_req), + NULL, 0); + /* wait EC reboot */ + usleep(500000); + } + + printf("Erasing partition %s : 0x%x bytes at 0x%08x\n", + part_name[part], size, offset); + er_req.size = size; + er_req.offset = offset; + res = ec_command(EC_CMD_FLASH_ERASE, &er_req, sizeof(er_req), NULL, 0); + if (res) { + fprintf(stderr, "Erase failed : %d\n", res); + return -1; + } + + printf("Writing partition %s : 0x%x bytes at 0x%08x\n", + part_name[part], size, offset); + /* Write data in chunks */ + for (i = 0; i < size; i += EC_FLASH_SIZE_MAX) { + wr_req.offset = offset + i; + wr_req.size = MIN(size - i, EC_FLASH_SIZE_MAX); + memcpy(wr_req.data, payload + i, wr_req.size); + res = ec_command(EC_CMD_FLASH_WRITE, &wr_req, sizeof(wr_req), + NULL, 0); + if (res) { + fprintf(stderr, "Write error at 0x%08x : %d\n", i, res); + return -1; + } + } + + printf("Verifying partition %s : 0x%x bytes at 0x%08x\n", + part_name[part], size, offset); + /* Read data in chunks */ + for (i = 0; i < size; i += EC_FLASH_SIZE_MAX) { + rd_req.offset = offset + i; + rd_req.size = MIN(size - i, EC_FLASH_SIZE_MAX); + res = ec_command(EC_CMD_FLASH_READ, &rd_req, sizeof(rd_req), + &rd_resp, sizeof(rd_resp)); + if (res) { + fprintf(stderr, "Read error at 0x%08x : %d\n", i, res); + return -1; + } + if (memcmp(payload + i, rd_resp.data, rd_req.size)) + fprintf(stderr, "ERR: @%08x->%08x\n", + offset + i, offset + i + size); + } + printf("Done.\n"); + get_version(); + + return 0; +} + +/* black magic to include the EC firmware binary as a payload inside + * the flashing program without relying on external tools such as objcopy or a + * binary to header converter. */ +__asm__ (".section .payload, \"ax\"\n" + "_payload_start:\n" + ".incbin \""STR(OUTDIR)"/"STR(PROJECT)".bin\"\n"); + +int main(int argc, char *argv[]) +{ + extern uint8_t data[] asm("_payload_start"); + + if (comm_init() < 0) + return -3; + +#ifndef CONFIG_NO_RW_B + flash_partition(EC_IMAGE_RW_B, data + CONFIG_FW_B_OFF, + CONFIG_FW_B_OFF, CONFIG_FW_B_SIZE); +#endif /* !CONFIG_NO_RW_B */ + flash_partition(EC_IMAGE_RW_A, data + CONFIG_FW_A_OFF, + CONFIG_FW_A_OFF, CONFIG_FW_A_SIZE); + flash_partition(EC_IMAGE_RO, data + CONFIG_FW_RO_OFF, + CONFIG_FW_RO_OFF, CONFIG_FW_RO_SIZE); + + return 0; +} -- cgit v1.2.1