diff options
28 files changed, 565 insertions, 109 deletions
diff --git a/arch/arm/boards/nxp-imx8mq-evk/Makefile b/arch/arm/boards/nxp-imx8mq-evk/Makefile index 0546b0b078..7907de411f 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/Makefile +++ b/arch/arm/boards/nxp-imx8mq-evk/Makefile @@ -1,4 +1,2 @@ obj-y += board.o -lwl-y += lowlevel.o ddr_init.o ddrphy_train.o - - +lwl-y += lowlevel.o ddr_init.o ddrphy_train.o trampoline.o diff --git a/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg b/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg index aff8321b9a..11463fe850 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg +++ b/arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg @@ -3,3 +3,4 @@ soc imx8mq loadaddr 0x007E1000 max_load_size 0x3F000 dcdofs 0x400 +#include <mach/habv4-imx8-gencsf.h> diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c index e3fdc64edf..a74171e5e5 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c +++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c @@ -53,76 +53,89 @@ static void setup_uart(void) static void nxp_imx8mq_evk_sram_setup(void) { - enum bootsource src = BOOTSOURCE_UNKNOWN; - int instance = BOOTSOURCE_INSTANCE_UNKNOWN; - int ret = -ENOTSUPP; - ddr_init(); +} - imx8_get_boot_source(&src, &instance); +extern unsigned char trampoline_start[]; +extern unsigned char trampoline_end[]; - if (src == BOOTSOURCE_MMC) - ret = imx8_esdhc_start_image(instance); +static void nxp_imx8mq_evk_install_tfa_trampoline(void) +{ + unsigned int tramp_len; + unsigned int offset; + /* + * Create a trampoline which is places in DRAM and calls back into the + * PBL entry function found in the TCRAM. Register x0 is set to 1 to + * indicate that DRAM setup was already run. + */ + tramp_len = (void *)trampoline_end - (void *)trampoline_start; + memcpy((void *)MX8MQ_ATF_BL33_BASE_ADDR, (void *)trampoline_start, + tramp_len); - BUG_ON(ret); + offset = get_runtime_offset(); + memcpy((void *)MX8MQ_ATF_BL33_BASE_ADDR + tramp_len, &offset, + sizeof(offset)); } +/* + * Power-on execution flow of start_nxp_imx8mq_evk() might not be + * obvious for a very first read, so here's, hopefully helpful, + * summary: + * + * 1. MaskROM uploads PBL into OCRAM and that's where this function is + * executed for the first time + * + * 2. DDR is initialized and the TF-A trampoline is installed in the + * DRAM. + * + * 3. TF-A is executed and exits into the trampoline in RAM, which enters the + * PBL for the second time. DRAM setup done is indicated by a one in register + * x0 by the trampoline + * + * 4. The piggydata is loaded from the SD card and copied to the expected + * location in the DRAM. + * + * 5. Standard barebox boot flow continues + */ static __noreturn noinline void nxp_imx8mq_evk_start(void) { + enum bootsource src = BOOTSOURCE_UNKNOWN; + int instance = BOOTSOURCE_INSTANCE_UNKNOWN; + int ret = -ENOTSUPP; + const u8 *bl31; + size_t bl31_size; + + imx8mq_cpu_lowlevel_init(); + if (IS_ENABLED(CONFIG_DEBUG_LL)) setup_uart(); - if (get_pc() < MX8MQ_DDR_CSD1_BASE_ADDR) { - /* - * We assume that we were just loaded by MaskROM into - * SRAM if we are not running from DDR. We also assume - * that means DDR needs to be initialized for the - * first time. - */ - nxp_imx8mq_evk_sram_setup(); - } /* - * Straight from the power-on we are at EL3, so the following - * code _will_ load and jump to ATF. - * - * However when we are re-executed upon exit from ATF's - * initialization routine, it is EL2 which means we'll skip - * loadting ATF blob again + * if register r0 does not contain 1, we are running for the first time + * and need to initialize the DRAM, install the trampoline and run TF-A + * (BL31). + * Otherwise the 1 indicates that the DRAM setup and trampoline are + * already installed and TF-A has been run. In this case we can skip */ if (current_el() == 3) { - const u8 *bl31; - size_t bl31_size; - + nxp_imx8mq_evk_sram_setup(); + nxp_imx8mq_evk_install_tfa_trampoline(); get_builtin_firmware(imx8mq_bl31_bin, &bl31, &bl31_size); imx8mq_atf_load_bl31(bl31, bl31_size); } + imx8_get_boot_source(&src, &instance); + + if (src == BOOTSOURCE_MMC) + ret = imx8_esdhc_load_piggy(instance); + else + BUG_ON(ret); /* * Standard entry we hit once we initialized both DDR and ATF */ imx8mq_barebox_entry(__dtb_imx8mq_evk_start); } -/* - * Power-on execution flow of start_nxp_imx8mq_evk() might not be - * obvious for a very first read, so here's, hopefully helpful, - * summary: - * - * 1. MaskROM uploads PBL into OCRAM and that's where this function is - * executed for the first time - * - * 2. DDR is initialized and full i.MX image is loaded to the - * beginning of RAM - * - * 3. start_nxp_imx8mq_evk, now in RAM, is executed again - * - * 4. BL31 blob is uploaded to OCRAM and the control is transfer to it - * - * 5. BL31 exits EL3 into EL2 at address MX8MQ_ATF_BL33_BASE_ADDR, - * executing start_nxp_imx8mq_evk() the third time - * - * 6. Standard barebox boot flow continues - */ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) { imx8mq_cpu_lowlevel_init(); @@ -132,4 +145,3 @@ ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) nxp_imx8mq_evk_start(); } - diff --git a/arch/arm/boards/nxp-imx8mq-evk/trampoline.S b/arch/arm/boards/nxp-imx8mq-evk/trampoline.S new file mode 100644 index 0000000000..54a1b76518 --- /dev/null +++ b/arch/arm/boards/nxp-imx8mq-evk/trampoline.S @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0) */ +#include <linux/linkage.h> +#include <asm/sections.h> + .section .trampoline,"a" + .globl trampoline_start +trampoline_start: + ldr w19, trampoline_end + br x19 + .globl trampoline_end +trampoline_end: diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c index 4f16af22f8..9cc3b358b0 100644 --- a/arch/arm/cpu/uncompress.c +++ b/arch/arm/cpu/uncompress.c @@ -42,14 +42,18 @@ unsigned long free_mem_end_ptr; extern unsigned char input_data[]; extern unsigned char input_data_end[]; +extern unsigned char sha_sum[]; +extern unsigned char sha_sum_end[]; + void __noreturn barebox_multi_pbl_start(unsigned long membase, unsigned long memsize, void *boarddata) { - uint32_t pg_len, uncompressed_len; + uint32_t pg_len, uncompressed_len, pbl_hash_len; void __noreturn (*barebox)(unsigned long, unsigned long, void *); unsigned long endmem = membase + memsize; unsigned long barebox_base; void *pg_start, *pg_end; + void *pbl_hash_start, *pbl_hash_end; unsigned long pc = get_pc(); pg_start = input_data + global_variable_offset(); @@ -92,6 +96,17 @@ void __noreturn barebox_multi_pbl_start(unsigned long membase, pr_debug("uncompressing barebox binary at 0x%p (size 0x%08x) to 0x%08lx (uncompressed size: 0x%08x)\n", pg_start, pg_len, barebox_base, uncompressed_len); + if (IS_ENABLED(CONFIG_PBL_VERIFY_PIGGY)) { + pbl_hash_start = sha_sum; + pbl_hash_end = sha_sum_end; + pbl_hash_len = pbl_hash_end - pbl_hash_start; + if (pbl_barebox_verify(pg_start, pg_len, pbl_hash_start, + pbl_hash_len) != 0) { + putc_ll('!'); + panic("hash mismatch, refusing to decompress"); + } + } + pbl_barebox_uncompress((void*)barebox_base, pg_start, pg_len); sync_caches_for_execution(); diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S index 300671bb51..01ed384495 100644 --- a/arch/arm/lib/pbl.lds.S +++ b/arch/arm/lib/pbl.lds.S @@ -68,6 +68,13 @@ SECTIONS . = ALIGN(4); .data : { *(.data*) } + . = ALIGN(4); + __shasum_start = .; + .shasum : { + KEEP(*(.shasum)) + } + __shasum_end = .; + .rel_dyn_start : { *(.__rel_dyn_start) } #ifdef CONFIG_CPU_32 .rel.dyn : { *(.rel*) } @@ -90,6 +97,16 @@ SECTIONS pbl_memory_size = . - BASE; +#if defined(CONFIG_CPU_64) && defined(CONFIG_HABV4) + . = ALIGN(0x1000); + __csf_start = .; + .hab_csf : { + BYTE(0x5a); + . += + 0x1fff; + } = 0x5a + __csf_end = .; +#endif /* CONFIG_CPU_64 && CONFIG_HABV4 */ + . = ALIGN(4); __piggydata_start = .; .piggydata : { diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 553d11a793..e7721621ab 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -183,6 +183,7 @@ config ARCH_IMX8MQ select COMMON_CLK_OF_PROVIDER select ARCH_HAS_FEC_IMX select HW_HAS_PCI + select PBL_VERIFY_PIGGY if HABV4 config ARCH_VF610 bool @@ -787,10 +788,10 @@ config HABV4 select HAB select NVMEM select IMX_OCOTP - depends on ARCH_IMX6 + depends on ARCH_IMX6 || ARCH_IMX8MQ depends on OFDEVICE help - High Assurance Boot, as found on i.MX28/i.MX6. + High Assurance Boot, as found on i.MX28/i.MX6/i.MX8MQ. config HAB_CERTS_ENV depends on HAB diff --git a/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h b/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h new file mode 100644 index 0000000000..34039ee590 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h @@ -0,0 +1,59 @@ +/* + * This snippet can be included from a i.MX flash header configuration + * file for generating signed images. The necessary keys/certificates + * are expected in these config variables: + * + * CONFIG_HABV4_TABLE_BIN + * CONFIG_HABV4_CSF_CRT_PEM + * CONFIG_HABV4_IMG_CRT_PEM + */ +#if defined(CONFIG_HABV4) && defined(CONFIG_CPU_64) +hab [Header] +hab Version = 4.3 +hab Hash Algorithm = sha256 +hab Engine Configuration = 0 +hab Certificate Format = X509 +hab Signature Format = CMS +hab Engine = CAAM + +hab [Install SRK] +hab File = CONFIG_HABV4_TABLE_BIN +hab # SRK index within SRK-Table 0..3 +hab Source index = 0 + +hab [Install CSFK] +/* target key index in keystore 1 */ +hab File = CONFIG_HABV4_CSF_CRT_PEM + +hab [Authenticate CSF] + +hab [Unlock] +hab Engine = CAAM +hab Features = RNG + +hab [Install Key] +/* verification key index in key store (0, 2...4) */ +hab Verification index = 0 +/* target key index in key store (2...4) */ +hab Target index = 2 +hab File = CONFIG_HABV4_IMG_CRT_PEM + +hab [Authenticate Data] +/* verification key index in key store (2...4) */ +hab Verification index = 2 + +hab_blocks + +hab_encrypt [Install Secret Key] +hab_encrypt Verification index = 0 +hab_encrypt Target index = 0 +hab_encrypt_key +hab_encrypt_key_length 256 +hab_encrypt_blob_address + +hab_encrypt [Decrypt Data] +hab_encrypt Verification index = 0 +hab_encrypt Mac Bytes = 16 + +hab_encrypt_blocks +#endif diff --git a/arch/arm/mach-imx/include/mach/imx-header.h b/arch/arm/mach-imx/include/mach/imx-header.h index 50584bb24b..dc8e2eee2f 100644 --- a/arch/arm/mach-imx/include/mach/imx-header.h +++ b/arch/arm/mach-imx/include/mach/imx-header.h @@ -98,6 +98,7 @@ struct config_data { uint32_t image_size; uint32_t max_load_size; uint32_t load_size; + uint32_t pbl_code_size; char *outfile; char *srkfile; int header_version; @@ -111,6 +112,7 @@ struct config_data { int (*nop)(const struct config_data *data); int csf_space; char *csf; + int sign_image; char *signed_hdmi_firmware_file; int encrypt_image; size_t dek_size; diff --git a/arch/arm/mach-imx/include/mach/xload.h b/arch/arm/mach-imx/include/mach/xload.h index 8f141bc37e..a605e76339 100644 --- a/arch/arm/mach-imx/include/mach/xload.h +++ b/arch/arm/mach-imx/include/mach/xload.h @@ -6,7 +6,12 @@ int imx6_spi_load_image(int instance, unsigned int flash_offset, void *buf, int int imx6_spi_start_image(int instance); int imx6_esdhc_start_image(int instance); int imx8_esdhc_start_image(int instance); +int imx8_esdhc_load_piggy(int instance); int imx_image_size(void); +int piggydata_size(void); + +extern unsigned char input_data[]; +extern unsigned char input_data_end[]; #endif /* __MACH_XLOAD_H */ diff --git a/arch/arm/mach-imx/xload-common.c b/arch/arm/mach-imx/xload-common.c index c5727eba38..bd6405258e 100644 --- a/arch/arm/mach-imx/xload-common.c +++ b/arch/arm/mach-imx/xload-common.c @@ -8,3 +8,9 @@ int imx_image_size(void) /* i.MX header is 4k */ return barebox_image_size + SZ_4K; } + +int piggydata_size(void) +{ + return input_data_end - input_data; +} + diff --git a/crypto/Makefile b/crypto/Makefile index 3402f57255..d6fb74aad9 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -8,6 +8,8 @@ obj-$(CONFIG_DIGEST_MD5_GENERIC) += md5.o obj-$(CONFIG_DIGEST_SHA1_GENERIC) += sha1.o obj-$(CONFIG_DIGEST_SHA224_GENERIC) += sha2.o obj-$(CONFIG_DIGEST_SHA256_GENERIC) += sha2.o +pbl-$(CONFIG_PBL_VERIFY_PIGGY) += sha2.o +pbl-$(CONFIG_PBL_VERIFY_PIGGY) += digest.o obj-$(CONFIG_DIGEST_SHA384_GENERIC) += sha4.o obj-$(CONFIG_DIGEST_SHA512_GENERIC) += sha4.o diff --git a/crypto/sha2.c b/crypto/sha2.c index c62ddb8d25..3947a09f41 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -27,6 +27,7 @@ #include <crypto/sha.h> #include <crypto/internal.h> +#include <crypto/pbl-sha.h> static inline u32 Ch(u32 x, u32 y, u32 z) { @@ -232,7 +233,7 @@ static int sha224_init(struct digest *desc) return 0; } -static int sha256_init(struct digest *desc) +int sha256_init(struct digest *desc) { struct sha256_state *sctx = digest_ctx(desc); sctx->state[0] = SHA256_H0; @@ -248,7 +249,7 @@ static int sha256_init(struct digest *desc) return 0; } -static int sha256_update(struct digest *desc, const void *data, +int sha256_update(struct digest *desc, const void *data, unsigned long len) { struct sha256_state *sctx = digest_ctx(desc); @@ -280,7 +281,7 @@ static int sha256_update(struct digest *desc, const void *data, return 0; } -static int sha256_final(struct digest *desc, u8 *out) +int sha256_final(struct digest *desc, u8 *out) { struct sha256_state *sctx = digest_ctx(desc); __be32 *dst = (__be32 *)out; @@ -348,7 +349,7 @@ static int sha224_digest_register(void) } device_initcall(sha224_digest_register); -static struct digest_algo m256 = { +struct digest_algo m256 = { .base = { .name = "sha256", .driver_name = "sha256-generic", @@ -365,6 +366,7 @@ static struct digest_algo m256 = { .ctx_length = sizeof(struct sha256_state), }; +#ifndef __PBL__ static int sha256_digest_register(void) { if (!IS_ENABLED(CONFIG_SHA256)) @@ -373,3 +375,4 @@ static int sha256_digest_register(void) return digest_algo_register(&m256); } coredevice_initcall(sha256_digest_register); +#endif /* __PBL__ */ diff --git a/drivers/hab/hab.c b/drivers/hab/hab.c index 03bb65e0fa..a346e01567 100644 --- a/drivers/hab/hab.c +++ b/drivers/hab/hab.c @@ -217,7 +217,7 @@ static struct imx_hab_ops *imx_get_hab_ops(void) if (IS_ENABLED(CONFIG_HABV3) && (cpu_is_mx25() || cpu_is_mx35())) tmp = &imx_hab_ops_iim; - else if (IS_ENABLED(CONFIG_HABV4) && cpu_is_mx6()) + else if (IS_ENABLED(CONFIG_HABV4) && (cpu_is_mx6() || cpu_is_mx8mq())) tmp = &imx_hab_ops_ocotp; else return NULL; diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c index a53e40ad23..e3c1de1a4d 100644 --- a/drivers/hab/habv4.c +++ b/drivers/hab/habv4.c @@ -22,8 +22,11 @@ #include <hab.h> #include <init.h> #include <types.h> +#include <linux/arm-smccc.h> +#include <asm/cache.h> #include <mach/generic.h> +#include <mach/imx8mq.h> #define HABV4_RVT_IMX28 0xffff8af8 #define HABV4_RVT_IMX6_OLD 0x00000094 @@ -177,6 +180,92 @@ struct habv4_rvt { void (*failsafe)(void); } __packed; +#define FSL_SIP_HAB 0xC2000007 +#define FSL_SIP_HAB_AUTHENTICATE 0x00 +#define FSL_SIP_HAB_ENTRY 0x01 +#define FSL_SIP_HAB_EXIT 0x02 +#define FSL_SIP_HAB_REPORT_EVENT 0x03 +#define FSL_SIP_HAB_REPORT_STATUS 0x04 +#define FSL_SIP_HAB_FAILSAFE 0x05 +#define FSL_SIP_HAB_CHECK_TARGET 0x06 + +static enum hab_status hab_sip_report_status(enum hab_config *config, + enum hab_state *state) +{ + struct arm_smccc_res res; + + if (state) + v8_flush_dcache_range((unsigned long)state, + (unsigned long)state + sizeof(*config)); + if (config) + v8_flush_dcache_range((unsigned long)config, + (unsigned long)config + sizeof(*state)); + + arm_smccc_smc(FSL_SIP_HAB, FSL_SIP_HAB_REPORT_STATUS, + (unsigned long) config, + (unsigned long) state, 0, 0, 0, 0, &res); + if (state) + v8_inv_dcache_range((unsigned long)state, + (unsigned long)state + sizeof(*config)); + if (config) + v8_inv_dcache_range((unsigned long)config, + (unsigned long)config + sizeof(*state)); + return (enum hab_status)res.a0; +} + +static enum hab_status imx8_read_sram_events(enum hab_status status, + uint32_t index, void *event, + uint32_t *bytes) +{ + struct hab_event_record *events[10]; + int num_events = 0; + char *sram = (char *)0x9061c0; + int i = 0; + int internal_index = 0; + char *end = 0; + struct hab_event_record *search; + + /* + * AN12263 HABv4 Guidelines and Recommendations + * recommends the address and size, however errors are usually contained + * within the first bytes. Scan only the first few bytes to rule out + * lots of false positives. + */ + end = sram + 0x1a0; + + while (sram < end) { + if (*sram == 0xdb) { + search = (void *)sram; + sram = sram + be16_to_cpu(search->hdr.len); + events[num_events] = search; + num_events++; + } else { + sram++; + } + } + while (i < num_events) { + if (events[i]->status == status) { + if (internal_index == index) { + *bytes = sizeof(struct hab_event_record) + + be16_to_cpu(events[i]->hdr.len); + if (event) + memcpy(event, events[i], *bytes); + return HAB_STATUS_SUCCESS; + } else { + internal_index++; + } + } + i++; + } + return HAB_STATUS_FAILURE; +} + +struct habv4_rvt hab_smc_ops = { + .header = { .tag = 0xdd }, + .report_event = imx8_read_sram_events, + .report_status = hab_sip_report_status, +}; + static const char *habv4_get_status_str(enum hab_status status) { switch (status) { @@ -496,23 +585,46 @@ int imx6_hab_get_status(void) return -EINVAL; } -static int init_imx6_hab_get_status(void) +static int imx8_hab_get_status(void) { - int ret = 0; + return habv4_get_status(&hab_smc_ops); +} - if (!cpu_is_mx6()) +static int init_imx8_hab_get_status(void) +{ + if (!cpu_is_mx8mq()) /* can happen in multi-image builds and is not an error */ return 0; - ret = imx6_hab_get_status(); - /* * Nobody will check the return value if there were HAB errors, but the * initcall will fail spectaculously with a strange error message. */ - if (ret == -EPERM) + imx8_hab_get_status(); + + return 0; +} + +/* + * + * + * + */ +postmmu_initcall(init_imx8_hab_get_status); + +static int init_imx6_hab_get_status(void) +{ + if (!cpu_is_mx6()) + /* can happen in multi-image builds and is not an error */ return 0; - return ret; + + /* + * Nobody will check the return value if there were HAB errors, but the + * initcall will fail spectaculously with a strange error message. + */ + imx6_hab_get_status(); + + return 0; } /* @@ -531,19 +643,15 @@ int imx28_hab_get_status(void) static int init_imx28_hab_get_status(void) { - int ret = 0; - if (!cpu_is_mx28()) /* can happen in multi-image builds and is not an error */ return 0; - ret = imx28_hab_get_status(); /* nobody will check the return value if there were HAB errors, but the * initcall will fail spectaculously with a strange error message. */ - if (ret == -EPERM) - return 0; - return ret; + imx28_hab_get_status(); + return 0; } /* i.MX28 ROM code can be run after MMU setup to make use of caching */ postmmu_initcall(init_imx28_hab_get_status); diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c index 367daa85a6..fb27c84163 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -243,27 +243,22 @@ static int esdhc_read_blocks(struct esdhc *esdhc, void *dst, size_t len) } #ifdef CONFIG_ARCH_IMX -static int -esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry, u32 offset) +static int esdhc_search_header(struct esdhc *esdhc, + struct imx_flash_header_v2 **header_pointer, + void *buffer, u32 *offset) { - - void *buf = (void *)address; - struct imx_flash_header_v2 *hdr; - int ret, len; - void __noreturn (*bb)(void); - unsigned int ofs; + int ret; int i, header_count = 1; - - len = imx_image_size(); - len = ALIGN(len, SECTOR_SIZE); + void *buf = buffer; + struct imx_flash_header_v2 *hdr; for (i = 0; i < header_count; i++) { ret = esdhc_read_blocks(esdhc, buf, - offset + SZ_1K + SECTOR_SIZE); + *offset + SZ_1K + SECTOR_SIZE); if (ret) return ret; - hdr = buf + offset + SZ_1K; + hdr = buf + *offset + SZ_1K; if (!is_imx_flash_header_v2(hdr)) { pr_debug("IVT header not found on SD card. " @@ -286,10 +281,31 @@ esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry, u32 o * this time skipping anything HDMI firmware * related. */ - offset += hdr->boot_data.size + hdr->header.length; + *offset += hdr->boot_data.size + hdr->header.length; header_count++; } } + *header_pointer = hdr; + return 0; +} + +static int +esdhc_start_image(struct esdhc *esdhc, ptrdiff_t address, ptrdiff_t entry, + u32 offset) +{ + + void *buf = (void *)address; + struct imx_flash_header_v2 *hdr = NULL; + int ret, len; + void __noreturn (*bb)(void); + unsigned int ofs; + + len = imx_image_size(); + len = ALIGN(len, SECTOR_SIZE); + + ret = esdhc_search_header(esdhc, &hdr, buf, &offset); + if (ret) + return ret; pr_debug("Check ok, loading image\n"); @@ -409,6 +425,52 @@ int imx8_esdhc_start_image(int instance) return esdhc_start_image(&esdhc, MX8MQ_DDR_CSD1_BASE_ADDR, MX8MQ_ATF_BL33_BASE_ADDR, SZ_32K); } + +int imx8_esdhc_load_piggy(int instance) +{ + void *buf = (void *)MX8MQ_ATF_BL33_BASE_ADDR; + struct imx_flash_header_v2 *hdr = NULL; + void *bb = 0; + struct esdhc esdhc; + int ret, len; + int offset = SZ_32K; + + + switch (instance) { + case 0: + esdhc.regs = IOMEM(MX8MQ_USDHC1_BASE_ADDR); + break; + case 1: + esdhc.regs = IOMEM(MX8MQ_USDHC2_BASE_ADDR); + break; + default: + return -EINVAL; + } + + esdhc.is_be = 0; + esdhc.is_mx6 = 1; + + ret = esdhc_search_header(&esdhc, &hdr, buf, &offset); + if (ret) + return ret; + + len = offset + hdr->boot_data.size + piggydata_size(); + len = ALIGN(len, SECTOR_SIZE); + + ret = esdhc_read_blocks(&esdhc, buf, len); + + /* + * Calculate location of the piggydata at the offset loaded into RAM + */ + buf = buf + offset + hdr->boot_data.size; + /* + * Barebox expects the piggydata right behind the PBL in the beginning + * of RAM. + */ + bb = (void *) MX8MQ_DDR_CSD1_BASE_ADDR + barebox_pbl_size; + memcpy(bb, buf, piggydata_size()); + return ret; +} #endif #ifdef CONFIG_ARCH_LS1046 diff --git a/images/Makefile b/images/Makefile index 293e644319..907986e2d0 100644 --- a/images/Makefile +++ b/images/Makefile @@ -57,11 +57,12 @@ quiet_cmd_elf__ ?= LD $@ cmd_elf__ ?= $(LD) $(LDFLAGS_barebox) --gc-sections \ -e $(2) -Map $@.map $(LDFLAGS_$(@F)) -o $@ \ -T $(pbl-lds) \ - --start-group $(barebox-pbl-common) $(obj)/piggy.o --end-group + --start-group $(barebox-pbl-common) $(obj)/piggy.o \ + $(obj)/sha_sum.o --end-group PBL_CPPFLAGS += -fdata-sections -ffunction-sections -$(obj)/%.pbl: $(pbl-lds) $(barebox-pbl-common) $(obj)/piggy.o FORCE +$(obj)/%.pbl: $(pbl-lds) $(barebox-pbl-common) $(obj)/piggy.o $(obj)/sha_sum.o FORCE $(call if_changed,elf__,$(*F)) $(obj)/%.pblb: $(obj)/%.pbl FORCE @@ -111,6 +112,21 @@ suffix_$(CONFIG_IMAGE_COMPRESSION_NONE) = comp_copy $(obj)/piggy.o: $(obj)/barebox.z FORCE +$(obj)/sha_sum.o: $(obj)/barebox.sha.bin FORCE + +quiet_cmd_sha256bin ?= SHA-BIN $@ + cmd_sha256bin ?= printf "$(shell awk '{printf $$1}' < $(obj)/barebox.sum | sed -e 's/../\\x&/g' )" > $@ + +quiet_cmd_sha256sum ?= SHA $@ + cmd_sha256sum ?= sha256sum $(obj)/barebox.z > $@ + +$(obj)/barebox.sha.bin: $(obj)/barebox.sum FORCE + $(call if_changed,sha256bin) + +$(obj)/barebox.sum: $(obj)/barebox.z FORCE + $(call if_changed,sha256sum) + + # barebox.z - compressed barebox binary # ---------------------------------------------------------------- $(obj)/barebox.z: $(obj)/../barebox.bin FORCE @@ -152,7 +168,7 @@ ifneq ($(pblx-y)$(pblx-),) $(error pblx- has been removed. Please use pblb- instead.) endif -targets += $(image-y) pbl.lds barebox.x barebox.z piggy.o +targets += $(image-y) pbl.lds barebox.x barebox.z piggy.o sha_sum.o barebox.sha.bin barebox.sum targets += $(patsubst %,%.pblb,$(pblb-y)) targets += $(patsubst %,%.pbl,$(pblb-y)) targets += $(patsubst %,%.s,$(pblb-y)) diff --git a/images/Makefile.imx b/images/Makefile.imx index dcec181779..84c4071b6c 100644 --- a/images/Makefile.imx +++ b/images/Makefile.imx @@ -8,6 +8,14 @@ $(obj)/%.imximg: $(obj)/% FORCE $(call if_changed,imx_image,$(CFG_$(@F)),) +$(obj)/%.pimximg: $(obj)/% FORCE + $(call if_changed,imx_image,$(CFG_$(patsubst %.pimximg,%.imximg,$(@F))),\ + -p $($(patsubst $(obj)/%.pblb,PBL_MEMORY_SIZE_%,$<))) + +$(obj)/%.psimximg: $(obj)/% FORCE + $(call if_changed,imx_image,$(CFG_$(patsubst %.psimximg,%.imximg,$(@F))),-s \ + -p $($(patsubst $(obj)/%.pblb,PBL_MEMORY_SIZE_%,$<))) + $(obj)/%.simximg: $(obj)/% FORCE $(call if_changed,imx_image,$(CFG_$(patsubst %.simximg,%.imximg,$(@F))),-s) @@ -579,8 +587,7 @@ image-$(CONFIG_MACH_ZII_IMX7D_DEV) += barebox-zii-imx7d-dev.img # ----------------------- i.MX8mq based boards -------------------------- pblb-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += start_nxp_imx8mq_evk CFG_start_nxp_imx8mq_evk.pblb.imximg = $(board)/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg -MAX_PBL_MEMORY_SIZE_start_nxp_imx8mq_evk = 0x3f000 -FILE_barebox-nxp-imx8mq-evk.img = start_nxp_imx8mq_evk.pblb.imximg +FILE_barebox-nxp-imx8mq-evk.img = start_nxp_imx8mq_evk.pblb.pimximg image-$(CONFIG_MACH_NXP_IMX8MQ_EVK) += barebox-nxp-imx8mq-evk.img pblb-$(CONFIG_MACH_ZII_IMX8MQ_DEV) += start_zii_imx8mq_dev diff --git a/images/sha_sum.S b/images/sha_sum.S new file mode 100644 index 0000000000..5928c206a8 --- /dev/null +++ b/images/sha_sum.S @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + .section .shasum,"a" + .globl sha_sum +sha_sum: + .incbin "images/barebox.sha.bin" + .globl sha_sum_end +sha_sum_end: diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 0eb18f614b..f584cad48d 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -8,12 +8,12 @@ extern char __bare_init_start[], __bare_init_end[]; extern char _end[]; extern char __image_start[]; extern char __image_end[]; +extern char __piggydata_start[]; extern void *_barebox_image_size; extern void *_barebox_bare_init_size; extern void *_barebox_pbl_size; #define barebox_image_size (__image_end - __image_start) #define barebox_bare_init_size (unsigned int)&_barebox_bare_init_size -#define barebox_pbl_size (unsigned int)&_barebox_pbl_size - +#define barebox_pbl_size (__piggydata_start - __image_start) #endif /* _ASM_GENERIC_SECTIONS_H_ */ diff --git a/include/crypto/pbl-sha.h b/include/crypto/pbl-sha.h new file mode 100644 index 0000000000..7d323ab479 --- /dev/null +++ b/include/crypto/pbl-sha.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PBL_SHA_H_ + +#define __PBL_SHA_H_ + +#include <digest.h> +#include <types.h> + +int sha256_init(struct digest *desc); +int sha256_update(struct digest *desc, const void *data, unsigned long len); +int sha256_final(struct digest *desc, u8 *out); + +#endif /* __PBL-SHA_H_ */ diff --git a/include/pbl.h b/include/pbl.h index 787bd8293f..1917a7633f 100644 --- a/include/pbl.h +++ b/include/pbl.h @@ -11,6 +11,8 @@ extern unsigned long free_mem_ptr; extern unsigned long free_mem_end_ptr; void pbl_barebox_uncompress(void *dest, void *compressed_start, unsigned int len); +int pbl_barebox_verify(void *compressed_start, unsigned int len, void *hash, + unsigned int hash_len); #ifdef __PBL__ #define IN_PBL 1 diff --git a/include/stdio.h b/include/stdio.h index 7b2a42b817..46e277889d 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -71,23 +71,32 @@ static inline int ctrlc (void) #if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \ (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE)) int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); + +static inline int puts(const char *s) +{ + return console_puts(CONSOLE_STDOUT, s); +} + +static inline void putchar(char c) +{ + console_putc(CONSOLE_STDOUT, c); +} #else static int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); static inline int printf(const char *fmt, ...) { return 0; } -#endif - static inline int puts(const char *s) { - return console_puts(CONSOLE_STDOUT, s); + return 0; } static inline void putchar(char c) { - console_putc(CONSOLE_STDOUT, c); + return; } +#endif /* * FILE based functions diff --git a/pbl/Kconfig b/pbl/Kconfig index f2250dd73b..7e6077f96d 100644 --- a/pbl/Kconfig +++ b/pbl/Kconfig @@ -44,6 +44,10 @@ config PBL_RELOCATABLE This option only inflluences the PBL image. See RELOCATABLE to also make the real image relocatable. +config PBL_VERIFY_PIGGY + depends on ARM + bool + config IMAGE_COMPRESSION bool depends on HAVE_IMAGE_COMPRESSION diff --git a/pbl/decomp.c b/pbl/decomp.c index 72a162309a..ef713a6c74 100644 --- a/pbl/decomp.c +++ b/pbl/decomp.c @@ -6,6 +6,10 @@ */ #include <common.h> +#include <crypto/sha.h> +#include <crypto/pbl-sha.h> +#include <digest.h> +#include <asm/sections.h> #include <pbl.h> #include <debug_ll.h> @@ -54,3 +58,38 @@ void pbl_barebox_uncompress(void *dest, void *compressed_start, unsigned int len NULL, NULL, dest, NULL, errorfn); } + +int pbl_barebox_verify(void *compressed_start, unsigned int len, void *hash, + unsigned int hash_len) +{ + struct sha256_state sha_state = { 0 }; + struct digest d = { .ctx = &sha_state }; + char computed_hash[SHA256_DIGEST_SIZE]; + int i; + char *char_hash = hash; + + if (hash_len != SHA256_DIGEST_SIZE) + return -1; + + sha256_init(&d); + sha256_update(&d, compressed_start, len); + sha256_final(&d, computed_hash); + if (IS_ENABLED(CONFIG_DEBUG_LL)) { + putc_ll('C'); + putc_ll('H'); + putc_ll('\n'); + for (i = 0; i < SHA256_DIGEST_SIZE; i++) { + puthex_ll(computed_hash[i]); + putc_ll('\n'); + } + putc_ll('I'); + putc_ll('H'); + putc_ll('\n'); + for (i = 0; i < SHA256_DIGEST_SIZE; i++) { + puthex_ll(char_hash[i]); + putc_ll('\n'); + } + } + + return memcmp(hash, computed_hash, SHA256_DIGEST_SIZE); +} diff --git a/pbl/misc.c b/pbl/misc.c index 7e76120a68..201ae38e9a 100644 --- a/pbl/misc.c +++ b/pbl/misc.c @@ -11,5 +11,10 @@ void __noreturn hang(void) void __noreturn panic(const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + printf(fmt, args); + va_end(args); while(1); } diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index 6a258bd823..a9323f8ba3 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -315,6 +315,16 @@ static size_t add_header_v2(const struct config_data *data, void *buf) uint32_t loadaddr = data->image_load_addr; uint32_t imagesize = data->load_size; + if (data->pbl_code_size) { + /* + * Restrict the imagesize to the PBL if given. + * Also take the alignment for CSF into account. + */ + imagesize = roundup(data->pbl_code_size + HEADER_LEN, 0x4); + if (data->csf) + imagesize = roundup(imagesize, 0x1000); + } + buf += offset; hdr = buf; @@ -333,14 +343,22 @@ static size_t add_header_v2(const struct config_data *data, void *buf) hdr->self = loadaddr + offset; hdr->boot_data.start = loadaddr; - if (data->max_load_size && imagesize > data->max_load_size) + if (!data->csf && data->max_load_size + && imagesize > data->max_load_size) hdr->boot_data.size = data->max_load_size; else hdr->boot_data.size = imagesize; - if (data->csf) { + if (data->sign_image) { hdr->csf = loadaddr + imagesize; hdr->boot_data.size += CSF_LEN; + } else if (data->pbl_code_size && data->csf) { + /* + * For i.MX8 the CSF space is added via the linker script, so + * the CSF length needs to be added if HABV4 is enabled but + * signing is not. + */ + hdr->boot_data.size += CSF_LEN; } hdr->dcd_header.tag = TAG_DCD_HEADER; @@ -555,6 +573,7 @@ static int hab_sign(struct config_data *data) char *cst; void *buf; size_t csf_space = CSF_LEN; + unsigned int offset = 0; cst = getenv("CST"); if (!cst) @@ -681,13 +700,36 @@ static int hab_sign(struct config_data *data) return -errno; } - outfd = open(data->outfile, O_WRONLY | O_APPEND); + /* + * For i.MX8, write into the reserved CSF section + */ + if (data->cpu_type == IMX_CPU_IMX8MQ) + outfd = open(data->outfile, O_WRONLY); + else + outfd = open(data->outfile, O_WRONLY | O_APPEND); + if (outfd < 0) { fprintf(stderr, "Cannot open %s for writing: %s\n", data->outfile, strerror(errno)); exit(1); } + if (data->cpu_type == IMX_CPU_IMX8MQ) { + /* + * For i.MX8 insert the CSF data into the reserved CSF area + * right behind the PBL + */ + offset = roundup(data->header_gap + data->pbl_code_size + + HEADER_LEN, 0x1000); + if (data->signed_hdmi_firmware_file) + offset += PLUGIN_HDMI_SIZE; + + if (lseek(outfd, offset, SEEK_SET) < 0) { + perror("lseek"); + exit(1); + } + } + ret = xwrite(outfd, buf, csf_space); if (ret < 0) { fprintf(stderr, "write failed: %s\n", strerror(errno)); @@ -752,7 +794,6 @@ int main(int argc, char *argv[]) int outfd; int dcd_only = 0; int now = 0; - int sign_image = 0; int i, header_copies; int add_barebox_header; uint32_t barebox_image_size = 0; @@ -769,7 +810,7 @@ int main(int argc, char *argv[]) prgname = argv[0]; - while ((opt = getopt(argc, argv, "c:hf:o:bduse")) != -1) { + while ((opt = getopt(argc, argv, "c:hf:o:p:bduse")) != -1) { switch (opt) { case 'c': configfile = optarg; @@ -780,6 +821,9 @@ int main(int argc, char *argv[]) case 'o': data.outfile = optarg; break; + case 'p': + data.pbl_code_size = strtoul(optarg, NULL, 0); + break; case 'b': add_barebox_header = 1; break; @@ -787,7 +831,7 @@ int main(int argc, char *argv[]) dcd_only = 1; break; case 's': - sign_image = 1; + data.sign_image = 1; break; case 'u': create_usb_image = 1; @@ -841,14 +885,12 @@ int main(int argc, char *argv[]) if (ret) exit(1); - if (data.max_load_size && (sign_image || data.encrypt_image)) { + if (data.max_load_size && (data.encrypt_image || data.csf) + && data.cpu_type != IMX_CPU_IMX8MQ) { fprintf(stderr, "Specifying max_load_size is incompatible with HAB signing/encrypting\n"); exit(1); } - if (!sign_image) - data.csf = NULL; - if (create_usb_image && !data.csf) { fprintf(stderr, "Warning: the -u option only has effect with signed images\n"); create_usb_image = 0; @@ -996,7 +1038,7 @@ int main(int argc, char *argv[]) exit(1); } - if (data.csf) { + if (data.csf && data.sign_image) { ret = hab_sign(&data); if (ret) exit(1); diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index 4f18d90d3a..b3e8d62ba8 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -338,6 +338,7 @@ static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) char *str; int ret; uint32_t signed_size = data->load_size; + uint32_t offset = 0; if (!data->csf) return -EINVAL; @@ -354,9 +355,19 @@ static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) if (data->encrypt_image) signed_size = ENCRYPT_OFFSET; + /* + * Ensure we only sign the PBL for i.MX8MQ + */ + if (data->pbl_code_size && data->cpu_type == IMX_CPU_IMX8MQ) { + offset = data->header_gap; + signed_size = roundup(data->pbl_code_size + HEADER_LEN, 0x1000); + if (data->signed_hdmi_firmware_file) + offset += PLUGIN_HDMI_SIZE; + } + if (!strcmp(type, "full")) { - ret = asprintf(&str, "Blocks = 0x%08x 0 %d \"%s\"\n", - data->image_load_addr, signed_size, + ret = asprintf(&str, "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"\n", + data->image_load_addr, offset, signed_size, data->outfile); } else if (!strcmp(type, "from-dcdofs")) { ret = asprintf(&str, "Blocks = 0x%08x 0x%x %d \"%s\"\n", |