diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | Makefile.rules | 3 | ||||
-rw-r--r-- | common/build.mk | 24 | ||||
-rw-r--r-- | include/config.h | 6 | ||||
-rw-r--r-- | util/build.mk | 7 | ||||
-rw-r--r-- | util/gen_emmc_transfer_data.c | 158 |
6 files changed, 202 insertions, 0 deletions
@@ -36,6 +36,10 @@ config=$(out)/.config # If no key file is provided, use the default dev key PEM ?= $(BDIR)/dev_key.pem +# If CONFIG_BOOTBLOCK is set, includes AP-FW bootblock in the EC image. +# If no bootblock is provided, just pack an empty file. +BOOTBLOCK ?= + # If CONFIG_TOUCHPAD_HASH_FW is set, include hashes of a touchpad firmware in # the EC image (if no touchpad firmware is provided, just output blank hashes). TOUCHPAD_FW ?= diff --git a/Makefile.rules b/Makefile.rules index 9ca18284ea..29a1a27b85 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -103,6 +103,9 @@ cmd_link_taskinfo = $(BUILDCC) $(BUILD_CFLAGS) --shared -fPIC $^ \ cmd_tp_hash = $(out)/util/gen_touchpad_hash \ $(if $(TOUCHPAD_FW),-f $(TOUCHPAD_FW)) -o $@ +cmd_emmc_bootblock = $(out)/util/gen_emmc_transfer_data \ + $(if $(BOOTBLOCK),-i $(BOOTBLOCK)) -o $@ + # commands for RSA signature: rwsig does not need to sign the whole image # (it signs the RW part separately). usbpd1 type needs to sign the final image. ifeq ($(CONFIG_RWSIG_TYPE_RWSIG),) diff --git a/common/build.mk b/common/build.mk index 65665993b2..9530586e41 100644 --- a/common/build.mk +++ b/common/build.mk @@ -157,6 +157,30 @@ $(out)/RW/common/rsa.o: CFLAGS+=-O3 $(out)/RO/common/rsa.o: CFLAGS+=-O3 endif +ifneq ($(CONFIG_BOOTBLOCK),) +build-util-bin += gen_emmc_transfer_data + +# Bootblock is only packed in RO image. +$(out)/util/gen_emmc_transfer_data: BUILD_LDFLAGS += -DSECTION_IS_RO +$(out)/bootblock_data.h: $(out)/util/gen_emmc_transfer_data $(out)/.bootblock + $(call quiet,emmc_bootblock,BTBLK ) + +# We only want to repack the bootblock if: $(BOOTBLOCK) variable value has +# changed, or the file pointed at by $(BOOTBLOCK) has changed. We do this +# by recording the latest $(BOOTBLOCK) file information in .bootblock +# TODO: Need a better makefile tricks to do this. + +bootblock_ls := $(shell ls -l "$(BOOTBLOCK)" 2>&1) +old_bootblock_ls := $(shell cat $(out)/.bootblock 2>/dev/null) + +$(out)/.bootblock: $(BOOTBLOCK) + @echo "$(bootblock_ls)" > $@ + +ifneq ($(bootblock_ls),$(old_bootblock_ls)) +.PHONY: $(out)/.bootblock +endif +endif # CONFIG_BOOTBLOCK + ifneq ($(CONFIG_TOUCHPAD_HASH_FW),) $(out)/RO/common/update_fw.o: $(out)/touchpad_fw_hash.h $(out)/RW/common/update_fw.o: $(out)/touchpad_fw_hash.h diff --git a/include/config.h b/include/config.h index d9fbd06fb1..0701a981d3 100644 --- a/include/config.h +++ b/include/config.h @@ -420,6 +420,12 @@ #undef CONFIG_BOOT_HEADER_STORAGE_SIZE /*****************************************************************************/ +/* Bootblock config */ + +/* Pack AP-FW bootblock in EC image. */ +#undef CONFIG_BOOTBLOCK + +/*****************************************************************************/ /* EC has GPIOs to allow board to reset RTC */ #undef CONFIG_BOARD_HAS_RTC_RESET diff --git a/util/build.mk b/util/build.mk index 065528a681..ad9f5656c2 100644 --- a/util/build.mk +++ b/util/build.mk @@ -58,6 +58,13 @@ $(out)/util/%/usb_pd_policy.o: %/usb_pd_policy.c $(call quiet,c_to_vif,BUILDCC) endif # CONFIG_USB_POWER_DELIVERY +ifneq ($(CONFIG_BOOTBLOCK),) +build-util-bin += gen_emmc_transfer_data + +# Bootblock is only packed in RO image. +$(out)/util/gen_emmc_transfer_data: BUILD_LDFLAGS += -DSECTION_IS_RO +endif # CONFIG_BOOTBLOCK + ifneq ($(CONFIG_TOUCHPAD_HASH_FW),) build-util-bin += gen_touchpad_hash diff --git a/util/gen_emmc_transfer_data.c b/util/gen_emmc_transfer_data.c new file mode 100644 index 0000000000..98417beb9b --- /dev/null +++ b/util/gen_emmc_transfer_data.c @@ -0,0 +1,158 @@ +/* Copyright 2018 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. + * + * Generate transferring data from a file. The transferring data emulates the + * eMMC protocol. + */ + +#include <err.h> +#include <errno.h> +#include <getopt.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <compile_time_macros.h> + +/* eMMC transfer block size */ +#define BLOCK_SIZE 512 +#define BLOCK_RAW_DATA "bootblock_raw_data" + +uint16_t crc16_arg(uint8_t data, uint16_t previous_crc) +{ + unsigned int crc = previous_crc << 8; + int i; + + crc ^= (data << 16); + for (i = 8; i; i--) { + if (crc & 0x800000) + crc ^= (0x11021 << 7); + crc <<= 1; + } + + return (uint16_t)(crc >> 8); +} + +void header_format(FILE *fin, FILE *fout) +{ + uint8_t data[BLOCK_SIZE]; + int blk, j; + uint16_t crc16; + size_t cnt = 0; + + fprintf(fout, "/* This file is auto-generated. Do not modify. */\n" + "#ifndef __CROS_EC_BOOTBLOCK_DATA_H\n" + "#define __CROS_EC_BOOTBLOCK_DATA_H\n" + "\n" + "#include <stdint.h>\n" + "\n" + ); + + fprintf(fout, + "static const uint8_t %s[] __attribute__((aligned(4))) =\n" + "{\n" + "\t0xff, 0x97, /* Acknowledge boot mode: 1 S=0 010 E=1 11 */\n" + "\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n", + BLOCK_RAW_DATA); + + for (blk = 0;; blk++) { + crc16 = 0; + if (fin) + cnt = fread(data, 1, BLOCK_SIZE, fin); + + if (cnt == 0) + break; + else if (cnt < BLOCK_SIZE) + memset(&data[cnt], 0xff, BLOCK_SIZE-cnt); + + fprintf(fout, "\t/* Block %d (%ld) */\n", blk, cnt); + fprintf(fout, "\t0xff, 0xfe, /* idle, start bit. */"); + for (j = 0; j < sizeof(data); j++) { + fprintf(fout, "%s0x%02x,", + (j % 8) == 0 ? "\n\t" : " ", data[j]); + crc16 = crc16_arg(data[j], crc16); + } + fprintf(fout, "\n"); + + fprintf(fout, "\t0x%02x, 0x%02x, 0xff," + " /* CRC, end bit, idle */\n", + crc16 >> 8, crc16 & 0xff); + } + + fprintf(fout, "\t/* Last block: idle */\n"); + fprintf(fout, "\t0xff, 0xff, 0xff, 0xff\n"); + fprintf(fout, "};\n"); + fprintf(fout, "#endif /* __CROS_EC_BOOTBLOCK_DATA_H */\n"); +} + +int main(int argc, char **argv) +{ + int nopt; + int ret = 0; + const char *output_name = NULL; + char *input_name = NULL; + FILE *fin = NULL; + FILE *fout = NULL; + + const char short_opts[] = "i:ho:"; + const struct option long_opts[] = { + { "input", 1, NULL, 'i' }, + { "help", 0, NULL, 'h' }, + { "out", 1, NULL, 'o' }, + { NULL } + }; + const char usage[] = "USAGE: %s [-i <input>] -o <output>\n"; + + while ((nopt = getopt_long(argc, argv, short_opts, long_opts, + NULL)) != -1) { + switch (nopt) { + case 'i': /* -i or --input*/ + input_name = optarg; + break; + case 'h': /* -h or --help */ + fprintf(stdout, usage, argv[0]); + return 0; + case 'o': /* -o or --out */ + output_name = optarg; + break; + default: /* Invalid parameter. */ + fprintf(stderr, usage, argv[0]); + return 1; + } + } + + if (output_name == NULL) { + fprintf(stderr, usage, argv[0]); + return 1; + } + + if (input_name == NULL) { + printf("No bootblock provided, outputting default file.\n"); + } else { + fin = fopen(input_name, "r"); + if (!fin) { + printf("Cannot open input file: %s\n", input_name); + ret = 1; + goto out; + } + } + + fout = fopen(output_name, "w"); + + if (!fout) { + printf("Cannot open output file: %s\n", output_name); + ret = 1; + goto out; + } + + header_format(fin, fout); + + fclose(fout); + +out: + if (fin) + fclose(fin); + + return ret; +} |