forked from espressif/esp-idf
Merge branch 'fix/fix_load_store_failure_mepc' into 'master'
fix(system): esp32p4: fix mepc when load/store failure occurred See merge request espressif/esp-idf!30252
This commit is contained in:
@@ -294,6 +294,14 @@ void panic_arch_fill_info(void *frame, panic_info_t *info)
|
|||||||
|
|
||||||
info->description = "Exception was unhandled.";
|
info->description = "Exception was unhandled.";
|
||||||
|
|
||||||
|
#if SOC_ASYNCHRONOUS_BUS_ERROR_MODE
|
||||||
|
uintptr_t bus_error_pc = rv_utils_asynchronous_bus_get_error_pc();
|
||||||
|
if (bus_error_pc) {
|
||||||
|
/* Change mepc with the fault pc address */
|
||||||
|
regs->mepc = bus_error_pc;
|
||||||
|
}
|
||||||
|
#endif // SOC_ASYNCHRONOUS_BUS_ERROR_MODE
|
||||||
|
|
||||||
info->addr = (void *) regs->mepc;
|
info->addr = (void *) regs->mepc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -155,6 +155,20 @@ extern "C" {
|
|||||||
#define TDATA1_HIT_S (20)
|
#define TDATA1_HIT_S (20)
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
Espressif's bus error exceptions registers and fields
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
#define MEXSTATUS 0x7E1
|
||||||
|
#define MHINT 0x7C5
|
||||||
|
|
||||||
|
#define LDPC0 0xBE0
|
||||||
|
#define LDPC1 0xBE1
|
||||||
|
|
||||||
|
#define STPC0 0xBF0
|
||||||
|
#define STPC1 0xBF1
|
||||||
|
#define STPC2 0xBF2
|
||||||
|
|
||||||
/* RISC-V CSR macros
|
/* RISC-V CSR macros
|
||||||
* Adapted from https://github.com/michaeljclark/riscv-probe/blob/master/libfemto/include/arch/riscv/machine.h
|
* Adapted from https://github.com/michaeljclark/riscv-probe/blob/master/libfemto/include/arch/riscv/machine.h
|
||||||
*/
|
*/
|
||||||
|
@@ -138,12 +138,12 @@ FORCE_INLINE_ATTR void rv_utils_intr_global_disable(void)
|
|||||||
* and `interrupt_intc.h`.
|
* and `interrupt_intc.h`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if SOC_CPU_HAS_FPU
|
|
||||||
|
|
||||||
/* ------------------------------------------------- FPU Related ----------------------------------------------------
|
/* ------------------------------------------------- FPU Related ----------------------------------------------------
|
||||||
*
|
*
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#if SOC_CPU_HAS_FPU
|
||||||
|
|
||||||
FORCE_INLINE_ATTR bool rv_utils_enable_fpu(void)
|
FORCE_INLINE_ATTR bool rv_utils_enable_fpu(void)
|
||||||
{
|
{
|
||||||
/* Set mstatus[14:13] to 0b01 to start the floating-point unit initialization */
|
/* Set mstatus[14:13] to 0b01 to start the floating-point unit initialization */
|
||||||
@@ -172,6 +172,48 @@ FORCE_INLINE_ATTR void rv_utils_disable_fpu(void)
|
|||||||
*
|
*
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
#if SOC_ASYNCHRONOUS_BUS_ERROR_MODE
|
||||||
|
|
||||||
|
FORCE_INLINE_ATTR uintptr_t rv_utils_asynchronous_bus_get_error_pc(void)
|
||||||
|
{
|
||||||
|
uint32_t error_pc;
|
||||||
|
uint32_t mcause, mexstatus;
|
||||||
|
|
||||||
|
mexstatus = RV_READ_CSR(MEXSTATUS);
|
||||||
|
/* MEXSTATUS: Bit 8: Indicates that a load/store access fault (MCAUSE=5/7)
|
||||||
|
* is due to bus-error exception. If this bit is not cleared before exiting
|
||||||
|
* the exception handler, it will trigger a bus error again.
|
||||||
|
* Since we have not mechanisms to recover a normal program execution after
|
||||||
|
* load/store error appears, do nothing. */
|
||||||
|
if ((mexstatus & BIT(8)) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
mcause = RV_READ_CSR(mcause) & 0xFF;
|
||||||
|
if (mcause == 5) { /* Load access fault */
|
||||||
|
/* Get the oldest PC at which the load instruction failed */
|
||||||
|
error_pc = RV_READ_CSR(LDPC1);
|
||||||
|
if (error_pc == 0) {
|
||||||
|
error_pc = RV_READ_CSR(LDPC0);
|
||||||
|
}
|
||||||
|
} else if (mcause == 7) { /* Store access fault */
|
||||||
|
/* Get the oldest PC at which the store instruction failed */
|
||||||
|
error_pc = RV_READ_CSR(STPC2);
|
||||||
|
if (error_pc == 0) {
|
||||||
|
error_pc = RV_READ_CSR(STPC1);
|
||||||
|
if (error_pc == 0) {
|
||||||
|
error_pc = RV_READ_CSR(STPC0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Bit 0: Valid bit indicating that this CSR holds the PC (program counter).
|
||||||
|
* Clear this bit */
|
||||||
|
return error_pc & ~(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SOC_ASYNCHRONOUS_BUS_ERROR_MODE
|
||||||
|
|
||||||
/* ---------------------------------------------------- Debugging ------------------------------------------------------
|
/* ---------------------------------------------------- Debugging ------------------------------------------------------
|
||||||
*
|
*
|
||||||
* ------------------------------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
@@ -1551,6 +1551,10 @@ config SOC_MEM_NON_CONTIGUOUS_SRAM
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_ASYNCHRONOUS_BUS_ERROR_MODE
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_EMAC_USE_IO_MUX
|
config SOC_EMAC_USE_IO_MUX
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
@@ -629,6 +629,7 @@
|
|||||||
/*-------------------------- Memory CAPS --------------------------*/
|
/*-------------------------- Memory CAPS --------------------------*/
|
||||||
#define SOC_MEM_TCM_SUPPORTED (1)
|
#define SOC_MEM_TCM_SUPPORTED (1)
|
||||||
#define SOC_MEM_NON_CONTIGUOUS_SRAM (1)
|
#define SOC_MEM_NON_CONTIGUOUS_SRAM (1)
|
||||||
|
#define SOC_ASYNCHRONOUS_BUS_ERROR_MODE (1)
|
||||||
/*--------------------------- EMAC --------------------------------*/
|
/*--------------------------- EMAC --------------------------------*/
|
||||||
#define SOC_EMAC_USE_IO_MUX (1) /*!< GPIO matrix is used to select GPIO pads */
|
#define SOC_EMAC_USE_IO_MUX (1) /*!< GPIO matrix is used to select GPIO pads */
|
||||||
|
|
||||||
|
@@ -39,6 +39,8 @@ void test_panic_extram_stack(void);
|
|||||||
void test_task_wdt_cpu1(void);
|
void test_task_wdt_cpu1(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void test_loadprohibited(void);
|
||||||
|
|
||||||
void test_storeprohibited(void);
|
void test_storeprohibited(void);
|
||||||
|
|
||||||
void test_cache_error(void);
|
void test_cache_error(void);
|
||||||
|
@@ -101,6 +101,7 @@ void app_main(void)
|
|||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
HANDLE_TEST(test_name, test_task_wdt_cpu1);
|
HANDLE_TEST(test_name, test_task_wdt_cpu1);
|
||||||
#endif
|
#endif
|
||||||
|
HANDLE_TEST(test_name, test_loadprohibited);
|
||||||
HANDLE_TEST(test_name, test_storeprohibited);
|
HANDLE_TEST(test_name, test_storeprohibited);
|
||||||
HANDLE_TEST(test_name, test_cache_error);
|
HANDLE_TEST(test_name, test_cache_error);
|
||||||
HANDLE_TEST(test_name, test_int_wdt_cache_disabled);
|
HANDLE_TEST(test_name, test_int_wdt_cache_disabled);
|
||||||
|
@@ -140,7 +140,15 @@ void test_task_wdt_cpu1(void)
|
|||||||
|
|
||||||
void __attribute__((no_sanitize_undefined)) test_storeprohibited(void)
|
void __attribute__((no_sanitize_undefined)) test_storeprohibited(void)
|
||||||
{
|
{
|
||||||
*(int*) 0x1 = 0;
|
*(int*) 0x4 = 0;
|
||||||
|
test_task_wdt_cpu0(); /* Trap for unhandled asynchronous bus errors */
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((no_sanitize_undefined)) test_loadprohibited(void)
|
||||||
|
{
|
||||||
|
static int __attribute__((used)) var;
|
||||||
|
var = *(int*) 0x4;
|
||||||
|
test_task_wdt_cpu0(); /* Trap for unhandled asynchronous bus errors */
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR test_cache_error(void)
|
void IRAM_ATTR test_cache_error(void)
|
||||||
@@ -222,7 +230,7 @@ void test_ub(void)
|
|||||||
* used for memory protection.
|
* used for memory protection.
|
||||||
*
|
*
|
||||||
* However, this test is not valid for S2 and S3, because they have PMS
|
* However, this test is not valid for S2 and S3, because they have PMS
|
||||||
* enabled on top of this, giving unpredicatable results.
|
* enabled on top of this, giving unpredictable results.
|
||||||
*/
|
*/
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
void test_illegal_access(void)
|
void test_illegal_access(void)
|
||||||
|
@@ -365,14 +365,12 @@ def test_illegal_instruction(
|
|||||||
common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
|
common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
def check_x_prohibited(dut: PanicTestDut, config: str, test_func_name: str, operation: str) -> None:
|
||||||
@pytest.mark.generic
|
|
||||||
def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
|
||||||
dut.run_test_func(test_func_name)
|
dut.run_test_func(test_func_name)
|
||||||
if dut.is_xtensa:
|
if dut.is_xtensa:
|
||||||
dut.expect_gme('StoreProhibited')
|
dut.expect_gme(f'{operation}Prohibited')
|
||||||
else:
|
else:
|
||||||
dut.expect_gme('Store access fault')
|
dut.expect_gme(f'{operation} access fault')
|
||||||
dut.expect_reg_dump(0)
|
dut.expect_reg_dump(0)
|
||||||
if dut.is_xtensa:
|
if dut.is_xtensa:
|
||||||
dut.expect_backtrace()
|
dut.expect_backtrace()
|
||||||
@@ -384,6 +382,18 @@ def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) ->
|
|||||||
common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
|
common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
check_x_prohibited(dut, config, test_func_name, 'Store')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_loadprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
check_x_prohibited(dut, config, test_func_name, 'Load')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
Reference in New Issue
Block a user