feat(system): esp32p4: support hw stack guard

This commit is contained in:
Alexey Lapshin 2024-01-20 00:21:18 +04:00
parent 22ee3e8aa6
commit 13b55386bf
16 changed files with 299 additions and 74 deletions

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -15,15 +15,20 @@ ESP_SYSTEM_INIT_FN(esp_hw_stack_guard_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES
{
uint32_t core_id = esp_cpu_get_core_id();
if (core_id == 0) {
/* initialize the peripheral only when running on core 0 */
periph_module_enable(PERIPH_ASSIST_DEBUG_MODULE);
periph_module_reset(PERIPH_ASSIST_DEBUG_MODULE);
ESP_INTR_DISABLE(ETS_ASSIST_DEBUG_INUM);
#if SOC_CPU_CORES_NUM > 1
PERIPH_RCC_ATOMIC()
#endif
{
assist_debug_ll_enable_bus_clock(true);
assist_debug_ll_reset_register();
}
/* just in case, disable the interrupt and clear pending status */
assist_debug_hal_sp_int_disable(core_id);
assist_debug_hal_sp_int_clear(core_id);
/* set interrupt to matrix */
esp_rom_route_intr_matrix(core_id, ETS_ASSIST_DEBUG_INTR_SOURCE, ETS_ASSIST_DEBUG_INUM);
esprv_int_set_type(ETS_ASSIST_DEBUG_INUM, INTR_TYPE_LEVEL);
esprv_int_set_priority(ETS_ASSIST_DEBUG_INUM, SOC_INTERRUPT_LEVEL_MEDIUM);
/*
* enable interrupt
@ -37,12 +42,6 @@ ESP_SYSTEM_INIT_FN(esp_hw_stack_guard_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES
*/
assist_debug_hal_sp_int_enable(core_id);
/* enable interrup routine */
esp_rom_route_intr_matrix(core_id, ETS_ASSIST_DEBUG_INTR_SOURCE, ETS_ASSIST_DEBUG_INUM);
esprv_int_set_type(ETS_ASSIST_DEBUG_INUM, INTR_TYPE_LEVEL);
esprv_int_set_priority(ETS_ASSIST_DEBUG_INUM, SOC_INTERRUPT_LEVEL_MEDIUM);
ESP_INTR_ENABLE(ETS_ASSIST_DEBUG_INUM);
return ESP_OK;
}
@ -72,23 +71,22 @@ void esp_hw_stack_guard_set_bounds(uint32_t sp_min, uint32_t sp_max)
assist_debug_hal_set_sp_bounds(core_id, sp_min, sp_max);
}
void esp_hw_stack_guard_get_bounds(uint32_t *sp_min, uint32_t *sp_max)
void esp_hw_stack_guard_get_bounds(uint32_t core_id, uint32_t *sp_min, uint32_t *sp_max)
{
uint32_t core_id = esp_cpu_get_core_id();
assist_debug_hal_get_sp_bounds(core_id, sp_min, sp_max);
}
bool esp_hw_stack_guard_is_fired(void)
uint32_t esp_hw_stack_guard_get_fired_cpu(void)
{
uint32_t core_id = esp_cpu_get_core_id();
return assist_debug_hal_is_sp_ovf_fired(core_id);
for (uint32_t i = 0; i < SOC_CPU_CORES_NUM; i++) {
if (assist_debug_hal_is_sp_ovf_fired(i)) {
return i;
}
}
return ESP_HW_STACK_GUARD_NOT_FIRED;
}
uint32_t esp_hw_stack_guard_get_pc(void)
uint32_t esp_hw_stack_guard_get_pc(uint32_t core_id)
{
uint32_t core_id = esp_cpu_get_core_id();
return assist_debug_hal_get_sp_ovf_pc(core_id);
}

View File

@ -9,7 +9,7 @@ entries:
reset_reason:esp_reset_reason_get_hint (noflash)
if ESP_SYSTEM_HW_STACK_GUARD = y:
hw_stack_guard:esp_hw_stack_guard_get_bounds (noflash)
hw_stack_guard:esp_hw_stack_guard_is_fired (noflash)
hw_stack_guard:esp_hw_stack_guard_get_fired_cpu (noflash)
hw_stack_guard:esp_hw_stack_guard_get_pc (noflash)
esp_err (noflash)

View File

@ -60,20 +60,21 @@ static inline void print_cache_err_details(const void *frame)
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
static inline void print_assist_debug_details(const void *frame)
{
uint32_t core_id = esp_cpu_get_core_id();
uint32_t core_id = esp_hw_stack_guard_get_fired_cpu();
if (core_id == ESP_HW_STACK_GUARD_NOT_FIRED) {
panic_print_str("ASSIST_DEBUG is not triggered BUT interrupt occured!\r\n\r\n");
core_id = 0;
}
uint32_t sp_min, sp_max;
const char *task_name = pcTaskGetName(xTaskGetCurrentTaskHandleForCore(core_id));
esp_hw_stack_guard_get_bounds(&sp_min, &sp_max);
esp_hw_stack_guard_get_bounds(core_id, &sp_min, &sp_max);
panic_print_str("\r\n");
if (!esp_hw_stack_guard_is_fired()) {
panic_print_str("ASSIST_DEBUG is not triggered BUT interrupt occured!\r\n\r\n");
}
panic_print_str("Detected in task \"");
panic_print_str(task_name);
panic_print_str("\" at 0x");
panic_print_hex((int) esp_hw_stack_guard_get_pc());
panic_print_hex((int) esp_hw_stack_guard_get_pc(core_id));
panic_print_str("\r\n");
panic_print_str("Stack pointer: 0x");
panic_print_hex((int)((RvExcFrame *)frame)->sp);
@ -250,7 +251,10 @@ void panic_soc_fill_info(void *f, panic_info_t *info)
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
else if (frame->mcause == ETS_ASSIST_DEBUG_INUM) {
info->core = esp_cache_err_get_cpuid();
info->core = esp_hw_stack_guard_get_fired_cpu();
if (info->core == ESP_HW_STACK_GUARD_NOT_FIRED) {
info->core = 0;
}
info->reason = "Stack protection fault";
info->details = print_assist_debug_details;
}

View File

@ -14,15 +14,17 @@
extern "C" {
#endif
#define ESP_HW_STACK_GUARD_NOT_FIRED UINT32_MAX
/* The functions below are designed to be used in interrupt/panic handler
* In case using them in user's code put them into critical section.*/
void esp_hw_stack_guard_monitor_start(void);
void esp_hw_stack_guard_monitor_stop(void);
void esp_hw_stack_guard_set_bounds(uint32_t sp_min, uint32_t sp_max);
void esp_hw_stack_guard_get_bounds(uint32_t *sp_min, uint32_t *sp_max);
bool esp_hw_stack_guard_is_fired(void);
uint32_t esp_hw_stack_guard_get_pc(void);
void esp_hw_stack_guard_get_bounds(uint32_t core_id, uint32_t *sp_min, uint32_t *sp_max);
uint32_t esp_hw_stack_guard_get_fired_cpu(void);
uint32_t esp_hw_stack_guard_get_pc(uint32_t core_id);
#ifdef __cplusplus
};
@ -33,8 +35,9 @@ uint32_t esp_hw_stack_guard_get_pc(void);
#include "hal/assist_debug_ll.h"
#define ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM (ASSIST_DEBUG_CORE_0_INTR_ENA_REG >> 12)
#define ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET (ASSIST_DEBUG_CORE_0_SP_MIN_REG - ASSIST_DEBUG_CORE_0_INTR_ENA_REG)
#define ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET (ASSIST_DEBUG_CORE_0_SP_MAX_REG - ASSIST_DEBUG_CORE_0_INTR_ENA_REG)
#define ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET (ASSIST_DEBUG_CORE_0_SP_MIN_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET (ASSIST_DEBUG_CORE_0_SP_MAX_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET (ASSIST_DEBUG_CORE_0_INTR_ENA_REG - DR_REG_ASSIST_DEBUG_BASE)
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0 reg1
lui \reg1, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
@ -44,23 +47,24 @@ sw a1, ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET(\reg1)
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
lw \reg2, 0(\reg1)
lw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
andi \reg2, \reg2, ~ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, 0(\reg1)
sw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU0 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
lw \reg2, 0(\reg1)
lw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
ori \reg2, \reg2, ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, 0(\reg1)
sw \reg2, ASSIST_DEBUG_CORE_0_SP_SPILL_OFFSET(\reg1)
.endm
#if SOC_CPU_CORES_NUM > 1
#define ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM (ASSIST_DEBUG_CORE_1_INTR_ENA_REG >> 12)
#define ASSIST_DEBUG_CORE_1_SP_MIN_OFFSET (ASSIST_DEBUG_CORE_1_SP_MIN_REG - ASSIST_DEBUG_CORE_1_INTR_ENA_REG)
#define ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET (ASSIST_DEBUG_CORE_1_SP_MAX_REG - ASSIST_DEBUG_CORE_1_INTR_ENA_REG)
#define ASSIST_DEBUG_CORE_1_SP_MIN_OFFSET (ASSIST_DEBUG_CORE_1_SP_MIN_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET (ASSIST_DEBUG_CORE_1_SP_MAX_REG - DR_REG_ASSIST_DEBUG_BASE)
#define ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET (ASSIST_DEBUG_CORE_1_INTR_ENA_REG - DR_REG_ASSIST_DEBUG_BASE)
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU1 reg1
lui \reg1, ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM
@ -70,22 +74,22 @@ sw a1, ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET(\reg1)
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU1 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM
lw \reg2, 0(\reg1)
lw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
andi \reg2, \reg2, ~ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, 0(\reg1)
sw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU1 reg1 reg2
lui \reg1, ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM
lw \reg2, 0(\reg1)
lw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
ori \reg2, \reg2, ASSIST_DEBUG_SP_SPILL_BITS
sw \reg2, 0(\reg1)
sw \reg2, ASSIST_DEBUG_CORE_1_SP_SPILL_OFFSET(\reg1)
.endm
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE reg1
/* Check the current core ID */
csrr \reg1, mhartid
beqz \reg1, @1f
beqz \reg1, 1f
/* Core 1 */
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU1 \reg1
j 2f
@ -98,7 +102,7 @@ ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0 \reg1
.macro ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE reg1 reg2
/* Check the current core ID */
csrr \reg1, mhartid
beqz \reg1, @1f
beqz \reg1, 1f
/* Core 1 */
ESP_HW_STACK_GUARD_MONITOR_START_CPU1 \reg1 \reg2
j 2f
@ -111,7 +115,7 @@ ESP_HW_STACK_GUARD_MONITOR_START_CPU0 \reg1 \reg2
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE reg1 reg2
/* Check the current core ID */
csrr \reg1, mhartid
beqz \reg1, @1f
beqz \reg1, 1f
/* Core 1 */
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU1 \reg1 \reg2
j 2f

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -37,6 +37,10 @@
#include "hal/wdt_types.h"
#include "hal/wdt_hal.h"
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
#include "esp_private/hw_stack_guard.h"
#endif
extern int _invalid_pc_placeholder;
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
@ -117,6 +121,14 @@ static void frame_to_panic_info(void *frame, panic_info_t *info, bool pseudo_exc
info->frame = frame;
}
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
FORCE_INLINE_ATTR __attribute__((__noreturn__))
void busy_wait(void)
{
while (1) {;} // infinite loop
}
#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
static void panic_handler(void *frame, bool pseudo_excause)
{
panic_info_t info = { 0 };
@ -134,19 +146,24 @@ static void panic_handler(void *frame, bool pseudo_excause)
// These are cases where both CPUs both go into panic handler. The following code ensures
// only one core proceeds to the system panic handler.
if (pseudo_excause) {
#define BUSY_WAIT_IF_TRUE(b) { if (b) while(1); }
// For WDT expiry, pause the non-offending core - offending core handles panic
BUSY_WAIT_IF_TRUE(panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU0 && core_id == 1);
BUSY_WAIT_IF_TRUE(panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1 && core_id == 0);
// For cache error, pause the non-offending core - offending core handles panic
if (panic_get_cause(frame) == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid()) {
// Only print the backtrace for the offending core in case of the cache error
g_exc_frames[core_id] = NULL;
while (1) {
;
}
// For WDT expiry, pause the non-offending core - offending core handles panic
if (panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU0 && core_id == 1) {
busy_wait();
} else if (panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1 && core_id == 0) {
busy_wait();
} else if (panic_get_cause(frame) == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid()) {
g_exc_frames[core_id] = NULL; // Only print the backtrace for the offending core
busy_wait();
}
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
else if (panic_get_cause(frame) == ETS_ASSIST_DEBUG_INUM &&
esp_hw_stack_guard_get_fired_cpu() != core_id &&
esp_hw_stack_guard_get_fired_cpu() != ESP_HW_STACK_GUARD_NOT_FIRED) {
g_exc_frames[core_id] = NULL; // Only print the backtrace for the offending core
busy_wait();
}
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
}
// Need to reconfigure WDTs before we stall any other CPU

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,6 +17,7 @@
#include <stdint.h>
#include "esp_attr.h"
#include "hal/assert.h"
#include "soc/system_struct.h"
#ifdef __cplusplus
extern "C" {
@ -54,7 +55,7 @@ extern "C" {
* interrupt, instead of "ENA".
*/
/* These functions are optimazed and designed for internal usage.
/* These functions are optimized and designed for internal usage.
* So, the API may differ from general ll layer pattern */
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_enable(__attribute__((unused)) uint32_t core_id)
@ -112,6 +113,17 @@ FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
}
FORCE_INLINE_ATTR void assist_debug_ll_enable_bus_clock(bool enable)
{
SYSTEM.cpu_peri_clk_en.clk_en_assist_debug = enable;
}
FORCE_INLINE_ATTR void assist_debug_ll_reset_register(void)
{
SYSTEM.cpu_peri_rst_en.rst_en_assist_debug = true;
SYSTEM.cpu_peri_rst_en.rst_en_assist_debug = false;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,6 +17,7 @@
#include <stdint.h>
#include "esp_attr.h"
#include "hal/assert.h"
#include "soc/system_struct.h"
#ifdef __cplusplus
extern "C" {
@ -54,7 +55,7 @@ extern "C" {
* interrupt, instead of "ENA".
*/
/* These functions are optimazed and designed for internal usage.
/* These functions are optimized and designed for internal usage.
* So, the API may differ from general ll layer pattern */
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_enable(__attribute__((unused)) uint32_t core_id)
@ -112,6 +113,17 @@ FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
}
FORCE_INLINE_ATTR void assist_debug_ll_enable_bus_clock(bool enable)
{
SYSTEM.cpu_peri_clk_en.reg_clk_en_assist_debug = enable;
}
FORCE_INLINE_ATTR void assist_debug_ll_reset_register(void)
{
SYSTEM.cpu_peri_rst_en.reg_rst_en_assist_debug = true;
SYSTEM.cpu_peri_rst_en.reg_rst_en_assist_debug = false;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,6 +17,7 @@
#include <stdint.h>
#include "esp_attr.h"
#include "hal/assert.h"
#include "soc/pcr_struct.h"
#ifdef __cplusplus
extern "C" {
@ -54,7 +55,7 @@ extern "C" {
* interrupt, instead of "ENA".
*/
/* These functions are optimazed and designed for internal usage.
/* These functions are optimized and designed for internal usage.
* So, the API may differ from general ll layer pattern */
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_enable(__attribute__((unused)) uint32_t core_id)
@ -112,6 +113,17 @@ FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
}
FORCE_INLINE_ATTR void assist_debug_ll_enable_bus_clock(bool enable)
{
PCR.assist_conf.assist_clk_en = enable;
}
FORCE_INLINE_ATTR void assist_debug_ll_reset_register(void)
{
PCR.assist_conf.assist_rst_en = true;
PCR.assist_conf.assist_rst_en = false;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,6 +17,7 @@
#include <stdint.h>
#include "esp_attr.h"
#include "hal/assert.h"
#include "soc/pcr_struct.h"
#ifdef __cplusplus
extern "C" {
@ -54,7 +55,7 @@ extern "C" {
* interrupt, instead of "ENA".
*/
/* These functions are optimazed and designed for internal usage.
/* These functions are optimized and designed for internal usage.
* So, the API may differ from general ll layer pattern */
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_enable(__attribute__((unused)) uint32_t core_id)
@ -112,6 +113,17 @@ FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
}
FORCE_INLINE_ATTR void assist_debug_ll_enable_bus_clock(bool enable)
{
PCR.assist_conf.assist_clk_en = enable;
}
FORCE_INLINE_ATTR void assist_debug_ll_reset_register(void)
{
PCR.assist_conf.assist_rst_en = true;
PCR.assist_conf.assist_rst_en = false;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,143 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for DEBUG_ASSIST peripheral
#pragma once
#include "soc/assist_debug_reg.h"
#define ASSIST_DEBUG_SP_SPILL_BITS (ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA | ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA)
#ifndef __ASSEMBLER__
#include <stdbool.h>
#include <stdint.h>
#include "esp_attr.h"
#include "hal/assert.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Most other peripherals have 4 interrupt-related registers: INT_ENA_REG, INT_CLR_REG, INT_RAW_REG, INT_ST_REG, the
* meaning of which is well-understood.
*
* Assist_debug peripheral uses a different structure of interrupt registers:
* INT_ENA_REG, INT_RLS_REG, INT_CLR_REG, INT_RAW_REG.
*
* Their behavior can be explained using the following (verilog-like) pseudo-code:
* reg sp_spill_max_st
* assign sp_spill_max = (sp > SP_MAX_REG)
* assign SP_SPILL_MAX_RAW = sp_spill_max & SPILL_MAX_ENA
* always (@posedge clk) begin
* if (reset) then sp_spill_max_st <= 0
* elif SP_SPILL_MAX_CLR then sp_spill_max_st <= 0
* else sp_spill_max_st <= SP_SPILL_MAX_RAW & SP_SPILL_MAX_RLS
* end
* // ...same for sp_spill_min and other things dsoc/hp_sys_clkrst_struct.hebug_assist can check.
*
* // this is the final interrupt line coming out of the peripheral:
* assign DEBUG_ASSIST_INT = sp_spill_max_st | sp_spill_min_st | ...
*
* Basically, there is no "ST" register showing the final (latched) interrupt state, and there is an additional
* "RLS" register which just like "ENA" can be used to mask the interrupt.
* Note that writing to CLR clears the (internal) latched interrupt state 'sp_spill_max_st',
* but doesn't affect the software-readable RAW register.
*
* In this code, we use "ENA" to enable monitoring of a particular condition, and "RLS" to enable the interrupt.
* This allows checking whether the condition (e.g. sp > SP_MAX) has occurred by reading the RAW register, without
* actually triggering the interrupt. Hence you will see the somewhat counter-intuitive use of "RLS" to enable the
* interrupt, instead of "ENA".
*/
/* These functions are optimized and designed for internal usage.
* So, the API may differ from general ll layer pattern */
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_enable(uint32_t core_id)
{
REG_SET_BIT(core_id ? ASSIST_DEBUG_CORE_1_INTR_ENA_REG : ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
}
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_disable(uint32_t core_id)
{
REG_CLR_BIT(core_id ? ASSIST_DEBUG_CORE_1_INTR_ENA_REG : ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
}
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_enable(uint32_t core_id)
{
REG_SET_BIT(core_id ? ASSIST_DEBUG_CORE_1_INTR_RLS_REG : ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
}
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_disable(uint32_t core_id)
{
REG_CLR_BIT(core_id ? ASSIST_DEBUG_CORE_1_INTR_RLS_REG : ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
}
FORCE_INLINE_ATTR bool assist_debug_ll_sp_spill_is_fired(uint32_t core_id)
{
return REG_READ(core_id ? ASSIST_DEBUG_CORE_1_INTR_RAW_REG : ASSIST_DEBUG_CORE_0_INTR_RAW_REG) & ASSIST_DEBUG_SP_SPILL_BITS;
}
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_clear(uint32_t core_id)
{
REG_WRITE(core_id ? ASSIST_DEBUG_CORE_1_INTR_CLR_REG : ASSIST_DEBUG_CORE_0_INTR_CLR_REG, ASSIST_DEBUG_SP_SPILL_BITS);
}
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_min(uint32_t core_id, uint32_t min)
{
REG_WRITE(core_id ? ASSIST_DEBUG_CORE_1_SP_MIN_REG : ASSIST_DEBUG_CORE_0_SP_MIN_REG, min);
}
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_min(uint32_t core_id)
{
return REG_READ(core_id ? ASSIST_DEBUG_CORE_1_SP_MIN_REG : ASSIST_DEBUG_CORE_0_SP_MIN_REG);
}
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_max(uint32_t core_id, uint32_t max)
{
REG_WRITE(core_id ? ASSIST_DEBUG_CORE_1_SP_MAX_REG : ASSIST_DEBUG_CORE_0_SP_MAX_REG, max);
}
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_max(uint32_t core_id)
{
return REG_READ(core_id ? ASSIST_DEBUG_CORE_1_SP_MAX_REG : ASSIST_DEBUG_CORE_0_SP_MAX_REG);
}
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(uint32_t core_id)
{
return REG_READ(core_id ? ASSIST_DEBUG_CORE_1_SP_PC_REG : ASSIST_DEBUG_CORE_0_SP_PC_REG);
}
FORCE_INLINE_ATTR void assist_debug_ll_enable_bus_clock(bool enable)
{
HP_SYS_CLKRST.soc_clk_ctrl0.reg_busmon_cpu_clk_en = enable;
}
#define assist_debug_ll_enable_bus_clock(...) \
(void)__DECLARE_RCC_ATOMIC_ENV; assist_debug_ll_enable_bus_clock(__VA_ARGS__)
FORCE_INLINE_ATTR void assist_debug_ll_reset_register(void)
{
/* esp32p4 has no assist_debug reset register: disable & clear interrupts manually. */
for (int i = 0; i < CONFIG_SOC_CPU_CORES_NUM; i++) {
assist_debug_ll_sp_spill_monitor_disable(i);
assist_debug_ll_sp_spill_interrupt_clear(i);
assist_debug_ll_sp_spill_set_min(i, 0);
assist_debug_ll_sp_spill_set_max(i, 0xffffffff);
/* Enable PC register storing when trigger stack monitor. */
REG_WRITE(i ? ASSIST_DEBUG_CORE_1_RCD_EN_REG : ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_1_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_1_RCD_RECORDEN);
}
}
#define assist_debug_ll_reset_register(...) \
(void)__DECLARE_RCC_ATOMIC_ENV; assist_debug_ll_reset_register(__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif // __ASSEMBLER__

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -14,6 +14,12 @@
#define MEMPROT_ISR _interrupt_handler
#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
#define ASTDBG_ISR _panic_handler
#else
#define ASTDBG_ISR _interrupt_handler
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
#if CONFIG_ESP_IPC_ISR_ENABLE
#define IPC_ISR_HANDLER esp_ipc_isr_handler
#else
@ -109,7 +115,7 @@ _mtvt_table:
.word _panic_handler /* 40: ETS_INT_WDT_INUM (+16) panic-interrupt (soc-level panic) */
.word _panic_handler /* 41: ETS_CACHEERR_INUM (+16) panic-interrupt (soc-level panic) */
.word MEMPROT_ISR /* 42: ETS_MEMPROT_ERR_INUM (+16) handler (soc-level panic) */
.word _interrupt_handler /* 43: Free interrupt number */
.word ASTDBG_ISR /* 43: ETS_ASSIST_DEBUG_INUM (+16) handler (soc-level panic) */
.word IPC_ISR_HANDLER /* 44: ETS_IPC_ISR_INUM (+16) handler*/
.word _interrupt_handler /* 45: Free interrupt number */
.word _interrupt_handler /* 46: Free interrupt number */

View File

@ -211,6 +211,10 @@ config SOC_CLK_TREE_SUPPORTED
bool
default y
config SOC_ASSIST_DEBUG_SUPPORTED
bool
default y
config SOC_WDT_SUPPORTED
bool
default y

View File

@ -5,7 +5,6 @@
*/
#pragma once
#include <stdint.h>
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {

View File

@ -68,6 +68,7 @@ typedef enum {
PERIPH_AXI_PDMA_MODULE,
PERIPH_UHCI_MODULE,
PERIPH_PCNT_MODULE,
PERIPH_ASSIST_DEBUG_MODULE,
/* LP peripherals */
PERIPH_LP_I2C0_MODULE,
PERIPH_LP_UART0_MODULE,

View File

@ -231,6 +231,7 @@
#define ETS_T1_WDT_INUM 24
#define ETS_CACHEERR_INUM 25
#define ETS_MEMPROT_ERR_INUM 26
#define ETS_ASSIST_DEBUG_INUM 27 // Note: this interrupt can be combined with others (e.g., CACHEERR), as we can identify its trigger is activated
#define ETS_IPC_ISR_INUM 28
//CPU0 Max valid interrupt number
#define ETS_MAX_INUM 31

View File

@ -80,7 +80,7 @@
// #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534
#define SOC_SDMMC_HOST_SUPPORTED 1
#define SOC_CLK_TREE_SUPPORTED 1
// #define SOC_ASSIST_DEBUG_SUPPORTED 1 //TODO: IDF-7565
#define SOC_ASSIST_DEBUG_SUPPORTED 1
#define SOC_WDT_SUPPORTED 1
#define SOC_SPI_FLASH_SUPPORTED 1
// #define SOC_TOUCH_SENSOR_SUPPORTED 1 //TODO: IDF-7477