Skip to content

uVisor prevents LwIP/Hal from properly using ENET hardware when enabled #315

@sherrellbc

Description

@sherrellbc

EDIT: I changed the issue's name to more appropriately track the purpose of this thread after relevant information has been uncovered surrounding the original problem.


I have been trying to determine the appropriate uVisor ACL such that I can use the Ethernet hardware on the FRDM K64F development board. After a few hours of debugging and tracing the problem I managed to determine two points of failure when using EthernetInterface.cpp and (a dependency thereof) the LWIP implementation; the root of the corresponding source tree can be found here.

The first problem I found was that the LWIP implementation was trying to disable the MPU, which I thought might be problematic for uVisor.

MPU->CESR &= ~MPU_CESR_VLD_MASK;

https://github.com/ARMmbed/mbed-os/blob/master/features/net/FEATURE_IPV4/lwip-interface/lwip-eth/arch/TARGET_Freescale/hardware_init_MK64F12.c#L41

I have defined the MPU as an enabled memory range in my ACL, but that does not prevent the system from stopping on that instruction.

const UvisorBoxAclItem g_main_acl[] = {     
         {SIM,    sizeof(*SIM),    UVISOR_TACLDEF_PERIPH}, 
         {OSC,    sizeof(*OSC),    UVISOR_TACLDEF_PERIPH}, 
         {MCG,    sizeof(*MCG),    UVISOR_TACLDEF_PERIPH}, 
         {PORTA,  sizeof(*PORTA),  UVISOR_TACLDEF_PERIPH}, 
         {PORTB,  sizeof(*PORTB),  UVISOR_TACLDEF_PERIPH}, 
         {PORTC,  sizeof(*PORTC),  UVISOR_TACLDEF_PERIPH}, 
         {PORTD,  sizeof(*PORTD),  UVISOR_TACLDEF_PERIPH}, 
         {PORTE,  sizeof(*PORTE),  UVISOR_TACLDEF_PERIPH}, 
         {RTC,    sizeof(*RTC),    UVISOR_TACLDEF_PERIPH}, 
         {LPTMR0, sizeof(*LPTMR0), UVISOR_TACLDEF_PERIPH}, 
         {PIT,    sizeof(*PIT),    UVISOR_TACLDEF_PERIPH}, 
         {SMC,    sizeof(*SMC),    UVISOR_TACLDEF_PERIPH}, 
         {UART0,  sizeof(*UART0),  UVISOR_TACLDEF_PERIPH}, 
         {I2C0,   sizeof(*I2C0),   UVISOR_TACLDEF_PERIPH},
         {SPI0,   sizeof(*SPI0),   UVISOR_TACLDEF_PERIPH},
         {MPU,  sizeof(*MPU), UVISOR_TACLDEF_PERIPH}, 

         /* EthernetInterface */
         {ENET,   sizeof(*ENET),   UVISOR_TACLDEF_PERIPH}, 
         {EWM,    sizeof(*EWM),   UVISOR_TACLDEF_PERIPH}, 
};

The second problem was related to a call to EnableIRQ in fsl_enet.c. At the highest level, a call to EthernetInterface.connect() will lead to execution of the following.

/* Enables Ethernet interrupt and NVIC. */
    ENET_EnableInterrupts(base, config->interrupt);
    if (config->interrupt & (kENET_RxByteInterrupt | kENET_RxFrameInterrupt))
    {
        EnableIRQ(s_enetRxIrqId[instance]);
    }
    if (config->interrupt & (kENET_TxByteInterrupt | kENET_TxFrameInterrupt))
    {
        EnableIRQ(s_enetTxIrqId[instance]);
    }
    if (config->interrupt & (kENET_BabrInterrupt | kENET_BabtInterrupt | kENET_GraceStopInterrupt | kENET_MiiInterrupt |
                             kENET_EBusERInterrupt | kENET_LateCollisionInterrupt | kENET_RetryLimitInterrupt |
                             kENET_UnderrunInterrupt | kENET_PayloadRxInterrupt | kENET_WakeupInterrupt))
    {
        EnableIRQ(s_enetErrIrqId[instance]);
    }

https://github.com/ARMmbed/mbed-os/blob/master/hal/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_enet.c#L453

As it turns out, EnableIRQ() is an inline function defined in fsl_common.h as a link to an NVIC_EnableIRQ call:

static inline void EnableIRQ(IRQn_Type interrupt)
{
#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT > 0)
    if (interrupt < FSL_FEATURE_INTMUX_IRQ_START_INDEX)
#endif
    {
        NVIC_EnableIRQ(interrupt);
    }
}

https://github.com/ARMmbed/mbed-os/blob/master/hal/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_common.h#L182

I could not trace the NVIC definition down any further as there were a very large number of them. However, I did check out the generated source code in a disassembler and it seems that NVIC_EnableIRQ is being translated to an SVC 3 call.

Are there a special configuration required for this? Does the default SVC_Handler function not handled this case for enabling interrupts? The behavior I am observing is that a call to this function never returns, so I can only guess (since I do not have a debugger) that the uVisor is trapping on this call.


As a side note, I tried using UVISOR_PERMISSIVE for my main ACL, but the problem still persists.

Are there any obvious problems with using NVIC_EnableIRQ or writing to the MPU? Are there additional configuration requirements to support either?

If I comment out the offending MPU and NVIC_EnableIRQ lines then everything executes without issue -- except the Ethernet hardware does not work, of course.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions