This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf9160 non-secure boot hard-fault

Hi all,

I’m currently working with the nrf9160 sip on a bare metal firmware project. I know the official support path is only with Zephyr OS but I’m facing an issue I’m not able to solve so far.

I want to take advantage of the Trustzone feature, to do so I created a minimal bootloader running in secure zone and responsible for setting up part of the flash/SRAM and peripherals as non-secure before trying to jump in the non-secure application. For some reasons, the bootloader get a hard-fault when it tries to load the reset handler of the non-secure app.

In order to reduce the unknown, I ported the SPM sample code provided as reference to my bootloader. Here is the debug output I’m getting:

Flash region            Domain          Permissions
00 0x00000 0x08000      Secure          rwxl
01 0x08000 0x10000      Secure          rwxl
02 0x10000 0x18000      Secure          rwxl
03 0x18000 0x20000      Secure          rwxl
04 0x20000 0x28000      Secure          rwxl
05 0x28000 0x30000      Secure          rwxl
06 0x30000 0x38000      Secure          rwxl
07 0x38000 0x40000      Secure          rwxl
08 0x40000 0x48000      Non-Secure      rwxl
09 0x48000 0x50000      Non-Secure      rwxl
10 0x50000 0x58000      Non-Secure      rwxl
11 0x58000 0x60000      Non-Secure      rwxl
12 0x60000 0x68000      Non-Secure      rwxl
13 0x68000 0x70000      Non-Secure      rwxl
14 0x70000 0x78000      Non-Secure      rwxl
15 0x78000 0x80000      Non-Secure      rwxl
16 0x80000 0x88000      Non-Secure      rwxl
17 0x88000 0x90000      Non-Secure      rwxl
18 0x90000 0x98000      Non-Secure      rwxl
19 0x98000 0xa0000      Non-Secure      rwxl
20 0xa0000 0xa8000      Non-Secure      rwxl
21 0xa8000 0xb0000      Non-Secure      rwxl
22 0xb0000 0xb8000      Non-Secure      rwxl
23 0xb8000 0xc0000      Non-Secure      rwxl
24 0xc0000 0xc8000      Non-Secure      rwxl
25 0xc8000 0xd0000      Non-Secure      rwxl
26 0xd0000 0xd8000      Non-Secure      rwxl
27 0xd8000 0xe0000      Non-Secure      rwxl
28 0xe0000 0xe8000      Non-Secure      rwxl
29 0xe8000 0xf0000      Non-Secure      rwxl
30 0xf0000 0xf8000      Non-Secure      rwxl
31 0xf8000 0x100000     Non-Secure      rwxl

SRAM region             Domain          Permissions
00 0x00000 0x02000      Secure          rwxl
01 0x02000 0x04000      Secure          rwxl
02 0x04000 0x06000      Secure          rwxl
03 0x06000 0x08000      Secure          rwxl
04 0x08000 0x0a000      Secure          rwxl
05 0x0a000 0x0c000      Secure          rwxl
06 0x0c000 0x0e000      Secure          rwxl
07 0x0e000 0x10000      Secure          rwxl
08 0x10000 0x12000      Non-Secure      rwxl
09 0x12000 0x14000      Non-Secure      rwxl
10 0x14000 0x16000      Non-Secure      rwxl
11 0x16000 0x18000      Non-Secure      rwxl
12 0x18000 0x1a000      Non-Secure      rwxl
13 0x1a000 0x1c000      Non-Secure      rwxl
14 0x1c000 0x1e000      Non-Secure      rwxl
15 0x1e000 0x20000      Non-Secure      rwxl
16 0x20000 0x22000      Non-Secure      rwxl
17 0x22000 0x24000      Non-Secure      rwxl
18 0x24000 0x26000      Non-Secure      rwxl
19 0x26000 0x28000      Non-Secure      rwxl
20 0x28000 0x2a000      Non-Secure      rwxl
21 0x2a000 0x2c000      Non-Secure      rwxl
22 0x2c000 0x2e000      Non-Secure      rwxl
23 0x2e000 0x30000      Non-Secure      rwxl
24 0x30000 0x32000      Non-Secure      rwxl
25 0x32000 0x34000      Non-Secure      rwxl
26 0x34000 0x36000      Non-Secure      rwxl
27 0x36000 0x38000      Non-Secure      rwxl
28 0x38000 0x3a000      Non-Secure      rwxl
29 0x3a000 0x3c000      Non-Secure      rwxl
30 0x3c000 0x3e000      Non-Secure      rwxl
31 0x3e000 0x40000      Non-Secure      rwxl

Peripheral              Domain          Status
00 NRF_P0               Non-Secure      OK
01 NRF_CLOCK            Non-Secure      OK
02 NRF_RTC1             Non-Secure      OK
03 NRF_NVMC             Non-Secure      OK
04 NRF_UARTE1           Non-Secure      OK
05 NRF_UARTE2           Non-Secure      OK
06 NRF_TWIM2            Non-Secure      OK
07 NRF_SPIM3            Non-Secure      OK
08 NRF_TIMER0           Non-Secure      OK
09 NRF_TIMER1           Non-Secure      OK
10 NRF_TIMER2           Non-Secure      OK
11 NRF_SAADC            Non-Secure      OK
12 NRF_PWM0             Non-Secure      OK
13 NRF_PWM1             Non-Secure      OK
14 NRF_PWM2             Non-Secure      OK
15 NRF_PWM3             Non-Secure      OK
16 NRF_WDT              Non-Secure      OK
17 NRF_IPC              Non-Secure      OK
18 NRF_VMC              Non-Secure      OK
19 NRF_FPU              Non-Secure      OK
20 NRF_EGU1             Non-Secure      OK
21 NRF_EGU2             Non-Secure      OK
22 NRF_GPIOTE1          Non-Secure      OK
23 NRF_REGULATORS       Non-Secure      OK

SPM: NS image at 0x40000
SPM: NS MSP at 0x20030000
SPM: NS reset vector at 0x40381
SPM: prepare to jump to Non-Secure image.

Here is the bootloader code:

extern int main(void);
extern int early_boot(void);

#define APP_ADDR		0x40000

static void spm_configure_ns(const tz_nonsecure_setup_conf_t
	*spm_ns_conf);
static void spm_config_flash(void);
static void spm_config_sram(void);
static bool usel_or_split(uint8_t id);
static int spm_config_peripheral(uint8_t id, bool dma_present);
static void spm_config_peripherals(void);
static void spm_jump(void)
static void spm_config(void);

extern unsigned long _sidata;   /* start address for the initialization values of the .data section. defined in linker script */
extern unsigned long _sdata;    /* start address for the .data section. defined in linker script */
extern unsigned long _edata;    /* end address for the .data section. defined in linker script */
extern unsigned long _sbss;     /* start address for the .bss section. defined in linker script */
extern unsigned long _ebss;     /* end address for the .bss section. defined in linker script */
extern unsigned long _estack;     /* end address for the .bss section. defined in linker script */

void Reset_Handler(void)
{
	unsigned long *src, *dest;
	
	SystemInit();
	SystemCoreClockUpdate();
	
	src = &_sidata;
	
	for(dest = &_sdata; dest < &_edata; )
	{
		*(dest++) = *(src++);
	}
    
	for(dest = &_sbss; dest < &_ebss; )
	{
		*(dest++) = 0;
	}

    spm_config();
    spm_jump();
}

static void spm_configure_ns(const tz_nonsecure_setup_conf_t
	*spm_ns_conf)
{
	/* Configure core register block for Non-Secure state. */
	tz_nonsecure_state_setup(spm_ns_conf);
	/* Prioritize Secure exceptions over Non-Secure */
	tz_nonsecure_exception_prio_config(1);
	/* Set non-banked exceptions to target Non-Secure */
	tz_nbanked_exception_target_state_set(0);
	/* Don't allow Non-Secure firmware to issue System resets. */
	tz_nonsecure_system_reset_req_block(1);
	/* Allow SPU to have precedence over (non-existing) ARMv8-M SAU. */
	tz_sau_configure(0, 1);

}

static void spm_config_flash(void)
{
	uint8_t i = 0;
	for(i = 0 ; i < 8 ; i++)
	{
		nrf_spu_flashregion_set(NRF_SPU_S, i, true, NRF_SPU_MEM_PERM_EXECUTE | NRF_SPU_MEM_PERM_READ | NRF_SPU_MEM_PERM_WRITE, true);
	}

	for(i = 8 ; i < 32 ; i++)
	{
		nrf_spu_flashregion_set(NRF_SPU_S, i, false, NRF_SPU_MEM_PERM_EXECUTE | NRF_SPU_MEM_PERM_READ | NRF_SPU_MEM_PERM_WRITE, true);
	}

	printf("Flash region\t\tDomain\t\tPermissions\n");

	for(i = 0 ; i < 32 ; i++)
	{
		printf("%02u 0x%05x 0x%05x \t", i, 32 * 1024 * i, 32 * (1024 * (i+1)));
		printf("%s", NRF_SPU->FLASHREGION[i].PERM & FLASH_SECURE ? "Secure\t\t" :
							   "Non-Secure\t");
		
		printf("%c", NRF_SPU->FLASHREGION[i].PERM  & FLASH_READ  ? 'r' : '-');
		printf("%c", NRF_SPU->FLASHREGION[i].PERM  & FLASH_WRITE ? 'w' : '-');
		printf("%c", NRF_SPU->FLASHREGION[i].PERM  & FLASH_EXEC  ? 'x' : '-');
		printf("%c", NRF_SPU->FLASHREGION[i].PERM  & FLASH_LOCK  ? 'l' : '-');
		printf("\n");
	}
	printf("\n");
}

static void spm_config_sram(void)
{
	uint8_t i = 0;
	for(i = 0 ; i < 8 ; i++)
	{
		nrf_spu_ramregion_set(NRF_SPU_S, i, true, NRF_SPU_MEM_PERM_EXECUTE | NRF_SPU_MEM_PERM_READ | NRF_SPU_MEM_PERM_WRITE, true);
	}

	for(i = 8 ; i < 32 ; i++)
	{
		nrf_spu_ramregion_set(NRF_SPU_S, i, false, NRF_SPU_MEM_PERM_EXECUTE | NRF_SPU_MEM_PERM_READ | NRF_SPU_MEM_PERM_WRITE, true);
	}

	printf("SRAM region\t\tDomain\t\tPermissions\n");

	for(i = 0 ; i < 32 ; i++)
	{
		printf("%02u 0x%05x 0x%05x\t", i, 8 * 1024 * i, 8 * (1024 * (i+1)));
		printf("%s", NRF_SPU->RAMREGION[i].PERM & FLASH_SECURE ? "Secure\t\t" :
							   "Non-Secure\t");
		
		printf("%c", NRF_SPU->RAMREGION[i].PERM  & FLASH_READ  ? 'r' : '-');
		printf("%c", NRF_SPU->RAMREGION[i].PERM  & FLASH_WRITE ? 'w' : '-');
		printf("%c", NRF_SPU->RAMREGION[i].PERM  & FLASH_EXEC  ? 'x' : '-');
		printf("%c", NRF_SPU->RAMREGION[i].PERM  & FLASH_LOCK  ? 'l' : '-');
		printf("\n");
	}
	printf("\n");
}

static bool usel_or_split(uint8_t id)
{
	const uint32_t perm = NRF_SPU->PERIPHID[id].PERM;

	/* NRF_GPIOTE1_NS needs special handling as its
	 * peripheral ID for non-secure han incorrect properties
	 * in the NRF_SPM->PERIPHID[id].perm register.
	 */
	if (id == NRFX_PERIPHERAL_ID_GET(NRF_GPIOTE1_NS)) {
		return true;
	}

	bool present = (perm & SPU_PERIPHID_PERM_PRESENT_Msk) ==
		       SPU_PERIPHID_PERM_PRESENT_Msk;

	/* User-selectable attribution */
	bool usel = (perm & SPU_PERIPHID_PERM_SECUREMAPPING_Msk) ==
		    SPU_PERIPHID_PERM_SECUREMAPPING_UserSelectable;

	/* Split attribution */
	bool split = (perm & SPU_PERIPHID_PERM_SECUREMAPPING_Msk) ==
		     SPU_PERIPHID_PERM_SECUREMAPPING_Split;

	return present && (usel || split);
}

static int spm_config_peripheral(uint8_t id, bool dma_present)
{
	/* Set a peripheral to Non-Secure state, if
	 * - it is present
	 * - has UserSelectable/Split attribution.
	 *
	 * Assign DMA capabilities and lock down the attribution.
	 *
	 * Note: the function assumes that the peripheral ID matches
	 * the IRQ line.
	 */
	NVIC_DisableIRQ(id);

	if (usel_or_split(id)) {
		NRF_SPU->PERIPHID[id].PERM = PERIPH_PRESENT | PERIPH_NONSEC |
			(dma_present ? PERIPH_DMA_NOSEP : 0) |
			PERIPH_LOCK;
	}

	/* Even for non-present peripherals we force IRQs to be routed
	 * to Non-Secure state.
	 */
	NVIC_SetTargetState(id);
	
	return 0;
}

static void spm_config_peripherals(void)
{
	struct periph_cfg {
		char *name;
		uint8_t id;
		uint8_t nonsecure;
	};

	/* - All user peripherals are allocated to the Non-Secure domain.
	 * - All GPIOs are allocated to the Non-Secure domain.
	 */
	static const struct periph_cfg periph[] = {
		PERIPH("NRF_P0", NRF_P0, true),
		PERIPH("NRF_CLOCK", NRF_CLOCK, true),
		PERIPH("NRF_RTC1", NRF_RTC1, true),
		PERIPH("NRF_NVMC", NRF_NVMC, true),
		PERIPH("NRF_UARTE1", NRF_UARTE1, true),
		PERIPH("NRF_UARTE2", NRF_UARTE2, true),
		PERIPH("NRF_TWIM2", NRF_TWIM2, true),
		PERIPH("NRF_SPIM3", NRF_SPIM3, true),
		PERIPH("NRF_TIMER0", NRF_TIMER0, true),
		PERIPH("NRF_TIMER1", NRF_TIMER1, true),
		PERIPH("NRF_TIMER2", NRF_TIMER2, true),
		PERIPH("NRF_SAADC", NRF_SAADC, true),
		PERIPH("NRF_PWM0", NRF_PWM0, true),
		PERIPH("NRF_PWM1", NRF_PWM1, true),
		PERIPH("NRF_PWM2", NRF_PWM2, true),
		PERIPH("NRF_PWM3", NRF_PWM3, true),
		PERIPH("NRF_WDT", NRF_WDT, true),

		/* There is no DTS node for the peripherals below,
		 * so address them using nrfx macros directly.
		 */
		PERIPH("NRF_IPC", NRF_IPC_S, true),
		PERIPH("NRF_VMC", NRF_VMC_S, true),
		PERIPH("NRF_FPU", NRF_FPU_S, true),
		PERIPH("NRF_EGU1", NRF_EGU1_S, true),
		PERIPH("NRF_EGU2", NRF_EGU2_S, true),

		PERIPH("NRF_GPIOTE1", NRF_GPIOTE1_NS,
				      true),
		PERIPH("NRF_REGULATORS", NRF_REGULATORS_S,
				      true),
	};

	printf("Peripheral\t\tDomain\t\tStatus\n");

	if (1) {
		/* Configure GPIO pins to be Non-Secure */
		NRF_SPU->GPIOPORT[0].PERM = 0;
	}

	for (size_t i = 0; i < ARRAY_SIZE(periph); i++) {
		int err;

		printf("%02u %-21s%s", i, periph[i].name,
		      periph[i].nonsecure ? "Non-Secure" : "Secure\t");

		if (!periph[i].nonsecure) {
			printf("\tSKIP\n");
			continue;
		}

		err = spm_config_peripheral(periph[i].id, false);
		if (err) {
			printf("\tERROR\n");
		} else {
			printf("\tOK\n");
		}
	}
	printf("\n");
}

static void spm_jump(void)
{
	/* Extract initial MSP of the Non-Secure firmware image.
	 * The assumption is that the MSP is located at VTOR_NS[0].
	 */
	uint32_t *vtor_ns = (uint32_t *)APP_ADDR;

	printf("SPM: NS image at 0x%x\n", (uint32_t)vtor_ns);
	printf("SPM: NS MSP at 0x%x\n", vtor_ns[0]);
	printf("SPM: NS reset vector at 0x%x\n", vtor_ns[1]);

	/* Configure Non-Secure stack */
	tz_nonsecure_setup_conf_t spm_ns_conf = {
		.vtor_ns = (uint32_t)vtor_ns,
		.msp_ns = vtor_ns[0],
		.psp_ns = 0,//vtor_ns[0],
		.control_ns.npriv = 0, /* Privileged mode*/
		.control_ns.spsel = 0 /* Use MSP in Thread mode */
	};

	spm_configure_ns(&spm_ns_conf);

	TZ_NONSECURE_FUNC_PTR_DECLARE(reset_ns);
	reset_ns = TZ_NONSECURE_FUNC_PTR_CREATE(vtor_ns[1]);

	if (TZ_NONSECURE_FUNC_PTR_IS_NS(reset_ns)) 
	{
	
		printf("SPM: prepare to jump to Non-Secure image.\n");
		/* Note: Move UARTE0 before jumping, if it is
		 * to be used on the Non-Secure domain.
		 */
		
		/* Configure UARTE0 as non-secure */
		spm_config_peripheral(NRFX_PERIPHERAL_ID_GET(NRF_UARTE0), false);

		__DSB();
		__ISB();

		/* Jump to Non-Secure firmware */
		reset_ns();

	} else {
		printf("SPM: wrong pointer type: 0x%x\n",
		      (uint32_t)reset_ns);
	}
}

static void spm_config(void)
{
	spm_config_flash();
	spm_config_sram();
	spm_config_peripherals();
}

Besides, initializing the non-secure flash/SRAM area and peripherals, is there anything else I should take of? 

Parents Reply Children
Related