diff --git a/arch/arm/boards/nxp-imx8mq-evk/Makefile b/arch/arm/boards/nxp-imx8mq-evk/Makefile index 0546b0b..7907de4 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 aff8321..11463fe 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 @@ loadaddr 0x007E1000 max_load_size 0x3F000 dcdofs 0x400 +#include diff --git a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c index e3fdc64..a74171e 100644 --- a/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c +++ b/arch/arm/boards/nxp-imx8mq-evk/lowlevel.c @@ -53,54 +53,28 @@ 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); - - if (src == BOOTSOURCE_MMC) - ret = imx8_esdhc_start_image(instance); - - BUG_ON(ret); } -static __noreturn noinline void nxp_imx8mq_evk_start(void) +extern unsigned char trampoline_start[]; +extern unsigned char trampoline_end[]; + +static void nxp_imx8mq_evk_install_tfa_trampoline(void) { - 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(); - } + unsigned int tramp_len; + unsigned int offset; /* - * 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 + * 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. */ - if (current_el() == 3) { - const u8 *bl31; - size_t bl31_size; + tramp_len = (void *)trampoline_end - (void *)trampoline_start; + memcpy((void *)MX8MQ_ATF_BL33_BASE_ADDR, (void *)trampoline_start, + tramp_len); - get_builtin_firmware(imx8mq_bl31_bin, &bl31, &bl31_size); - imx8mq_atf_load_bl31(bl31, bl31_size); - } - - /* - * Standard entry we hit once we initialized both DDR and ATF - */ - imx8mq_barebox_entry(__dtb_imx8mq_evk_start); + offset = get_runtime_offset(); + memcpy((void *)MX8MQ_ATF_BL33_BASE_ADDR + tramp_len, &offset, + sizeof(offset)); } /* @@ -111,18 +85,57 @@ * 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 + * 2. DDR is initialized and the TF-A trampoline is installed in the + * DRAM. * - * 3. start_nxp_imx8mq_evk, now in RAM, is executed again + * 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. BL31 blob is uploaded to OCRAM and the control is transfer to it + * 4. The piggydata is loaded from the SD card and copied to the expected + * location in the DRAM. * - * 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 + * 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 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) { + 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); +} + ENTRY_FUNCTION(start_nxp_imx8mq_evk, r0, r1, r2) { imx8mq_cpu_lowlevel_init(); @@ -132,4 +145,3 @@ 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 0000000..54a1b76 --- /dev/null +++ b/arch/arm/boards/nxp-imx8mq-evk/trampoline.S @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (GPL-2.0) */ +#include +#include + .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 4f16af2..9cc3b35 100644 --- a/arch/arm/cpu/uncompress.c +++ b/arch/arm/cpu/uncompress.c @@ -42,14 +42,18 @@ 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 @@ 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 300671b..01ed384 100644 --- a/arch/arm/lib/pbl.lds.S +++ b/arch/arm/lib/pbl.lds.S @@ -68,6 +68,13 @@ . = 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 @@ 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 553d11a..e772162 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -183,6 +183,7 @@ 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 @@ 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 0000000..34039ee --- /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 50584bb..dc8e2ee 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 @@ 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 @@ 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 8f141bc..a605e76 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_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 c5727eb..bd64052 100644 --- a/arch/arm/mach-imx/xload-common.c +++ b/arch/arm/mach-imx/xload-common.c @@ -8,3 +8,9 @@ /* 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 3402f57..d6fb74a 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -8,6 +8,8 @@ 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 c62ddb8..3947a09 100644 --- a/crypto/sha2.c +++ b/crypto/sha2.c @@ -27,6 +27,7 @@ #include #include +#include static inline u32 Ch(u32 x, u32 y, u32 z) { @@ -232,7 +233,7 @@ 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 @@ 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 @@ 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 @@ } 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 @@ .ctx_length = sizeof(struct sha256_state), }; +#ifndef __PBL__ static int sha256_digest_register(void) { if (!IS_ENABLED(CONFIG_SHA256)) @@ -373,3 +375,4 @@ 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 03bb65e..a346e01 100644 --- a/drivers/hab/hab.c +++ b/drivers/hab/hab.c @@ -217,7 +217,7 @@ 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 a53e40a..e3c1de1 100644 --- a/drivers/hab/habv4.c +++ b/drivers/hab/habv4.c @@ -22,8 +22,11 @@ #include #include #include +#include +#include #include +#include #define HABV4_RVT_IMX28 0xffff8af8 #define HABV4_RVT_IMX6_OLD 0x00000094 @@ -177,6 +180,92 @@ 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 @@ 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 @@ 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 367daa8..fb27c84 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -243,27 +243,22 @@ } #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 @@ * 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 @@ 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 293e644..907986e 100644 --- a/images/Makefile +++ b/images/Makefile @@ -57,11 +57,12 @@ 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 @@ $(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 @@ $(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 dcec181..84c4071 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 @@ # ----------------------- 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 0000000..5928c20 --- /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 0eb18f6..f584cad 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -8,12 +8,12 @@ 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 0000000..7d323ab --- /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 +#include + +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 787bd82..1917a76 100644 --- a/include/pbl.h +++ b/include/pbl.h @@ -11,6 +11,8 @@ 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 7b2a42b..46e2778 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -71,13 +71,6 @@ #if (!defined(__PBL__) && !defined(CONFIG_CONSOLE_NONE)) || \ (defined(__PBL__) && defined(CONFIG_PBL_CONSOLE)) int printf(const char *fmt, ...) __attribute__ ((format(__printf__, 1, 2))); -#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) { @@ -88,6 +81,22 @@ { 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; +} +static inline int puts(const char *s) +{ + return 0; +} + +static inline void putchar(char c) +{ + return; +} +#endif /* * FILE based functions diff --git a/pbl/Kconfig b/pbl/Kconfig index f2250dd..7e6077f 100644 --- a/pbl/Kconfig +++ b/pbl/Kconfig @@ -44,6 +44,10 @@ 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 72a1623..ef713a6 100644 --- a/pbl/decomp.c +++ b/pbl/decomp.c @@ -6,6 +6,10 @@ */ #include +#include +#include +#include +#include #include #include @@ -54,3 +58,38 @@ 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 7e76120..201ae38 100644 --- a/pbl/misc.c +++ b/pbl/misc.c @@ -11,5 +11,10 @@ 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 6a258bd..a9323f8 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -315,6 +315,16 @@ 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 @@ 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 @@ char *cst; void *buf; size_t csf_space = CSF_LEN; + unsigned int offset = 0; cst = getenv("CST"); if (!cst) @@ -681,13 +700,36 @@ 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 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 @@ 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 @@ 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 @@ dcd_only = 1; break; case 's': - sign_image = 1; + data.sign_image = 1; break; case 'u': create_usb_image = 1; @@ -841,14 +885,12 @@ 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 @@ 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 4f18d90..b3e8d62 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -338,6 +338,7 @@ char *str; int ret; uint32_t signed_size = data->load_size; + uint32_t offset = 0; if (!data->csf) return -EINVAL; @@ -354,9 +355,19 @@ 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",