Hello,

I am trying to write an Application RoT for a research project I am a part of. I have run into an issue that I have been unable to solve independently.

My problem is the unexpected behavior of psa_wait() when using signal masks.
I have two signals, TFM_TIMER1_IRQ_SIGNAL and TFM_SECURE_FUNCTION_SIGNAL. The TIMER1_IRQ signal is triggered by an FLIH interrupt handler that returns TFM_FLIH_SIGNAL. The interrupt is triggered every 1 second by TIMER1. The TFM_SECURE_FUNCTION_SIGNAL is triggered by a periodic function call from the NSPE (a Zephyr thread) and is called every 10 seconds.

Observed result:
If PSA_WAIT_ANY is used as a signal mask, the TIMER0_IRQ_SIGNAL will only be received when TFM_SECURE_FUNCTION_SIGNAL is received, ergo, every 10 s. Thus any stage 2 handling of an interrupt would be missed.

If TFM_TIMER1_IRQ_SIGNAL is used as a signal mask, the signal will be received every 1 s as expected. The TFM_SECURE_FUNCTION_SIGNAL will never be received, as can be expected in the NSPEtoo.

I have tried a "hybrid approach" where I call psa_wait(TFM_TIMER1_IRQ_SIGNAL, PSA_BLOCK) /* handle signals .... */ and then psa_wait(TFM_SECURE_FUNCTION_SIGNAL, PSA_POLL). The stage 2 IRS is called, and the secure function is also called. But not with the regularity that I would like.

Am I missing something obvious? I have read the Secure Interrupt Integration Guide and carefully studied the SLIH and FLIH test services for the TF-M regression tests. Have I forgotten to reset a signal somewhere? Does the interrupt not preempt the NSPE?

I would be immensely grateful for any or all responses. If you need more information, please let me know.

Best wishes,

Martin Gunnarsson
PhD Student
RISE Research Institutes of Sweden & Lund University

Complete code of my Application RoT:
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#include "tfm_api.h"
#include "tfm_secure_api.h"

#include "psa/service.h"
#include "tfm_sp_log.h"

#include "psa_manifest/pid.h"
#include "psa_manifest/tfm_secure_partition.h"

#include <hal/nrf_gpio.h>
#include <hal/nrf_timer.h>
#include <helpers/nrfx_reset_reason.h>
#include <nrf_board.h>
#include <region_defs.h>


#define TIMER_RELOAD_VALUE (1*1024*1024)
static volatile uint32_t interrupt_ctr = 0;
static volatile uint32_t function_ctr = 0;

static void timer_init(NRF_TIMER_Type * TIMER)
{
    nrf_timer_mode_set(TIMER, NRF_TIMER_MODE_TIMER);
    nrf_timer_bit_width_set(TIMER, NRF_TIMER_BIT_WIDTH_32);
    nrf_timer_frequency_set(TIMER, NRF_TIMER_FREQ_1MHz);
    nrf_timer_cc_set(TIMER, NRF_TIMER_CC_CHANNEL0, TIMER_RELOAD_VALUE);
    /* Clear the timer once event is generated. */
    nrf_timer_shorts_enable(TIMER, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);
}

static void timer_stop(NRF_TIMER_Type * TIMER)
{
    nrf_timer_task_trigger(TIMER, NRF_TIMER_TASK_STOP);
    nrf_timer_int_disable(TIMER, NRF_TIMER_INT_COMPARE0_MASK);
    nrf_timer_event_clear(TIMER, NRF_TIMER_EVENT_COMPARE0);
}

static void timer_start(NRF_TIMER_Type * TIMER)
{
    timer_stop(TIMER);

    nrf_timer_task_trigger(TIMER, NRF_TIMER_TASK_CLEAR);
    nrf_timer_int_enable(TIMER, NRF_TIMER_INT_COMPARE0_MASK);

    nrf_timer_task_trigger(TIMER, NRF_TIMER_TASK_START);
}

static void timer_event_clear(NRF_TIMER_Type *TIMER)
{
    nrf_timer_event_clear(TIMER, NRF_TIMER_EVENT_COMPARE0);
}

void tfm_secure_controller_secure_timer_start(void)
{
    timer_init(NRF_TIMER1);
    timer_start(NRF_TIMER1);
}

void tfm_secure_controller_secure_timer_clear_intr(void)
{
    timer_event_clear(NRF_TIMER1);
}


psa_flih_result_t tfm_timer1_irq_flih(void)
{
  tfm_secure_controller_secure_timer_clear_intr();
  interrupt_ctr++;
  return PSA_FLIH_SIGNAL;
}

static psa_status_t tfm_sp_secure_function_ipc(psa_msg_t *msg)
{
    function_ctr++;
    LOG_INFFMT("Secure function called %u times, interrupt ctr: %u\n", function_ctr, interrupt_ctr );
    return PSA_SUCCESS;
}

void tfm_sp_secure_function(psa_msg_t *msg) {
  psa_status_t status;
  status = tfm_sp_secure_function_ipc(msg);
  psa_reply(msg->handle, status);
}

void tfm_sp_entry(void)
{
    LOG_INFFMT("Secure Partition: Init\n");
   
    tfm_secure_controller_secure_timer_start();
    psa_irq_enable(TFM_TIMER1_IRQ_SIGNAL);
    psa_signal_t signals = 0;
    uint32_t ctr = 0;

    while (1) {
        signals = psa_wait(TFM_TIMER1_IRQ_SIGNAL, PSA_BLOCK);
        if ( (signals & TFM_TIMER1_IRQ_SIGNAL) == TFM_TIMER1_IRQ_SIGNAL) {
          ctr++;
          LOG_INFFMT("FLIH stage 2 %u\n", interrupt_ctr);
          psa_reset_signal(TFM_TIMER1_IRQ_SIGNAL);
        }
     
        if ( ctr % 10 == 0 ) {
          signals = psa_wait(PSA_WAIT_ANY, PSA_POLL);
          if ( (signals & TFM_SECURE_FUNCTION_SIGNAL) == TFM_SECURE_FUNCTION_SIGNAL) {
            psa_msg_t msg;
            psa_get(signals, &msg);
            tfm_sp_secure_function(&msg);
       
          }
        }
    }  
}