I am porting FreeRTOS with TrustZone on LPC5500, I put FreeRTOS in secure memory, and created several user tasks in non-secure memory, as shown below:
But so far, I have not successfully switched from a secure task to a non-secure task.
How to switch from a secure task to a non-secure task?
Hi,
Sorry it took a bit long to reply. I created an example:
- Non-secure world first call a Secure API to pass the pointer of the NS thread to Secure world.
- Non-secure world call a Secure API that execute the test sequence:
1) Setup Non-secure PSP
2) Setup Non-secure CONTROL
3) Create Non-secure stack frame
4) Trigger PendSV that do the EXC_RETURN
Please note I didn't enable the FPU in this example, and Secure world used MSP for thread.
If Secure world use PSP for thread the exception return value is 0xFFFFFFBD.
regards,
Joseph
================== Secure world =================
void __attribute__((cmse_nonsecure_entry)) set_thread_addr(uint32_t addr) { ptr = addr; printf ("[Secure world received pointer 0x%x]\n", ptr); return; }void __attribute__((cmse_nonsecure_entry)) tz_test1(void) { uint32_t v_MSP_NS; uint32_t v_PSP_NS; v_MSP_NS = __TZ_get_MSP_NS(); // Get Non-secure stack space v_PSP_NS = (v_MSP_NS - 0x100) & 0xFFFFFFF8U; // allocate 256 bytes for NS task stack, double word aligned __TZ_set_PSP_NS(v_PSP_NS); // Set PSP_NS __TZ_set_CONTROL_NS(__TZ_get_CONTROL_NS()|0x2); // Set CONTROL_NS to use PSP // Create stack frame for exception return HW32_REG((v_PSP_NS + 0x1C)) = 0x01000000U; // xPSR HW32_REG((v_PSP_NS + 0x18)) = ptr; // PC HW32_REG((v_PSP_NS + 0x14)) = 0xFFFFFFFFU; // LR HW32_REG((v_PSP_NS + 0x10)) = 0; // r12 HW32_REG((v_PSP_NS + 0x0C)) = 0; // r3 HW32_REG((v_PSP_NS + 0x08)) = 0; // r2 HW32_REG((v_PSP_NS + 0x04)) = 0; // r1 HW32_REG((v_PSP_NS + 0x00)) = 0; // r0 printf ("Stack frame created, triggering PendSV...\n"); // Trigger Secure PendSV SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; __DSB(); __ISB(); // PendSV should be triggered now return ; }void __attribute__((naked)) PendSV_Handler(void){ __asm volatile ( "LDR R0,= 0xFFFFFFB9\n\t" "BX R0\n\t" // Exception return to NS thread ); }
================== Non-secure world =================
int main(void){ unsigned int p; UART_Config(); printf("Non-secure Hello world\n"); printf ("Run test\n"); p = (unsigned) NS_thread; // Get starting address of thread printf ("NS_thread address is 0x%x\n", p); set_thread_addr(p); // Pass address of NS_thread printf ("Return to NS world #1\n"); tz_test1(); printf ("Return to NS world #2\n"); while(1); } void NS_thread(void){ puts("[NS thread]\n"); while(1); return;}
Hi Joseph
Thanks for your answer, I will try it.
Best Regards
Yang Zhang
The example you provided is very good, I can return to a non-secure task from the PendSV interrupt now. But when I call a secure function (entry function) in the non-secure task, the program will jump to the secure memory. At this time, the PSP stack pointer is used. The use of the PSP will destroy the scene of the secure task. After several task switches have been performed, the program will appear hardfault. I think this is due to the use of both PSP and PSP_NS. Can you give me some advice?
Thank you very much.
Non-secure tasks also need Secure stack allocation if you want to allow them to call Secure APIs. So when the Non-secure task is created, a Secure stack space (possibly based on the maximum stack usage of a Secure API).
When doing context switch, you need need to switch both PSP_NS and PSP_S (and their stack limit registers).
Do you know any way to set the PSP in a non-secure task?
Non-secure software cannot set Secure PSP. Given that in your arrangement your RTOS is in Secure side, when you create the task you can allocate the Secure stack for it at the same time.
The context switching code (in Secure privileged side) can set the PSP_S.
I understand what you said, I wiil try it.
Thanks a lot.
Regarding stack frame, sorry for not clear. I meant the stack frame you created in Non-secure stack for the exception return to take place. What is in that stack frame?
Sorry for delay. I must have missed the notification email (too many emails).
A task (assume Non-secure unprivileged) can update SP (R13), and if the current selected SP is PSP, then it is updating PSP_NS.
But normally in an RTOS environment, the initial value of PSP_NS is initialized by the OS (not by the task itself) before the Non-secure task starts.