uVisor prevents LwIP/Hal from properly using ENET hardware when enabled
- Dominant language
- C
- Stars
- 135
- Forks
- 72
- PR merge metrics
- No merged PRs in 30d
Description
**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](https://github.com/ARMmbed/mbed-os/tree/master/features/net/FEATURE_IPV4/lwip-interface).
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](https://www.keil.com/pack/doc/cmsis/Core/html/group___n_v_i_c__gr.html) 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](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0179b/ar01s02s07.html) 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.
Contributor guide
Research direction
Start with features/net/FEATURE_IPV4/lwip-interface/lwip-eth/arch/TARGET_Freescale/hardware_init_MK64F12.c and hal/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_MCU_K64F/drivers/fsl_enet.c. Trace the MPU write, EnableIRQ/NVIC_EnableIRQ in fsl_common.h, and the SVC_Handler behavior under the supplied ACL. Done means identifying the uVisor configuration or compatibility issue that prevents Ethernet initialization.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- embedded-iot, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100