diff --git a/config/examples/imx-rt1040.config b/config/examples/imx-rt1040.config index 24ac4303e..a7ff8848d 100644 --- a/config/examples/imx-rt1040.config +++ b/config/examples/imx-rt1040.config @@ -19,7 +19,7 @@ NVM_FLASH_WRITEONCE?=1 WOLFBOOT_VERSION?=0 V?=0 SPMATH?=1 -RAM_CODE?=0 +RAM_CODE?=1 DUALBANK_SWAP?=0 PKA?=0 WOLFBOOT_PARTITION_SIZE?=0x20000 diff --git a/config/examples/imx-rt1050.config b/config/examples/imx-rt1050.config index f872c8820..3c55d6c9b 100644 --- a/config/examples/imx-rt1050.config +++ b/config/examples/imx-rt1050.config @@ -19,7 +19,7 @@ NVM_FLASH_WRITEONCE?=1 WOLFBOOT_VERSION?=0 V?=0 SPMATH?=1 -RAM_CODE?=0 +RAM_CODE?=1 DUALBANK_SWAP?=0 PKA?=0 WOLFBOOT_PARTITION_SIZE?=0x20000 diff --git a/config/examples/imx-rt1060.config b/config/examples/imx-rt1060.config index 3f5e2cf6a..9a16cf5e8 100644 --- a/config/examples/imx-rt1060.config +++ b/config/examples/imx-rt1060.config @@ -19,7 +19,7 @@ NVM_FLASH_WRITEONCE?=1 WOLFBOOT_VERSION?=0 V?=0 SPMATH?=1 -RAM_CODE?=0 +RAM_CODE?=1 DUALBANK_SWAP?=0 PKA?=0 WOLFBOOT_PARTITION_SIZE?=0x20000 diff --git a/config/examples/imx-rt1060_hab.config b/config/examples/imx-rt1060_hab.config index 43e46b653..b94e5d05b 100644 --- a/config/examples/imx-rt1060_hab.config +++ b/config/examples/imx-rt1060_hab.config @@ -20,7 +20,7 @@ NVM_FLASH_WRITEONCE?=1 WOLFBOOT_VERSION?=0 V?=0 SPMATH?=1 -RAM_CODE?=0 +RAM_CODE?=1 DUALBANK_SWAP?=0 PKA?=0 WOLFBOOT_PARTITION_SIZE?=0x20000 diff --git a/config/examples/imx-rt1064.config b/config/examples/imx-rt1064.config index 03f3b9b66..b3787b330 100644 --- a/config/examples/imx-rt1064.config +++ b/config/examples/imx-rt1064.config @@ -19,7 +19,7 @@ NVM_FLASH_WRITEONCE?=1 WOLFBOOT_VERSION?=0 V?=0 SPMATH?=1 -RAM_CODE?=0 +RAM_CODE?=1 DUALBANK_SWAP?=0 PKA?=0 WOLFBOOT_PARTITION_SIZE?=0x20000 diff --git a/docs/Targets.md b/docs/Targets.md index 19b494072..75445a678 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1455,6 +1455,30 @@ be added to the configuration. The `imx_rt` target supports building without a flash configuration, IVT, Boot Data and DCD. This is needed when wanting to use HAB through NXP's *Secure Provisioning Tool* to sign wolfBoot to enable secure boot. To build wolfBoot this way `TARGET_IMX_HAB` needs to be set to 1 in the configuration file (see `config/examples/imx-rt1060 _hab.config` for an example). When built with `TARGET_IMX_HAB=1` wolfBoot must be written to flash using NXP's *Secure Provisioning Tool*. +### Building libwolfBoot + +To enable interactions with wolfBoot, your application needs to include `libwolfBoot`. When compiling this a few things are important to note: +* When using XIP, functions that have the `RAMFUNCTION` signature need to be located in RAM and not flash. To do this the `.ramcode` section needs to be placed in RAM. Note that defining `WOLFBOOT_USE_STDLIBC` will not use wolfBoot's implementation of `memcpy`, and thus breaks this requirement. +* When using XIP, the `DCACHE_InvalidateByRange` function from NXP's SDK needs to be placed in RAM. To do this exclude the file it's located in from being put into flash +``` +.text : +{ + ... + *(EXCLUDE_FILE( + */fsl_cache.c.obj + ) .text*) /* .text* sections (code) */ + *(EXCLUDE_FILE( + */fsl_cache.c.obj + ) .rodata*) /* .rodata* sections (constants, strings, etc.) */ + ... +} > FLASH +``` +and instead include it in your RAM section +.ram : +{ + */fsl_cache.c.obj(.text* .rodata*) +} > RAM + ### Flashing Firmware can be directly uploaded to the target by copying `factory.bin` to the virtual USB drive associated to the device, or by loading the image directly into flash using a JTAG/SWD debugger. diff --git a/hal/imx_rt.c b/hal/imx_rt.c index cac754fee..257b4d64f 100644 --- a/hal/imx_rt.c +++ b/hal/imx_rt.c @@ -49,12 +49,18 @@ #endif #ifdef CPU_MIMXRT1061CVJ5B #include "evkmimxrt1060_flexspi_nor_config.h" +#define USE_GET_CONFIG #endif #ifdef CPU_MIMXRT1052DVJ6B #include "evkbimxrt1050_flexspi_nor_config.h" +/** + * Does not support getting the config through the FlexSPI ROM API + * (see ch. 9.13.1 in rev.5 of the reference manual) + */ #endif #ifdef CPU_MIMXRT1042XJM5B #include "evkmimxrt1040_flexspi_nor_config.h" +#define USE_GET_CONFIG #endif #include "xip/fsl_flexspi_nor_boot.h" @@ -235,7 +241,32 @@ bootloader_api_entry_t *g_bootloaderTree; /** Flash configuration in the .flash_config section of flash **/ #ifdef CPU_MIMXRT1064DVL6A - #define CONFIG_FLASH_SIZE (4 * 1024 * 1024) /* 4MBytes */ + #if defined(CONFIG_FLASH_W25Q16JV) + /* Winbond W25Q16JV */ + #define CONFIG_FLASH_SIZE (2 * 1024 * 1024) /* 2MBytes */ + #elif defined(CONFIG_FLASH_W25Q32JV) + /* Winbond W25Q32JV */ + #define CONFIG_FLASH_SIZE (4 * 1024 * 1024) /* 4MBytes */ + #elif defined(CONFIG_FLASH_W25Q64JV) + /* Winbond W25Q64JV */ + #define CONFIG_FLASH_SIZE (8 * 1024 * 1024) /* 8MBytes */ + #elif defined(CONFIG_FLASH_W25Q128JV) + /* Winbond W25Q128JV */ + #define CONFIG_FLASH_SIZE (16 * 1024 * 1024) /* 16MBytes */ + #elif defined(CONFIG_FLASH_W25Q256JV) + /* Winbond W25Q256JV */ + #define CONFIG_FLASH_SIZE (32 * 1024 * 1024) /* 32MBytes */ + #elif defined(CONFIG_FLASH_W25Q512JV) + /* Winbond W25Q512JV */ + #define CONFIG_FLASH_SIZE (64 * 1024 * 1024) /* 64MBytes */ + #elif defined(CONFIG_FLASH_IS25WP064A) + /* ISSI IS25WP064A (on EVKB with rework see AN12183) */ + #define CONFIG_FLASH_SIZE (8 * 1024 * 1024) /* 8MBytes */ + #else + /* Default to 4MBytes */ + #define CONFIG_FLASH_SIZE (4 * 1024 * 1024) /* 4MBytes */ + #endif + #define CONFIG_FLASH_PAGE_SIZE 256UL /* 256Bytes */ #define CONFIG_FLASH_SECTOR_SIZE (4 * 1024) /* 4KBytes */ #define CONFIG_FLASH_BLOCK_SIZE (64 * 1024) /* 64KBytes */ @@ -266,8 +297,33 @@ const flexspi_nor_config_t FLASH_CONFIG_SECTION qspiflash_config = { /** Flash configuration in the .flash_config section of flash **/ -#if defined(CPU_MIMXRT1062DVL6A) || defined(CPU_MIMXRT1062DVL6B) - #define CONFIG_FLASH_SIZE (8 * 1024 * 1024) /* 8MBytes */ +#if defined(CPU_MIMXRT1062DVL6A) || defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1061CVJ5B) || defined(CPU_MIMXRT1042XJM5B) + #if defined(CONFIG_FLASH_W25Q16JV) + /* Winbond W25Q16JV */ + #define CONFIG_FLASH_SIZE (2 * 1024 * 1024) /* 2MBytes */ + #elif defined(CONFIG_FLASH_W25Q32JV) + /* Winbond W25Q32JV */ + #define CONFIG_FLASH_SIZE (4 * 1024 * 1024) /* 4MBytes */ + #elif defined(CONFIG_FLASH_W25Q64JV) + /* Winbond W25Q64JV */ + #define CONFIG_FLASH_SIZE (8 * 1024 * 1024) /* 8MBytes */ + #elif defined(CONFIG_FLASH_W25Q128JV) + /* Winbond W25Q128JV */ + #define CONFIG_FLASH_SIZE (16 * 1024 * 1024) /* 16MBytes */ + #elif defined(CONFIG_FLASH_W25Q256JV) + /* Winbond W25Q256JV */ + #define CONFIG_FLASH_SIZE (32 * 1024 * 1024) /* 32MBytes */ + #elif defined(CONFIG_FLASH_W25Q512JV) + /* Winbond W25Q512JV */ + #define CONFIG_FLASH_SIZE (64 * 1024 * 1024) /* 64MBytes */ + #elif defined(CONFIG_FLASH_IS25WP064A) + /* ISSI IS25WP064A (on EVKB with rework see AN12183) */ + #define CONFIG_FLASH_SIZE (8 * 1024 * 1024) /* 8MBytes */ + #else + /* Default to 8MBytes */ + #define CONFIG_FLASH_SIZE (8 * 1024 * 1024) /* 8MBytes */ + #endif + #define CONFIG_FLASH_PAGE_SIZE 256UL /* 256Bytes */ #define CONFIG_FLASH_SECTOR_SIZE (4 * 1024) /* 4KBytes */ #define CONFIG_FLASH_BLOCK_SIZE (64 * 1024) /* 64KBytes */ @@ -294,12 +350,10 @@ const flexspi_nor_config_t FLASH_CONFIG_SECTION qspiflash_config = { .blockSize = CONFIG_FLASH_BLOCK_SIZE, .isUniformBlockSize = CONFIG_FLASH_UNIFORM_BLOCKSIZE, }; -#endif - +#endif /* CPU_MIMXRT1062DVL6A || CPU_MIMXRT1062DVL6B || CPU_MIMXRT1061CVJ5B || CPU_MIMXRT1042XJM5B */ /** Flash configuration in the .flash_config section of flash **/ -#if defined(CPU_MIMXRT1061CVJ5B) || defined(CPU_MIMXRT1052DVJ6B) || defined(CPU_MIMXRT1042XJM5B) - +#if defined(CPU_MIMXRT1052DVJ6B) #if defined(CONFIG_FLASH_W25Q16JV) /* Winbond W25Q16JV */ #define CONFIG_FLASH_SIZE (2 * 1024 * 1024) /* 2MBytes */ @@ -590,11 +644,11 @@ const flexspi_nor_config_t FLASH_CONFIG_SECTION qspiflash_config = { .ipcmdSerialClkFreq = 0, }; #endif -#endif /* CPU_MIMXRT1042XJM5B || CPU_MIMXRT1052DVJ6B */ - +#endif /* CPU_MIMXRT1052DVJ6B */ #ifndef __FLASH_BASE -#if defined(CPU_MIMXRT1062DVL6A) || defined(CPU_MIMXRT1062DVL6B) || \ +#if defined(CPU_MIMXRT1062DVL6A) || \ + defined(CPU_MIMXRT1062DVL6B) || \ defined(CPU_MIMXRT1061CVJ5B) || \ defined(CPU_MIMXRT1052DVJ6B) || \ defined(CPU_MIMXRT1042XJM5B) @@ -841,7 +895,7 @@ void hal_prepare_boot(void) #endif /* __WOLFBOOT */ -static int hal_flash_init(void) +static int RAMFUNCTION hal_flash_init(void) { #ifdef USE_GET_CONFIG serial_nor_config_option_t flexspi_cfg_option; @@ -851,11 +905,20 @@ static int hal_flash_init(void) #ifdef USE_GET_CONFIG memset(&flexspi_cfg_option, 0, sizeof(flexspi_cfg_option)); flexspi_cfg_option.option0.U = 0xC0000007; /* QuadSPI-NOR, f = default */ + /** + * Disable interrupts before accessing flash when using XIP + * (note 4 p.279 in i.MX RT1060 Processor Reference Manual, Rev. 3, 07/2021) + */ + asm volatile("cpsid i"); g_bootloaderTree->flexSpiNorDriver->get_config(0, &flexspi_config, &flexspi_cfg_option); g_bootloaderTree->flexSpiNorDriver->init(0, &flexspi_config); g_bootloaderTree->flexSpiNorDriver->clear_cache(0); + /* Ensure no speculative prefetching happens before flash access is finished */ + asm volatile("dsb"); + /* Re-enable interrupts */ + asm volatile("cpsie i"); #endif } return 0; @@ -876,23 +939,33 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) * (note 4 p.279 in i.MX RT1060 Processor Reference Manual, Rev. 3, 07/2021) */ asm volatile("cpsid i"); + int write_success = 0; for (i = 0; i < len; i+= CONFIG_FLASH_PAGE_SIZE) { memcpy(wbuf, data + i, CONFIG_FLASH_PAGE_SIZE); status = g_bootloaderTree->flexSpiNorDriver->program(0, FLEXSPI_CONFIG, (address + i) - FLASH_BASE, wbuf); - /** - * Flash is memory mapped, so the address range must be invalidated in data cache - * to ensure coherency between flash and cache - */ - DCACHE_InvalidateByRange(address + i, sizeof(wbuf)); if (status != kStatus_Success) { - asm volatile("cpsie i"); - return -1; + write_success = -1; + break; } } + /* Ensure no speculative prefetching happens before flash program is finished */ + asm volatile("dsb"); + /** + * Flash is memory mapped, so the address range must be invalidated in data cache + * to ensure coherency between flash and cache. + * + * Also, both the address and size must be 32-byte aligned as cache-lines are 32 bytes + * (see definition of DCACHE_InvalidateByRange). + * To ensure all data is included we align the address downwards, and the length upwards. + */ + uint32_t aligned_address = address - (address % 32); + uint32_t aligned_len = len + (32 - (len % 32)); + DCACHE_InvalidateByRange(aligned_address, aligned_len); + /* Re-enable interrupts */ asm volatile("cpsie i"); - return 0; + return write_success; } void RAMFUNCTION hal_flash_unlock(void) @@ -918,11 +991,20 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) asm volatile("cpsid i"); status = g_bootloaderTree->flexSpiNorDriver->erase(0, FLEXSPI_CONFIG, address - FLASH_BASE, len); + /* Ensure no speculative prefetching happens before flash erase is finished */ + asm volatile("dsb"); /** * Flash is memory mapped, so the address range must be invalidated in data cache - * to ensure coherency between flash and cache + * to ensure coherency between flash and cache. + * + * Also, both the address and size must be 32-byte aligned as cache-lines are 32 bytes + * (see definition of DCACHE_InvalidateByRange). + * To ensure all data is included we align the address downwards, and the length upwards. */ - DCACHE_InvalidateByRange(address, len); + uint32_t aligned_address = address - (address % 32); + uint32_t aligned_len = len + (32 - (len % 32)); + DCACHE_InvalidateByRange(aligned_address, aligned_len); + /* Re-enable interrupts */ asm volatile("cpsie i"); if (status != kStatus_Success) return -1;