summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/Makefile4
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/flash-header-imx8mq-evk.imxcfg1
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/lowlevel.c106
-rw-r--r--arch/arm/boards/nxp-imx8mq-evk/trampoline.S10
-rw-r--r--arch/arm/cpu/uncompress.c17
-rw-r--r--arch/arm/lib/pbl.lds.S17
-rw-r--r--arch/arm/mach-imx/Kconfig5
-rw-r--r--arch/arm/mach-imx/include/mach/habv4-imx8-gencsf.h59
-rw-r--r--arch/arm/mach-imx/include/mach/imx-header.h2
-rw-r--r--arch/arm/mach-imx/include/mach/xload.h5
-rw-r--r--arch/arm/mach-imx/xload-common.c6
-rw-r--r--crypto/Makefile2
-rw-r--r--crypto/sha2.c11
-rw-r--r--drivers/hab/hab.c2
-rw-r--r--drivers/hab/habv4.c134
-rw-r--r--drivers/mci/imx-esdhc-pbl.c90
-rw-r--r--images/Makefile22
-rw-r--r--images/Makefile.imx11
-rw-r--r--images/sha_sum.S7
-rw-r--r--include/asm-generic/sections.h4
-rw-r--r--include/crypto/pbl-sha.h13
-rw-r--r--include/pbl.h2
-rw-r--r--include/stdio.h17
-rw-r--r--pbl/Kconfig4
-rw-r--r--pbl/decomp.c39
-rw-r--r--pbl/misc.c5
-rw-r--r--scripts/imx/imx-image.c64
-rw-r--r--scripts/imx/imx.c15
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",