AnsweredAssumed Answered

Configure Shared Peripheral Interrupt as Secure to Handle in S-EL1 or EL3

Question asked by Matthias Stauber on Feb 19, 2020
Latest reply on Mar 6, 2020 by gusarambula

Hello,

 

I'm trying to figure out how to configure and handle secure interrupts on i.MX 8. Here is what I have found out so far:

 

  • GICv3 is initialized in EL3 by imx-atf through the following chain:
bl31_platform_setup
  --> plat_gic_driver_init
    --> gicv3_driver_init(&arm_gic_data);
  --> plat_gic_init
    --> gicv3_distif_init();                    // distributor interface
      --> gicv3_secure_spis_config_props        // Shared Peripheral Interrupts
    --> gicv3_rdistif_init(plat_my_core_pos()); // redistributor interface
    --> gicv3_cpuif_enable(plat_my_core_pos()); // CPU interface

 

This arm_gic_data is initialized as follows:

 

static const interrupt_prop_t g01s_interrupt_props[] = {
     INTR_PROP_DESC(6, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_LEVEL),
     INTR_PROP_DESC(7, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, GIC_INTR_CFG_LEVEL),
     INTR_PROP_DESC(78, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_LEVEL),  // <-- my entry here
};

const gicv3_driver_data_t arm_gic_data = {
     .gicd_base = PLAT_GICD_BASE,
     .gicr_base = PLAT_GICR_BASE,
     .interrupt_props = g01s_interrupt_props,  // my entry is passed through this field
     .interrupt_props_num = ARRAY_SIZE(g01s_interrupt_props),
     .rdistif_num = PLATFORM_CORE_COUNT,
     .rdistif_base_addrs = rdistif_base_addrs,
     .mpidr_to_core_pos = plat_imx_mpidr_to_core_pos,
};

 

My assumption was that by adding this entry for the wdog0 interrupt (78), I can have it routed to EL3 which would eventually route it to the S-EL1 payload (OP-TEE). However, if I enable the watchdog0 the interrupt is routed to GNU/Linux, as is shown here:

 

# cat /proc/interrupts | grep wdog
59:          0          0          0          0  GPC-PSCI  78 Edge      30280000.wdog
# [  194.865972] watchdog0: pretimeout event
# cat /proc/interrupts | grep wdog
59:          1          0          0          0  GPC-PSCI  78 Edge      30280000.wdog

 

Does anyone have experience with using secure interrupts and has an idea what I am still missing? I would expect the SoC to reset without the interrupt ever registering in GNU/Linux.

 

The wdog0 is just a more or less arbitrary example I chose because it would be triggered periodically.

 

Thank you in advance!

 

Edit: OP-TEE OS seems to do separate configuration of the GIC, and after inspecting CAAM driver code, I realized that 32 should be added to the actual interrupt number in OP-TEE, so 78 + 32 == 110. I do not understand why this is the case, but it likely has to do with the way OP-TEE accesses the GIC registers (32 is one register width).

 

Calling itr_add() in OP-TEE seems to apply the correct configuration, and the interrupt is no longer received inside GNU/Linux (the configuration in BL31 was most likely correct, too, but OP-TEE maybe just overrides everything as non-secure by default again).

 

However, now the interrupt is not passed to GNU/Linux, but I haven't figured out where it actually goes, since my OP-TEE registered handler is not being called, although itr_enable() is called, too.

Outcomes