Porting the qca_demo into TrustZone for board lpcxpresso55s69

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Porting the qca_demo into TrustZone for board lpcxpresso55s69

Jump to solution
2,098 Views
rtrimana
Contributor II

Hi Everyone, I am currently trying to port the qca_demo into TrustZone for the board lpcxpresso55s69. In the main loop, I could make the WIFI shield work by making a wrapper through NSC since it seems to change the value in SYSCON and so it needs secure access via NSC.

    /* Initialize WIFI shield */

    result = vWIFISHIELD_Init();

    assert(A_OK == result);

 However, it's getting stuck in this part waiting for WMI event I believe.

    /* Initialize the WIFI driver (thus starting the driver task) */
    result = wlan_driver_start();
    assert(A_OK == result);

Debugging this brought me into this part in the WiFi driver and it's basically waiting for the WMI event to happen. The code works perfectly fine when used without TrustZone.

        //		Api_BootProfile(pCxt, 0x00);
        /* Wait for Wmi event to be ready Implementation of this macro is platform specific
         * as multi-threaded systems will implement differently from single threaded. */
        /* Increased the WMI_READY timeout from 5 seconds to 15 seconds to allow
           firmware download over SPI interface */
        if (A_OK != DRIVER_WAIT_FOR_CONDITION(pCxt, &(pDCxt->wmiReady), true, 15000))
        {
            ret = A_ERROR;
            break;
        }

Can anyone please help with any insights? Thanks so much in advance.

Tags (2)
0 Kudos
1 Solution
2,052 Views
rtrimana
Contributor II

I did some further debugging on this and it turned out that to make this to work, we also have to set the "Interrupt security configuration". This can be found in the TEE setup: "Security Access Configuration" tab and set "Interrupt security configuration" for "Pin interrupt 1 or pattern match engine slice 1" and "System DMA 0 (non-secure)" to "Non-secure". By default, all entries are set to "Secure".

I believe the previous issue that caused the assertion was because the WiFi 10 Click board couldn't communicate with the host board (LPCXpresso55S69) and so the interrupts generated were not handled. Hope this thread can help people who try to do the same thing in the future. Please feel free to tag me if you have any questions and I will try to respond to you.

Thanks also to @Alice_Yang for your assistance and help.

View solution in original post

0 Kudos
8 Replies
2,068 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello rtrimana,

It seems you have solved your issue, and pay attention the points when use Trustzone:

Alice_Yang_0-1659512564971.png

Alice_Yang_1-1659512581554.png

 

 

 

 

 

0 Kudos
2,060 Views
rtrimana
Contributor II

Hi @Alice_Yang ,

Thanks for the tip, but I don't think I have fully solved the issue. How about the current issue that the code is getting stuck at the assertion? I tried to debug more and it seems that the driver is not getting any signal from the WiFi module. I am using this WiFi module from Mikroe: https://www.mikroe.com/wifi-10-click.

Could it be that the SPI pins are blocked by TEE for NS in this case? Do you have any suggestions/thoughts/recommendations?

0 Kudos
2,053 Views
rtrimana
Contributor II

I did some further debugging on this and it turned out that to make this to work, we also have to set the "Interrupt security configuration". This can be found in the TEE setup: "Security Access Configuration" tab and set "Interrupt security configuration" for "Pin interrupt 1 or pattern match engine slice 1" and "System DMA 0 (non-secure)" to "Non-secure". By default, all entries are set to "Secure".

I believe the previous issue that caused the assertion was because the WiFi 10 Click board couldn't communicate with the host board (LPCXpresso55S69) and so the interrupts generated were not handled. Hope this thread can help people who try to do the same thing in the future. Please feel free to tag me if you have any questions and I will try to respond to you.

Thanks also to @Alice_Yang for your assistance and help.

0 Kudos
1,190 Views
yuripo
Contributor I
Hi!
Thanks for the post. I have the same problem while importing qca_demo into rtos trustzone example. Can you please provide some example code?
0 Kudos
2,084 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello,

How do you allocate code in secure part and Non-secure part?

Recommend you first read the Trustzone knowledge from UM of lpc55s69, and there is Trustzone demo under SDK, recommend you first run and check it. Also I attach a hands-on description about the this Trustzone demo.

 

BR

Alice

0 Kudos
2,050 Views
rtrimana
Contributor II

Hi @Alice_Yang , thanks so much for your response. Please disregard the error I posted in my first post. I was trying different things and that was one of the bad outputs.

I basically use the FreeRTOS blinky demo as my base code for RTOS and TrustZone. I tried using the Hello World TZ example but that did not come with FreeRTOS setup so it was harder to adjust.

Here's what I did to the FreeRTOS blinky demo:

(1) I integrate the functions and options etc. from the qca_demo with the blinky demo. I also resized the memory partitions, especially for NSC since it might need to contain more non-secure callable functions (the S and NS levels are kept to preserve the levels, e.g., S-Priv, NSC-Priv, etc.).

(2) I keep the S and NS code and I modified the prvCreateTasks() to instead create the task from the qca_demo. Please see the code below.

...
void task_main(void *param)
{
    /* This task calls secure side functions. So allocate a
     * secure context for it. */
    portALLOCATE_SECURE_CONTEXT(configMINIMAL_SECURE_STACK_SIZE);

    int32_t result = 0;
    (void)result;

    /* Initialize WIFI shield */
    result = WIFISHIELD_Init_NSE();
    assert(A_OK == result);
    /* Initialize the WIFI driver (thus starting the driver task) */
    //result = wlan_driver_start_NSE();
    result = wlan_driver_start();
    assert(A_OK == result);
...
}
...
static void prvCreateTasks(void)
{
    /* Create the WiFi task. */
	BaseType_t result =
//        xTaskCreate(task_main, "main", TASK_MAIN_STACK_SIZE, task_main_stack, TASK_MAIN_PRIO, &task_main_task_handler);
		xTaskCreate(task_main, "main", TASK_MAIN_STACK_SIZE, task_main_stack, portPRIVILEGE_BIT | tskIDLE_PRIORITY, &task_main_task_handler);
	assert(pdPASS == result);
}

(3) The original FreeRTOSConfig.h from qca_demo contains the following options.

#define configENABLE_MPU                                0
#define configENABLE_FPU                                0
#define configENABLE_TRUSTZONE                          0
#define configRUN_FREERTOS_SECURE_ONLY                  1

I changed it into the following.

#define configENABLE_MPU                                0
#define configENABLE_FPU                                0
#define configENABLE_TRUSTZONE                          1
#define configRUN_FREERTOS_SECURE_ONLY                  0

Initially the configEnable_MPU and configENABLE_FPU were also set for the blinky demo but I set them to 0 instead to simplify the setup for now since I realized partitioning the code into privilege levels based on MPU made things worse.

This all compiles and runs (please see the source code attached), and it goes well and creates the first task for task_main as shown in (1). However, currently the code gets the HardFault when trying to create the second task for the Atheros driver in driver_main.c.

status = xTaskCreate(Atheros_Driver_Task, "Atheros_Wifi_Task", ATHEROS_TASK_STACKSIZE, pCxt, ATHEROS_TASK_PRIORITY,
                         &atheros_wifi_task_id);

Upon stepping into this function, I followed the execution path and found that the following function might be the problem.

void vPortYield( void ) /* PRIVILEGED_FUNCTION */
{
    /* Set a PendSV to request a context switch. */
    portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;

    /* Barriers are normally not required but do ensure the code is
     * completely within the specified behaviour for the architecture. */
    __asm volatile ( "dsb" ::: "memory" );
    __asm volatile ( "isb" );
}

Basically, it looks to me that the first task is already running, and the scheduler wants to run this task as it is given a higher priority. But when the scheduler tries to perform this yield function to yield the first task and run the second task instead, it gives the HardFault. Please let me know if you have any thoughts on what the problem could be.

Thanks so much for the attached document. I'll have a look and follow what's inside. Looking forward to hearing back from you again.

0 Kudos
2,048 Views
rtrimana
Contributor II

I took a look at the slides and I think I got a pretty good idea about the Demo and the HardFault I was getting. Currently, I tried to set the SYSCON and IOCON to NS-User so that the GPIO pins can be configured by the non-secure world. I did this through the TEE option: the settings for both SYSCON and IOCON are available on the Masters/Slaves tab.

I think the WIFISHIELD is now configurable without calling the NSC function to get help from the secure world, and the two threads (task_main and Atheros) were created successfully. However, I think it failed to get past this part of the code in cust_api_init.c.

        /* Api_InitFinish waits for wmi_ready event from chip. */
        if (A_OK != Api_InitFinish(p_Global_Cxt))
        {
            error = QCA_ERROR;
            break;
        }

Basically, I am getting QCA_ERROR from calling this Api_InitFinish(). And so the flow ended up hitting an assertion in fsl_assert.c as shown below.

void __assert_func(const char *file, int line, const char *func, const char *failedExpr)
{
    PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" function name \"%s\" \n", failedExpr, file, line, func);
    for (;;)
    {
        __BKPT(0);
    }
}
 
 
0 Kudos
2,046 Views
rtrimana
Contributor II

Sorry, one more thing I forgot to mention was that I had to create an NSC function as a wrapper for the WIFISHIELD_init() function because it is trying to set the SYSCON register and so it needs the secure access.

#if defined(__IAR_SYSTEMS_ICC__)
__cmse_nonsecure_entry
#else
__attribute__((cmse_nonsecure_entry))
#endif
	int32_t
    WIFISHIELD_Init_NSE()
{
    /* Initialize WiFi shield. */
	return WIFISHIELD_Init();
}

 This function is being called in the task_main() in main_ns.c.

0 Kudos