mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(esp_system): implement hw stack guard for riscv chips
- add hardware stack guard based on assist-debug module - enable hardware stack guard by default - disable hardware stack guard for freertos ci.release test - refactor rtos_int_enter/rtos_int_exit to change SP register inside them - fix panic_reason.h header for RISC-V - update docs to include information about the new feature
This commit is contained in:
parent
bce88908c7
commit
4df3ff619e
@ -53,6 +53,10 @@ else()
|
||||
list(APPEND srcs "systick_etm.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_SYSTEM_HW_STACK_GUARD)
|
||||
list(APPEND srcs "hw_stack_guard.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_REQUIRES spi_flash esp_timer esp_mm
|
||||
|
@ -561,6 +561,14 @@ menu "ESP System Settings"
|
||||
(2). For special workflow, the chip needs do more things instead of restarting directly. This part
|
||||
needs to be done in callback function of interrupt.
|
||||
|
||||
config ESP_SYSTEM_HW_STACK_GUARD
|
||||
bool "Hardware stack guard"
|
||||
depends on SOC_ASSIST_DEBUG_SUPPORTED
|
||||
default y
|
||||
help
|
||||
This config allows to trigger a panic interrupt when Stack Pointer register goes out of allocated stack
|
||||
memory bounds.
|
||||
|
||||
endmenu # ESP System Settings
|
||||
|
||||
menu "IPC (Inter-Processor Call)"
|
||||
|
95
components/esp_system/hw_stack_guard.c
Normal file
95
components/esp_system/hw_stack_guard.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "hal/assist_debug_hal.h"
|
||||
#include "esp_private/hw_stack_guard.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_cpu.h"
|
||||
|
||||
ESP_SYSTEM_INIT_FN(esp_hw_stack_guard_init, ESP_SYSTEM_INIT_ALL_CORES, 101)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* enable interrupt
|
||||
* Note: to control hw_stack_guard use monitor enable/disable because in case:
|
||||
* - monitor == active
|
||||
* - interrupt != active
|
||||
* - trigger event happened
|
||||
* - you get an interrupt right after enabling interrupts
|
||||
* So, use monitor to disable hw_guard to avoid false-positives.
|
||||
* And keep interrupt always enabled for better performace (don't spend cpu time for enable/disable)
|
||||
*/
|
||||
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_intc_int_set_type(ETS_ASSIST_DEBUG_INUM, INTR_TYPE_LEVEL);
|
||||
esprv_intc_int_set_priority(ETS_ASSIST_DEBUG_INUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
||||
|
||||
ESP_INTR_ENABLE(ETS_ASSIST_DEBUG_INUM);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
uint32_t core_id = esp_cpu_get_core_id();
|
||||
|
||||
/* enable monitor. Interrupt is always enabled (see comment in esp_hw_stack_guard_init()) */
|
||||
assist_debug_hal_sp_mon_enable(core_id);
|
||||
}
|
||||
|
||||
void esp_hw_stack_guard_monitor_stop(void)
|
||||
{
|
||||
uint32_t core_id = esp_cpu_get_core_id();
|
||||
/* disable monitor. Interrupt is always enabled (see comment in esp_hw_stack_guard_init()) */
|
||||
assist_debug_hal_sp_mon_disable(core_id);
|
||||
}
|
||||
|
||||
void esp_hw_stack_guard_set_bounds(uint32_t sp_min, uint32_t sp_max)
|
||||
{
|
||||
uint32_t core_id = esp_cpu_get_core_id();
|
||||
|
||||
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)
|
||||
{
|
||||
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 core_id = esp_cpu_get_core_id();
|
||||
|
||||
return assist_debug_hal_is_sp_ovf_fired(core_id);
|
||||
}
|
||||
|
||||
uint32_t esp_hw_stack_guard_get_pc(void)
|
||||
{
|
||||
uint32_t core_id = esp_cpu_get_core_id();
|
||||
|
||||
return assist_debug_hal_get_sp_ovf_pc(core_id);
|
||||
}
|
@ -7,6 +7,10 @@ entries:
|
||||
panic_arch (noflash)
|
||||
cache_err_int:esp_cache_err_get_cpuid (noflash)
|
||||
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_pc (noflash)
|
||||
|
||||
esp_err (noflash)
|
||||
esp_system_chip:esp_system_abort (noflash)
|
||||
|
@ -9,35 +9,50 @@
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
#include "esp_private/hw_stack_guard.h"
|
||||
#endif
|
||||
|
||||
static portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static void *current_task_stack = NULL;
|
||||
|
||||
extern void esp_shared_stack_invoke_function(shared_stack_function function, void *stack);
|
||||
|
||||
static StackType_t *esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
|
||||
static StackType_t *esp_shared_stack_setup_context(StaticTask_t *tcb, void **sp_min, void **sp_max, StackType_t *stack, size_t stack_size)
|
||||
{
|
||||
//We need also to tweak current task stackpointer to avoid erroneous
|
||||
//stack overflow indication, so fills the stack with freertos known pattern:
|
||||
memset(stack, 0xa5U, stack_size * sizeof(StackType_t));
|
||||
|
||||
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||
//Then put the fake stack inside of TCB:
|
||||
current_task_stack = current->pxDummy6;
|
||||
current->pxDummy6 = (void *)stack;
|
||||
|
||||
StackType_t *top_of_stack = stack + stack_size;
|
||||
|
||||
//Align stack to a 16byte boundary, as required by CPU specific:
|
||||
top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
|
||||
//Align stack to a 16-byte boundary, as required by CPU specific:
|
||||
StackType_t *top_of_stack = (StackType_t *) ALIGNUP(0x10, (uint32_t) (stack + stack_size));
|
||||
StackType_t *adjusted_top_of_stack = top_of_stack - RV_STK_FRMSZ;
|
||||
|
||||
//Then put the fake stack inside of TCB:
|
||||
*sp_min = tcb->pxDummy6;
|
||||
tcb->pxDummy6 = (void *)stack;
|
||||
|
||||
*sp_max = tcb->pxDummy8;
|
||||
tcb->pxDummy8 = adjusted_top_of_stack;
|
||||
|
||||
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||
vPortSetStackWatchpoint(stack);
|
||||
#endif
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
esp_hw_stack_guard_monitor_stop();
|
||||
esp_hw_stack_guard_set_bounds((uint32_t) tcb->pxDummy6, (uint32_t) tcb->pxDummy8);
|
||||
#endif
|
||||
return ((StackType_t *)adjusted_top_of_stack);
|
||||
}
|
||||
|
||||
static void esp_shared_stack_restore_context(StaticTask_t *tcb, void *sp_min, void *sp_max) {
|
||||
tcb->pxDummy6 = sp_min;
|
||||
tcb->pxDummy8 = sp_max;
|
||||
|
||||
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||
vPortSetStackWatchpoint(sp_min);
|
||||
#endif
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
esp_hw_stack_guard_set_bounds((uint32_t) sp_min, (uint32_t) sp_max);
|
||||
esp_hw_stack_guard_monitor_start();
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
|
||||
{
|
||||
@ -46,21 +61,33 @@ void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size
|
||||
assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
|
||||
assert(function);
|
||||
|
||||
static portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
StaticTask_t *tcb = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||
void *sp_min = NULL;
|
||||
void *sp_max = (void *) UINTPTR_MAX;
|
||||
|
||||
xSemaphoreTake(lock, portMAX_DELAY);
|
||||
|
||||
portENTER_CRITICAL(&shared_stack_spinlock);
|
||||
stack = esp_switch_stack_setup(stack, stack_size);
|
||||
stack = esp_shared_stack_setup_context(tcb, &sp_min, &sp_max, stack, stack_size);
|
||||
__asm__ volatile ("mv t0, sp \n" /* save current SP */
|
||||
"mv sp, %0 \n" /* set shared stack as new SP */
|
||||
"addi sp, sp, -16 \n" /* allocate memory for previous SP */
|
||||
"sw t0, 0(sp) \n" /* store previous SP in a safe place */
|
||||
:: "r"(stack));
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
esp_hw_stack_guard_monitor_start();
|
||||
#endif
|
||||
portEXIT_CRITICAL(&shared_stack_spinlock);
|
||||
|
||||
esp_shared_stack_invoke_function(function, stack);
|
||||
function();
|
||||
|
||||
portENTER_CRITICAL(&shared_stack_spinlock);
|
||||
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||
|
||||
//Restore current task stack:
|
||||
current->pxDummy6 = (StackType_t *)current_task_stack;
|
||||
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||
vPortSetStackWatchpoint(current->pxDummy6);
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
esp_hw_stack_guard_monitor_stop();
|
||||
#endif
|
||||
__asm__ volatile ("lw sp, 0(sp)"); /* restore real SP of current task */
|
||||
esp_shared_stack_restore_context(tcb, sp_min, sp_max);
|
||||
portEXIT_CRITICAL(&shared_stack_spinlock);
|
||||
|
||||
xSemaphoreGive(lock);
|
||||
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
.section .text
|
||||
|
||||
.global esp_shared_stack_invoke_function
|
||||
.type esp_shared_stack_invoke_function, @function
|
||||
esp_shared_stack_invoke_function:
|
||||
/* save current stack and return address */
|
||||
mv t0, sp
|
||||
mv t1, ra
|
||||
|
||||
/* Set shared stack as new stack pointer */
|
||||
mv sp, a1
|
||||
|
||||
/* store the ra and previous stack pointer in a safe place
|
||||
stack pointer for riscv should always be 16 byte aligned */
|
||||
addi sp,sp,-16
|
||||
sw t0, 0(sp)
|
||||
sw t1, 4(sp)
|
||||
|
||||
/* call the subroutine */
|
||||
jalr a0, 0
|
||||
|
||||
/* gets the ra and stack pointer saved previously */
|
||||
lw t0, 0(sp)
|
||||
lw t1, 4(sp)
|
||||
addi sp, sp, 16
|
||||
|
||||
/* restore both ra and real stack pointer of current task */
|
||||
mv ra, t1
|
||||
mv sp, t0
|
||||
ret
|
@ -25,6 +25,13 @@
|
||||
#include "esp_private/cache_utils.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/hw_stack_guard.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define DIM(array) (sizeof(array)/sizeof(*array))
|
||||
|
||||
@ -149,6 +156,34 @@ static inline void print_cache_err_details(const void *frame)
|
||||
#endif
|
||||
}
|
||||
|
||||
#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 sp_min, sp_max;
|
||||
const char *task_name = pcTaskGetName(xTaskGetCurrentTaskHandleForCPU(core_id));
|
||||
esp_hw_stack_guard_get_bounds(&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_str("\r\n");
|
||||
panic_print_str("Stack pointer: 0x");
|
||||
panic_print_hex((int) ((RvExcFrame *)frame)->sp);
|
||||
panic_print_str("\r\n");
|
||||
panic_print_str("Stack bounds: 0x");
|
||||
panic_print_hex((int) sp_min);
|
||||
panic_print_str(" - 0x");
|
||||
panic_print_hex((int) sp_max);
|
||||
panic_print_str("\r\n\r\n");
|
||||
}
|
||||
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
|
||||
/**
|
||||
* Function called when a memory protection error occurs (PMS). It prints details such as the
|
||||
@ -257,20 +292,7 @@ void panic_soc_fill_info(void *f, panic_info_t *info)
|
||||
{
|
||||
RvExcFrame *frame = (RvExcFrame *) f;
|
||||
|
||||
/* Please keep in sync with PANIC_RSN_* defines */
|
||||
static const char *pseudo_reason[PANIC_RSN_COUNT] = {
|
||||
"Unknown reason",
|
||||
"Interrupt wdt timeout on CPU0",
|
||||
#if SOC_CPU_NUM > 1
|
||||
"Interrupt wdt timeout on CPU1",
|
||||
#endif
|
||||
"Cache error",
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
"Memory protection fault",
|
||||
#endif
|
||||
};
|
||||
|
||||
info->reason = pseudo_reason[0];
|
||||
info->reason = "Unknown reason";
|
||||
info->addr = (void *) frame->mepc;
|
||||
|
||||
/* The mcause has been set by the CPU when the panic occured.
|
||||
@ -283,7 +305,7 @@ void panic_soc_fill_info(void *f, panic_info_t *info)
|
||||
* about why the error happened. */
|
||||
|
||||
info->core = esp_cache_err_get_cpuid();
|
||||
info->reason = pseudo_reason[PANIC_RSN_CACHEERR];
|
||||
info->reason = "Cache error";
|
||||
info->details = print_cache_err_details;
|
||||
|
||||
} else if (frame->mcause == ETS_INT_WDT_INUM) {
|
||||
@ -295,14 +317,24 @@ void panic_soc_fill_info(void *f, panic_info_t *info)
|
||||
info->exception = PANIC_EXCEPTION_IWDT;
|
||||
|
||||
#if SOC_CPU_NUM > 1
|
||||
#error "TODO: define PANIC_RSN_INTWDT_CPU1 in panic_reason.h"
|
||||
_Static_assert(PANIC_RSN_INTWDT_CPU0 + 1 == PANIC_RSN_INTWDT_CPU1,
|
||||
"PANIC_RSN_INTWDT_CPU1 must be equal to PANIC_RSN_INTWDT_CPU0 + 1");
|
||||
info->reason = core == 0 ? "Interrupt wdt timeout on CPU0" : "Interrupt wdt timeout on CPU1";
|
||||
#else
|
||||
info->reason = "Interrupt wdt timeout on CPU0";
|
||||
#endif
|
||||
info->reason = pseudo_reason[PANIC_RSN_INTWDT_CPU0 + core];
|
||||
}
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
else if (frame->mcause == ETS_ASSIST_DEBUG_INUM) {
|
||||
info->core = esp_cache_err_get_cpuid();
|
||||
info->reason = "Stack protection fault";
|
||||
info->details = print_assist_debug_details;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
else if (frame->mcause == ETS_MEMPROT_ERR_INUM) {
|
||||
info->reason = pseudo_reason[PANIC_RSN_MEMPROT];
|
||||
info->reason = "Memory protection fault";
|
||||
info->details = print_memprot_err_details;
|
||||
info->core = esp_mprot_get_active_intr(&s_memp_intr) == ESP_OK ? s_memp_intr.core : -1;
|
||||
}
|
||||
@ -315,7 +347,6 @@ void panic_arch_fill_info(void *frame, panic_info_t *info)
|
||||
info->core = 0;
|
||||
info->exception = PANIC_EXCEPTION_FAULT;
|
||||
|
||||
//Please keep in sync with PANIC_RSN_* defines
|
||||
static const char *reason[] = {
|
||||
"Instruction address misaligned",
|
||||
"Instruction access fault",
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#else // __ASSEMBLER__
|
||||
|
||||
#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)
|
||||
|
||||
.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
|
||||
lui t0, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
|
||||
sw a0, ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET(t0)
|
||||
sw a1, ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET(t0)
|
||||
.endm
|
||||
|
||||
.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
|
||||
lui t0, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
|
||||
lw t1, 0(t0)
|
||||
andi t1, t1, ~ASSIST_DEBUG_SP_SPILL_BITS
|
||||
sw t1, 0(t0)
|
||||
.endm
|
||||
|
||||
.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU0
|
||||
lui t0, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
|
||||
lw t1, 0(t0)
|
||||
ori t1, t1, ASSIST_DEBUG_SP_SPILL_BITS
|
||||
sw t1, 0(t0)
|
||||
.endm
|
||||
|
||||
#endif // __ASSEMBLER__
|
@ -3,7 +3,6 @@ set(srcs "clk.c"
|
||||
"system_internal.c"
|
||||
"cache_err_int.c"
|
||||
"../../arch/riscv/expression_with_stack.c"
|
||||
"../../arch/riscv/expression_with_stack_asm.S"
|
||||
"../../arch/riscv/panic_arch.c"
|
||||
"../../arch/riscv/debug_stubs.c")
|
||||
|
||||
|
@ -4,7 +4,6 @@ set(srcs "clk.c"
|
||||
"cache_err_int.c"
|
||||
"apb_backup_dma.c"
|
||||
"../../arch/riscv/expression_with_stack.c"
|
||||
"../../arch/riscv/expression_with_stack_asm.S"
|
||||
"../../arch/riscv/panic_arch.c"
|
||||
"../../arch/riscv/debug_stubs.c")
|
||||
|
||||
|
@ -3,7 +3,6 @@ set(srcs "clk.c"
|
||||
"system_internal.c"
|
||||
"cache_err_int.c"
|
||||
"../../arch/riscv/expression_with_stack.c"
|
||||
"../../arch/riscv/expression_with_stack_asm.S"
|
||||
"../../arch/riscv/panic_arch.c"
|
||||
"../../arch/riscv/debug_stubs.c")
|
||||
|
||||
|
@ -4,7 +4,6 @@ set(srcs
|
||||
"system_internal.c"
|
||||
"cache_err_int.c"
|
||||
"../../arch/riscv/expression_with_stack.c"
|
||||
"../../arch/riscv/expression_with_stack_asm.S"
|
||||
"../../arch/riscv/panic_arch.c"
|
||||
"../../arch/riscv/debug_stubs.c")
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
# esp_timer has to be initialized early, since it is used by several other components
|
||||
100: esp_timer_startup_init in components/esp_timer/src/esp_timer.c on CONFIG_ESP_TIMER_ISR_AFFINITY
|
||||
|
||||
# HW stack guard via assist-debug module.
|
||||
101: esp_hw_stack_guard_init in components/esp_system/hw_stack_guard.c on ESP_SYSTEM_INIT_ALL_CORES
|
||||
|
||||
# esp_sleep doesn't have init dependencies
|
||||
105: esp_sleep_startup_init in components/esp_hw_support/sleep_gpio.c on BIT(0)
|
||||
106: sleep_clock_startup_init in components/esp_hw_support/sleep_clock.c on BIT(0)
|
||||
|
@ -7,6 +7,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* Macros used instead ofsetoff() for better performance of interrupt handler */
|
||||
#define PORT_OFFSET_PX_STACK 0x30
|
||||
#define PORT_OFFSET_PX_END_OF_STACK (PORT_OFFSET_PX_STACK + \
|
||||
/* void * pxDummy6 */ 4 + \
|
||||
/* BaseType_t xDummy23[ 2 ] */ 8 + \
|
||||
/* uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ] */ CONFIG_FREERTOS_MAX_TASK_NAME_LEN + \
|
||||
/* BaseType_t xDummy24 */ 4)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "spinlock.h"
|
||||
#include "soc/interrupt_reg.h"
|
||||
@ -355,3 +366,5 @@ portmacro.h. Therefore, we need to keep these headers around for now to allow th
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ASSEMBLER__
|
||||
|
@ -41,6 +41,17 @@
|
||||
#endif //CONFIG_PM_TRACE
|
||||
|
||||
_Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16");
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/**
|
||||
* offsetof() can not be used in asm code. Then we need make sure that
|
||||
* PORT_OFFSET_PX_STACK and PORT_OFFSET_PX_END_OF_STACK have expected values.
|
||||
* Macro used in the portasm.S instead of variables to save at least 4 instruction calls
|
||||
* which accessing DRAM memory. This optimization saves CPU time in the interrupt handling.
|
||||
*/
|
||||
|
||||
_Static_assert(offsetof( StaticTask_t, pxDummy6 ) == PORT_OFFSET_PX_STACK);
|
||||
_Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK);
|
||||
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
|
||||
/* ---------------------------------------------------- Variables ------------------------------------------------------
|
||||
*
|
||||
@ -51,7 +62,7 @@ volatile UBaseType_t uxInterruptNesting = 0;
|
||||
portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
|
||||
portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
|
||||
volatile BaseType_t xPortSwitchFlag = 0;
|
||||
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||
__attribute__((aligned(16))) StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
||||
|
||||
// Variables used for IDF style critical sections. These are orthogonal to FreeRTOS critical sections
|
||||
|
@ -1,8 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "portmacro.h"
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
#include "esp_private/hw_stack_guard.h"
|
||||
#endif
|
||||
|
||||
.global uxInterruptNesting
|
||||
.global uxSchedulerRunning
|
||||
@ -10,23 +15,26 @@
|
||||
.global pxCurrentTCBs
|
||||
.global vTaskSwitchContext
|
||||
.global xPortSwitchFlag
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
.global xIsrStack
|
||||
.global port_offset_pxStack
|
||||
.global port_offset_pxEndOfStack
|
||||
.global esp_hw_stack_guard_monitor_stop
|
||||
.global esp_hw_stack_guard_monitor_start
|
||||
.global esp_hw_stack_guard_set_bounds
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
.section .text
|
||||
|
||||
/**
|
||||
* This function makes the RTOS aware about a ISR entering, it takes the
|
||||
* current task stack saved, places into the TCB, loads the ISR stack
|
||||
* the interrupted stack must be passed in a0. It needs to receive the
|
||||
* ISR nesting code improvements
|
||||
* current task stack saved, places into the TCB, loads the ISR stack.
|
||||
* TODO: ISR nesting code improvements ?
|
||||
*/
|
||||
|
||||
.global rtos_int_enter
|
||||
.type rtos_int_enter, @function
|
||||
rtos_int_enter:
|
||||
/* preserve the return address */
|
||||
mv t1, ra
|
||||
mv t2, a0
|
||||
|
||||
/* scheduler not enabled, jump directly to ISR handler */
|
||||
lw t0, uxSchedulerRunning
|
||||
beq t0,zero, rtos_enter_end
|
||||
@ -40,19 +48,30 @@ rtos_int_enter:
|
||||
/* If reached here from another low-prio ISR, skip stack pushing to TCB */
|
||||
bne t4,zero, rtos_enter_end
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_monitor_stop(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
/* Save current TCB and load the ISR stack */
|
||||
lw t0, pxCurrentTCBs
|
||||
sw t2, 0x0(t0)
|
||||
sw sp, 0x0(t0)
|
||||
lw sp, xIsrStackTop
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_set_bounds(xIsrStack, xIsrStackTop); */
|
||||
la a0, xIsrStack
|
||||
mv a1, sp
|
||||
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
|
||||
/* esp_hw_stack_guard_monitor_start(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_START_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
rtos_enter_end:
|
||||
mv ra, t1
|
||||
ret
|
||||
|
||||
/**
|
||||
* Recovers the next task to run stack pointer and place it into
|
||||
* a0, then the interrupt handler can restore the context of
|
||||
* the next task
|
||||
* Restores the context of the next task.
|
||||
*/
|
||||
.global rtos_int_exit
|
||||
.type rtos_int_exit, @function
|
||||
@ -96,9 +115,26 @@ isr_skip_decrement:
|
||||
sw t2, 0x0(t0)
|
||||
|
||||
no_switch:
|
||||
/* Recover the stack of next task and prepare to exit : */
|
||||
lw a0, pxCurrentTCBs
|
||||
lw a0, 0x0(a0)
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_monitor_stop(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
/* Recover the stack of next task */
|
||||
lw t0, pxCurrentTCBs
|
||||
lw sp, 0x0(t0)
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_set_bounds(pxCurrentTCBs[0]->pxStack,
|
||||
* pxCurrentTCBs[0]->pxEndOfStack);
|
||||
*/
|
||||
lw a0, PORT_OFFSET_PX_STACK(t0)
|
||||
lw a1, PORT_OFFSET_PX_END_OF_STACK(t0)
|
||||
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
|
||||
/* esp_hw_stack_guard_monitor_start(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_START_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
rtos_exit_end:
|
||||
ret
|
||||
|
@ -35,9 +35,17 @@
|
||||
#ifndef PORTMACRO_H
|
||||
#define PORTMACRO_H
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* Macros used instead ofsetoff() for better performance of interrupt handler */
|
||||
#define PORT_OFFSET_PX_STACK 0x30
|
||||
#define PORT_OFFSET_PX_END_OF_STACK (PORT_OFFSET_PX_STACK + \
|
||||
/* void * pxDummy6 */ 4 + \
|
||||
/* uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ] */ CONFIG_FREERTOS_MAX_TASK_NAME_LEN + \
|
||||
/* BaseType_t xDummyCoreID */ 4)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -58,6 +58,17 @@
|
||||
#include "esp_memory_utils.h"
|
||||
|
||||
_Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16");
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/**
|
||||
* offsetof() can not be used in asm code. Then we need make sure that
|
||||
* PORT_OFFSET_PX_STACK and PORT_OFFSET_PX_END_OF_STACK have expected values.
|
||||
* Macro used in the portasm.S instead of variables to save at least 4 instruction calls
|
||||
* which accessing DRAM memory. This optimization saves CPU time in the interrupt handling.
|
||||
*/
|
||||
|
||||
_Static_assert(offsetof( StaticTask_t, pxDummy6 ) == PORT_OFFSET_PX_STACK);
|
||||
_Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK);
|
||||
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
|
||||
/* ---------------------------------------------------- Variables ------------------------------------------------------
|
||||
*
|
||||
@ -74,7 +85,7 @@ static UBaseType_t uxSavedInterruptState = 0;
|
||||
BaseType_t uxSchedulerRunning = 0; // Duplicate of xSchedulerRunning, accessible to port files
|
||||
UBaseType_t uxInterruptNesting = 0;
|
||||
BaseType_t xPortSwitchFlag = 0;
|
||||
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||
__attribute__((aligned(16))) StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
||||
|
||||
|
||||
|
@ -3,6 +3,11 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "portmacro.h"
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
#include "esp_private/hw_stack_guard.h"
|
||||
#endif
|
||||
|
||||
.global uxInterruptNesting
|
||||
.global uxSchedulerRunning
|
||||
@ -10,23 +15,26 @@
|
||||
.global pxCurrentTCB
|
||||
.global vTaskSwitchContext
|
||||
.global xPortSwitchFlag
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
.global xIsrStack
|
||||
.global port_offset_pxStack
|
||||
.global port_offset_pxEndOfStack
|
||||
.global esp_hw_stack_guard_monitor_stop
|
||||
.global esp_hw_stack_guard_monitor_start
|
||||
.global esp_hw_stack_guard_set_bounds
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
.section .text
|
||||
|
||||
/**
|
||||
* This function makes the RTOS aware about a ISR entering, it takes the
|
||||
* current task stack saved, places into the TCB, loads the ISR stack
|
||||
* the interrupted stack must be passed in a0. It needs to receive the
|
||||
* ISR nesting code improvements
|
||||
* current task stack saved, places into the TCB, loads the ISR stack.
|
||||
* TODO: ISR nesting code improvements ?
|
||||
*/
|
||||
|
||||
.global rtos_int_enter
|
||||
.type rtos_int_enter, @function
|
||||
rtos_int_enter:
|
||||
/* preserve the return address */
|
||||
mv t1, ra
|
||||
mv t2, a0
|
||||
|
||||
/* scheduler not enabled, jump directly to ISR handler */
|
||||
lw t0, uxSchedulerRunning
|
||||
beq t0,zero, rtos_enter_end
|
||||
@ -40,19 +48,29 @@ rtos_int_enter:
|
||||
/* If reached here from another low-prio ISR, skip stack pushing to TCB */
|
||||
bne t4,zero, rtos_enter_end
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_monitor_stop(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
/* Save current TCB and load the ISR stack */
|
||||
lw t0, pxCurrentTCB
|
||||
sw t2, 0x0(t0)
|
||||
sw sp, 0x0(t0)
|
||||
lw sp, xIsrStackTop
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_set_bounds(xIsrStack, xIsrStackTop); */
|
||||
la a0, xIsrStack
|
||||
mv a1, sp
|
||||
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
|
||||
ESP_HW_STACK_GUARD_MONITOR_START_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
rtos_enter_end:
|
||||
mv ra, t1
|
||||
ret
|
||||
|
||||
/**
|
||||
* Recovers the next task to run stack pointer and place it into
|
||||
* a0, then the interrupt handler can restore the context of
|
||||
* the next task
|
||||
* Recovers the next task to run stack pointer.
|
||||
*/
|
||||
.global rtos_int_exit
|
||||
.type rtos_int_exit, @function
|
||||
@ -94,9 +112,26 @@ isr_skip_decrement:
|
||||
sw t2, 0x0(t0)
|
||||
|
||||
no_switch:
|
||||
/* Recover the stack of next task and prepare to exit : */
|
||||
lw a0, pxCurrentTCB
|
||||
lw a0, 0x0(a0)
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_monitor_stop(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
/* Recover the stack of next task */
|
||||
lw t0, pxCurrentTCB
|
||||
lw sp, 0x0(t0)
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
/* esp_hw_stack_guard_set_bounds(pxCurrentTCB[0]->pxStack,
|
||||
* pxCurrentTCB[0]->pxEndOfStack);
|
||||
*/
|
||||
lw a0, PORT_OFFSET_PX_STACK(t0)
|
||||
lw a1, PORT_OFFSET_PX_END_OF_STACK(t0)
|
||||
ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
|
||||
/* esp_hw_stack_guard_monitor_start(); */
|
||||
ESP_HW_STACK_GUARD_MONITOR_START_CPU0
|
||||
#endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
|
||||
|
||||
rtos_exit_end:
|
||||
ret
|
||||
|
@ -18,6 +18,18 @@
|
||||
* additional API.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------- Static asserts ----------------------------------------------------
|
||||
*
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Both StaticTask_t and TCB_t structures are provided by FreeRTOS sources.
|
||||
* This is just an additional check of the consistency of these structures.
|
||||
*/
|
||||
|
||||
_Static_assert(offsetof( StaticTask_t, pxDummy6 ) == offsetof( TCB_t, pxStack ));
|
||||
_Static_assert(offsetof( StaticTask_t, pxDummy8 ) == offsetof( TCB_t, pxEndOfStack ));
|
||||
|
||||
/* ----------------------------------------------------- Newlib --------------------------------------------------------
|
||||
*
|
||||
* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
@ -3,3 +3,6 @@
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
|
||||
# Test if disabled hardware stack guard works as expected (enabled by default)
|
||||
CONFIG_ESP_SYSTEM_HW_STACK_GUARD=n
|
||||
|
119
components/hal/esp32c2/include/hal/assist_debug_ll.h
Normal file
119
components/hal/esp32c2/include/hal/assist_debug_ll.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 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"
|
||||
|
||||
#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 debug_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 optimazed 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)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_enable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool assist_debug_ll_sp_spill_is_fired(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_INTR_RAW_REG) & ASSIST_DEBUG_SP_SPILL_BITS;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_clear(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_INTR_CLR_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_min(__attribute__((unused)) uint32_t core_id, uint32_t min)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MIN_REG, min);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_min(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MIN_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_max(__attribute__((unused)) uint32_t core_id, uint32_t max)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MAX_REG, max);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_max(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MAX_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ASSEMBLER__
|
@ -59,6 +59,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
return SYSTEM_BT_LC_EN;
|
||||
case PERIPH_TEMPSENSOR_MODULE:
|
||||
return SYSTEM_TSENS_CLK_EN;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_CLK_EN_ASSIST_DEBUG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -106,6 +108,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
||||
}
|
||||
case PERIPH_MODEM_RPA_MODULE:
|
||||
return BLE_RPA_REST_BIT;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_RST_EN_ASSIST_DEBUG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -127,6 +131,10 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
|
||||
case PERIPH_ECC_MODULE:
|
||||
case PERIPH_TEMPSENSOR_MODULE:
|
||||
return SYSTEM_PERIP_CLK_EN1_REG;
|
||||
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_CPU_PERI_CLK_EN_REG;
|
||||
|
||||
default:
|
||||
return SYSTEM_PERIP_CLK_EN0_REG;
|
||||
}
|
||||
@ -149,6 +157,10 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
||||
case PERIPH_ECC_MODULE:
|
||||
case PERIPH_TEMPSENSOR_MODULE:
|
||||
return SYSTEM_PERIP_RST_EN1_REG;
|
||||
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_CPU_PERI_RST_EN_REG;
|
||||
|
||||
default:
|
||||
return SYSTEM_PERIP_RST_EN0_REG;
|
||||
}
|
||||
|
119
components/hal/esp32c3/include/hal/assist_debug_ll.h
Normal file
119
components/hal/esp32c3/include/hal/assist_debug_ll.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 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"
|
||||
|
||||
#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 debug_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 optimazed 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)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_enable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool assist_debug_ll_sp_spill_is_fired(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_INTR_RAW_REG) & ASSIST_DEBUG_SP_SPILL_BITS;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_clear(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_INTR_CLR_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_min(__attribute__((unused)) uint32_t core_id, uint32_t min)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MIN_REG, min);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_min(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MIN_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_max(__attribute__((unused)) uint32_t core_id, uint32_t max)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MAX_REG, max);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_max(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MAX_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ASSEMBLER__
|
@ -75,6 +75,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
return SYSTEM_BT_LC_EN;
|
||||
case PERIPH_TEMPSENSOR_MODULE:
|
||||
return SYSTEM_TSENS_CLK_EN;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_CLK_EN_ASSIST_DEBUG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -150,6 +152,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
||||
}
|
||||
case PERIPH_DS_MODULE:
|
||||
return SYSTEM_CRYPTO_DS_RST;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_RST_EN_ASSIST_DEBUG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -174,6 +178,10 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
|
||||
case PERIPH_GDMA_MODULE:
|
||||
case PERIPH_TEMPSENSOR_MODULE:
|
||||
return SYSTEM_PERIP_CLK_EN1_REG;
|
||||
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_CPU_PERI_CLK_EN_REG;
|
||||
|
||||
default:
|
||||
return SYSTEM_PERIP_CLK_EN0_REG;
|
||||
}
|
||||
@ -198,6 +206,10 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
||||
case PERIPH_GDMA_MODULE:
|
||||
case PERIPH_TEMPSENSOR_MODULE:
|
||||
return SYSTEM_PERIP_RST_EN1_REG;
|
||||
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return SYSTEM_CPU_PERI_RST_EN_REG;
|
||||
|
||||
default:
|
||||
return SYSTEM_PERIP_RST_EN0_REG;
|
||||
}
|
||||
|
119
components/hal/esp32c6/include/hal/assist_debug_ll.h
Normal file
119
components/hal/esp32c6/include/hal/assist_debug_ll.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 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"
|
||||
|
||||
#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 debug_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 optimazed 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)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_enable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool assist_debug_ll_sp_spill_is_fired(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_INTR_RAW_REG) & ASSIST_DEBUG_SP_SPILL_BITS;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_clear(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_INTR_CLR_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_min(__attribute__((unused)) uint32_t core_id, uint32_t min)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MIN_REG, min);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_min(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MIN_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_max(__attribute__((unused)) uint32_t core_id, uint32_t max)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MAX_REG, max);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_max(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MAX_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ASSEMBLER__
|
@ -78,6 +78,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
return PCR_SDIO_SLAVE_CLK_EN;
|
||||
case PERIPH_REGDMA_MODULE:
|
||||
return PCR_REGDMA_CLK_EN;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_CLK_EN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -159,6 +161,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
||||
return PCR_SDIO_SLAVE_RST_EN;
|
||||
case PERIPH_REGDMA_MODULE:
|
||||
return PCR_REGDMA_RST_EN;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_RST_EN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -225,6 +229,8 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
|
||||
return PCR_SDIO_SLAVE_CONF_REG;
|
||||
case PERIPH_REGDMA_MODULE:
|
||||
return PCR_REGDMA_CONF_REG;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_CONF_REG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -291,6 +297,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
||||
return PCR_SDIO_SLAVE_CONF_REG;
|
||||
case PERIPH_REGDMA_MODULE:
|
||||
return PCR_REGDMA_CONF_REG;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_CONF_REG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
119
components/hal/esp32h2/include/hal/assist_debug_ll.h
Normal file
119
components/hal/esp32h2/include/hal/assist_debug_ll.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 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"
|
||||
|
||||
#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 debug_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 optimazed 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)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_monitor_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_ENA_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_enable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_SET_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_disable(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_CLR_BIT(ASSIST_DEBUG_CORE_0_INTR_RLS_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool assist_debug_ll_sp_spill_is_fired(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_INTR_RAW_REG) & ASSIST_DEBUG_SP_SPILL_BITS;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_interrupt_clear(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_INTR_CLR_REG, ASSIST_DEBUG_SP_SPILL_BITS);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_min(__attribute__((unused)) uint32_t core_id, uint32_t min)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MIN_REG, min);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_min(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MIN_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_ll_sp_spill_set_max(__attribute__((unused)) uint32_t core_id, uint32_t max)
|
||||
{
|
||||
REG_WRITE(ASSIST_DEBUG_CORE_0_SP_MAX_REG, max);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_max(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_MAX_REG);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_ll_sp_spill_get_pc(__attribute__((unused)) uint32_t core_id)
|
||||
{
|
||||
return REG_READ(ASSIST_DEBUG_CORE_0_SP_PC_REG);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __ASSEMBLER__
|
@ -89,6 +89,8 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
// return PCR_BT_BASEBAND_EN;
|
||||
// case PERIPH_BT_LC_MODULE:
|
||||
// return PCR_BT_LC_EN;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_CLK_EN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -189,6 +191,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
||||
// return PCR_BT_BASEBAND_EN;
|
||||
// case PERIPH_BT_LC_MODULE:
|
||||
// return PCR_BT_LC_EN;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_RST_EN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -263,6 +267,8 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
|
||||
return PCR_TSENS_CLK_CONF_REG;
|
||||
case PERIPH_REGDMA_MODULE:
|
||||
return PCR_REGDMA_CONF_REG;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_CONF_REG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -330,6 +336,8 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
||||
return PCR_TSENS_CLK_CONF_REG;
|
||||
case PERIPH_REGDMA_MODULE:
|
||||
return PCR_REGDMA_CONF_REG;
|
||||
case PERIPH_ASSIST_DEBUG_MODULE:
|
||||
return PCR_ASSIST_CONF_REG;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
70
components/hal/include/hal/assist_debug_hal.h
Normal file
70
components/hal/include/hal/assist_debug_hal.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_attr.h"
|
||||
#include "hal/assist_debug_ll.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_sp_int_enable(uint32_t core_id)
|
||||
{
|
||||
assist_debug_ll_sp_spill_interrupt_enable(core_id);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_sp_int_disable(uint32_t core_id)
|
||||
{
|
||||
assist_debug_ll_sp_spill_interrupt_disable(core_id);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_sp_int_clear(uint32_t core_id)
|
||||
{
|
||||
assist_debug_ll_sp_spill_interrupt_clear(core_id);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_sp_mon_enable(uint32_t core_id)
|
||||
{
|
||||
assist_debug_ll_sp_spill_monitor_enable(core_id);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_sp_mon_disable(uint32_t core_id)
|
||||
{
|
||||
assist_debug_ll_sp_spill_monitor_disable(core_id);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_hal_get_sp_ovf_pc(uint32_t core_id)
|
||||
{
|
||||
return assist_debug_ll_sp_spill_get_pc(core_id);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_get_sp_bounds(uint32_t core_id, uint32_t *sp_min, uint32_t *sp_max)
|
||||
{
|
||||
if (sp_min) {
|
||||
*sp_min = assist_debug_ll_sp_spill_get_min(core_id);
|
||||
}
|
||||
if (sp_max) {
|
||||
*sp_max = assist_debug_ll_sp_spill_get_max(core_id);
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void assist_debug_hal_set_sp_bounds(uint32_t core_id, uint32_t sp_min, uint32_t sp_max)
|
||||
{
|
||||
assist_debug_ll_sp_spill_set_min(core_id, sp_min);
|
||||
assist_debug_ll_sp_spill_set_max(core_id, sp_max);
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR uint32_t assist_debug_hal_is_sp_ovf_fired(uint32_t core_id)
|
||||
{
|
||||
return assist_debug_ll_sp_spill_is_fired(core_id);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -4,16 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include "soc/soc.h"
|
||||
|
||||
typedef enum {
|
||||
PANIC_RSN_NONE = 0,
|
||||
PANIC_RSN_INTWDT_CPU0,
|
||||
#if SOC_CPU_NUM > 1
|
||||
PANIC_RSN_INTWDT_CPU1,
|
||||
#endif
|
||||
PANIC_RSN_CACHEERR,
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
PANIC_RSN_MEMPROT,
|
||||
#endif
|
||||
PANIC_RSN_COUNT
|
||||
} panic_reasons_t;
|
||||
/* Since riscv does not replace mcause with "pseudo_reason" as it xtensa does
|
||||
* PANIC_RSN_* defined with original interrupt numbers to make it work in
|
||||
* common code
|
||||
*/
|
||||
#define PANIC_RSN_INTWDT_CPU0 ETS_INT_WDT_INUM
|
||||
|
@ -124,18 +124,26 @@ _vector_table:
|
||||
.option push
|
||||
.option norvc
|
||||
j _panic_handler /* exception handler, entry 0 */
|
||||
#if ETS_INT_WDT_INUM != 24
|
||||
#error "ETS_INT_WDT_INUM expected to be 24"
|
||||
#endif
|
||||
.rept (ETS_INT_WDT_INUM - 1)
|
||||
j _interrupt_handler /* 24 identical entries, all pointing to the interrupt handler */
|
||||
j _interrupt_handler /* 23 identical entries, all pointing to the interrupt handler */
|
||||
.endr
|
||||
j _panic_handler /* Call panic handler for ETS_INT_WDT_INUM interrupt (soc-level panic)*/
|
||||
j _panic_handler /* Call panic handler for ETS_CACHEERR_INUM interrupt (soc-level panic)*/
|
||||
#ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
j _panic_handler /* Call panic handler for ETS_MEMPROT_ERR_INUM interrupt (soc-level panic)*/
|
||||
.rept (ETS_MAX_INUM - ETS_MEMPROT_ERR_INUM)
|
||||
#else
|
||||
.rept (ETS_MAX_INUM - ETS_CACHEERR_INUM)
|
||||
#endif //CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
j _interrupt_handler /* 6 identical entries, all pointing to the interrupt handler */
|
||||
j _panic_handler /* 24: ETS_INT_WDT_INUM panic-interrupt (soc-level panic) */
|
||||
j _panic_handler /* 25: ETS_CACHEERR_INUM panic-interrupt (soc-level panic) */
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
j _panic_handler /* 26: ETS_MEMPROT_ERR_INUM panic-interrupt (soc-level panic) */
|
||||
#else
|
||||
j _interrupt_handler /* 26: interrupt-handler */
|
||||
#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
|
||||
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
j _panic_handler /* 27: ETS_ASSIST_DEBUG_INUM panic-interrupt (soc-level panic) */
|
||||
#else
|
||||
j _interrupt_handler /* 27: interrupt-handler */
|
||||
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
.rept (ETS_MAX_INUM - ETS_ASSIST_DEBUG_INUM)
|
||||
j _interrupt_handler /* remain entries are identical, all pointing to the interrupt handler */
|
||||
.endr
|
||||
|
||||
.option pop
|
||||
@ -241,9 +249,6 @@ _interrupt_handler:
|
||||
/* Save SP */
|
||||
sw t0, RV_STK_SP(sp)
|
||||
|
||||
/* Before doing anythig preserve the stack pointer */
|
||||
/* It will be saved in current TCB, if needed */
|
||||
mv a0, sp
|
||||
call rtos_int_enter
|
||||
/* If this is a non-nested interrupt, SP now points to the interrupt stack */
|
||||
|
||||
@ -305,13 +310,7 @@ _interrupt_handler:
|
||||
sw s3, 0(t0)
|
||||
fence
|
||||
|
||||
/* Yield to the next task is needed: */
|
||||
mv a0, sp
|
||||
call rtos_int_exit
|
||||
/* If this is a non-nested interrupt, context switch called, SP now points to back to task stack. */
|
||||
|
||||
/* The next (or current) stack pointer is returned in a0 */
|
||||
mv sp, a0
|
||||
|
||||
/* restore the rest of the registers */
|
||||
csrw mcause, s1
|
||||
|
@ -91,6 +91,10 @@ config SOC_CLK_TREE_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_ASSIST_DEBUG_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_XTAL_SUPPORT_26M
|
||||
bool
|
||||
default y
|
||||
|
@ -5,7 +5,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -15,77 +14,77 @@ extern "C" {
|
||||
* core0 monitor enable configuration register
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_INTR_ENA_REG (DR_REG_ASSIST_DEBUG_BASE + 0x0)
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA : R/W; bitpos: [0]; default: 0;
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA : R/W; bitpos: [0]; default: 0;
|
||||
* enbale sp underlow monitor
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_ENA_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA : R/W; bitpos: [1]; default: 0;
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_ENA_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA : R/W; bitpos: [1]; default: 0;
|
||||
* enbale sp overflow monitor
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_ENA_S 1
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_ENA_S 1
|
||||
|
||||
/** ASSIST_DEBUG_CORE_0_INTR_RAW_REG register
|
||||
* core0 monitor interrupt status register
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_INTR_RAW_REG (DR_REG_ASSIST_DEBUG_BASE + 0x4)
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW : RO; bitpos: [0]; default: 0;
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW : RO; bitpos: [0]; default: 0;
|
||||
* sp underlow monitor interrupt status register
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RAW_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW : RO; bitpos: [1]; default: 0;
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RAW_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW : RO; bitpos: [1]; default: 0;
|
||||
* sp overflow monitor interupt status register
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RAW_S 1
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RAW_S 1
|
||||
|
||||
/** ASSIST_DEBUG_CORE_0_INTR_RLS_REG register
|
||||
* core0 monitor interrupt enable register
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_INTR_RLS_REG (DR_REG_ASSIST_DEBUG_BASE + 0x8)
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS : R/W; bitpos: [0]; default: 0;
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS : R/W; bitpos: [0]; default: 0;
|
||||
* enbale sp underlow monitor interrupt
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_RLS_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS : R/W; bitpos: [1]; default: 0;
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_RLS_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS : R/W; bitpos: [1]; default: 0;
|
||||
* enbale sp overflow monitor interrupt
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_RLS_S 1
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_RLS_S 1
|
||||
|
||||
/** ASSIST_DEBUG_CORE_0_INTR_CLR_REG register
|
||||
* core0 monitor interrupt clr register
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_INTR_CLR_REG (DR_REG_ASSIST_DEBUG_BASE + 0xc)
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR : WT; bitpos: [0]; default: 0;
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR : WT; bitpos: [0]; default: 0;
|
||||
* clr sp underlow monitor interrupt
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_RD_CLR_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR : WT; bitpos: [1]; default: 0;
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR (BIT(0))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MIN_CLR_S 0
|
||||
/** ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR : WT; bitpos: [1]; default: 0;
|
||||
* clr sp overflow monitor interrupt
|
||||
*/
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR_M (ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR_V << ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR_S)
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_AREA_DRAM0_0_WR_CLR_S 1
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR (BIT(1))
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR_M (ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR_V << ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR_S)
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR_V 0x00000001U
|
||||
#define ASSIST_DEBUG_CORE_0_SP_SPILL_MAX_CLR_S 1
|
||||
|
||||
/** ASSIST_DEBUG_CORE_0_SP_MIN_REG register
|
||||
* stack min value
|
||||
|
@ -34,6 +34,7 @@ typedef enum {
|
||||
PERIPH_SARADC_MODULE,
|
||||
PERIPH_TEMPSENSOR_MODULE,
|
||||
PERIPH_MODEM_RPA_MODULE,
|
||||
PERIPH_ASSIST_DEBUG_MODULE,
|
||||
PERIPH_MODULE_MAX
|
||||
} periph_module_t;
|
||||
|
||||
|
@ -209,12 +209,11 @@
|
||||
//On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW.
|
||||
//There is no HW NMI conception. SW should controlled the masked levels through INT_THRESH_REG.
|
||||
|
||||
//CPU0 Interrupt number reserved in riscv/vector.S, not touch this.
|
||||
|
||||
//CPU0 Interrupt numbers used in components/riscv/vectors.S. Change it's logic if modifying
|
||||
#define ETS_T0_WDT_INUM 24
|
||||
#define ETS_CACHEERR_INUM 25
|
||||
#define ETS_MEMPROT_ERR_INUM 26
|
||||
#define ETS_DPORT_INUM 28
|
||||
#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
|
||||
|
||||
//CPU0 Max valid interrupt number
|
||||
#define ETS_MAX_INUM 31
|
||||
|
@ -16,7 +16,7 @@
|
||||
* If this file is changed the script will automatically run the script
|
||||
* and generate the kconfig variables as part of the pre-commit hooks.
|
||||
*
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py 'components/soc/esp32c3/include/soc/'`
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py -d 'components/soc/esp32c2/include/soc/'`
|
||||
*
|
||||
* For more information see `tools/gen_soc_caps_kconfig/README.md`
|
||||
*
|
||||
@ -47,6 +47,7 @@
|
||||
#define SOC_SYSTIMER_SUPPORTED 1
|
||||
#define SOC_BOD_SUPPORTED 1
|
||||
#define SOC_CLK_TREE_SUPPORTED 1
|
||||
#define SOC_ASSIST_DEBUG_SUPPORTED 1
|
||||
|
||||
/*-------------------------- XTAL CAPS ---------------------------------------*/
|
||||
#define SOC_XTAL_SUPPORT_26M 1
|
||||
|
@ -143,6 +143,10 @@ config SOC_CLK_TREE_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_ASSIST_DEBUG_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_XTAL_SUPPORT_40M
|
||||
bool
|
||||
default y
|
||||
|
@ -39,6 +39,7 @@ typedef enum {
|
||||
PERIPH_SYSTIMER_MODULE,
|
||||
PERIPH_SARADC_MODULE,
|
||||
PERIPH_TEMPSENSOR_MODULE,
|
||||
PERIPH_ASSIST_DEBUG_MODULE,
|
||||
PERIPH_MODULE_MAX
|
||||
} periph_module_t;
|
||||
|
||||
|
@ -209,10 +209,12 @@
|
||||
//On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW.
|
||||
//There is no HW NMI conception. SW should controlled the masked levels through INT_THRESH_REG.
|
||||
|
||||
//CPU0 Interrupt number reserved in riscv/vector.S, not touch this.
|
||||
//CPU0 Interrupt numbers used in components/riscv/vectors.S. Change it's logic if modifying
|
||||
#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
|
||||
|
||||
//CPU0 Max valid interrupt number
|
||||
#define ETS_MAX_INUM 31
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* If this file is changed the script will automatically run the script
|
||||
* and generate the kconfig variables as part of the pre-commit hooks.
|
||||
*
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py 'components/soc/esp32c3/include/soc/'`
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py -d 'components/soc/esp32c3/include/soc/'`
|
||||
*
|
||||
* For more information see `tools/gen_soc_caps_kconfig/README.md`
|
||||
*
|
||||
@ -63,6 +63,7 @@
|
||||
#define SOC_MEMPROT_SUPPORTED 1
|
||||
#define SOC_BOD_SUPPORTED 1
|
||||
#define SOC_CLK_TREE_SUPPORTED 1
|
||||
#define SOC_ASSIST_DEBUG_SUPPORTED 1
|
||||
|
||||
/*-------------------------- XTAL CAPS ---------------------------------------*/
|
||||
#define SOC_XTAL_SUPPORT_40M 1
|
||||
|
@ -195,6 +195,10 @@ config SOC_CLK_TREE_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_ASSIST_DEBUG_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_XTAL_SUPPORT_40M
|
||||
bool
|
||||
default y
|
||||
|
@ -1,11 +1,10 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -48,6 +48,7 @@ typedef enum {
|
||||
PERIPH_IEEE802154_MODULE,
|
||||
PERIPH_COEX_MODULE,
|
||||
PERIPH_PHY_MODULE,
|
||||
PERIPH_ASSIST_DEBUG_MODULE,
|
||||
PERIPH_MODULE_MAX
|
||||
} periph_module_t;
|
||||
|
||||
|
@ -214,10 +214,12 @@
|
||||
//On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW.
|
||||
//There is no HW NMI conception. SW should controlled the masked levels through INT_THRESH_REG.
|
||||
|
||||
//CPU0 Interrupt number reserved in riscv/vector.S, not touch this.
|
||||
//CPU0 Interrupt numbers used in components/riscv/vectors.S. Change it's logic if modifying
|
||||
#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
|
||||
|
||||
//CPU0 Max valid interrupt number
|
||||
#define ETS_MAX_INUM 31
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* If this file is changed the script will automatically run the script
|
||||
* and generate the kconfig variables as part of the pre-commit hooks.
|
||||
*
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py 'components/soc/esp32c6/include/soc/'`
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py -d 'components/soc/esp32c6/include/soc/'`
|
||||
*
|
||||
* For more information see `tools/gen_soc_caps_kconfig/README.md`
|
||||
*
|
||||
@ -73,6 +73,7 @@
|
||||
#define SOC_LP_PERIPHERALS_SUPPORTED 1
|
||||
#define SOC_LP_I2C_SUPPORTED 1
|
||||
#define SOC_CLK_TREE_SUPPORTED 1
|
||||
#define SOC_ASSIST_DEBUG_SUPPORTED 1
|
||||
|
||||
/*-------------------------- XTAL CAPS ---------------------------------------*/
|
||||
#define SOC_XTAL_SUPPORT_40M 1
|
||||
|
@ -179,6 +179,10 @@ config SOC_CLK_TREE_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_ASSIST_DEBUG_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_XTAL_SUPPORT_32M
|
||||
bool
|
||||
default y
|
||||
|
@ -1,11 +1,10 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "soc/soc.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -47,6 +47,7 @@ typedef enum {
|
||||
PERIPH_IEEE802154_MODULE,
|
||||
PERIPH_COEX_MODULE,
|
||||
PERIPH_PHY_MODULE,
|
||||
PERIPH_ASSIST_DEBUG_MODULE,
|
||||
PERIPH_MODULE_MAX
|
||||
} periph_module_t;
|
||||
|
||||
|
@ -211,10 +211,12 @@
|
||||
//On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW.
|
||||
//There is no HW NMI conception. SW should controlled the masked levels through INT_THRESH_REG.
|
||||
|
||||
//CPU0 Interrupt number reserved in riscv/vector.S, not touch this.
|
||||
//CPU0 Interrupt numbers used in components/riscv/vectors.S. Change it's logic if modifying
|
||||
#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
|
||||
|
||||
//CPU0 Max valid interrupt number
|
||||
#define ETS_MAX_INUM 31
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* If this file is changed the script will automatically run the script
|
||||
* and generate the kconfig variables as part of the pre-commit hooks.
|
||||
*
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py 'components/soc/esp32h2/include/soc/'`
|
||||
* It can also be ran manually with `./tools/gen_soc_caps_kconfig/gen_soc_caps_kconfig.py -d 'components/soc/esp32h2/include/soc/'`
|
||||
*
|
||||
* For more information see `tools/gen_soc_caps_kconfig/README.md`
|
||||
*
|
||||
@ -70,6 +70,7 @@
|
||||
#define SOC_LP_TIMER_SUPPORTED 1
|
||||
#define SOC_PAU_SUPPORTED 1
|
||||
#define SOC_CLK_TREE_SUPPORTED 1
|
||||
#define SOC_ASSIST_DEBUG_SUPPORTED 1
|
||||
|
||||
/*-------------------------- XTAL CAPS ---------------------------------------*/
|
||||
#define SOC_XTAL_SUPPORT_32M 1
|
||||
|
@ -7,7 +7,7 @@ Fatal Errors
|
||||
Overview
|
||||
--------
|
||||
|
||||
In certain situations, execution of the program can not be continued in a well defined way. In ESP-IDF, these situations include:
|
||||
In certain situations, the execution of the program can not be continued in a well-defined way. In ESP-IDF, these situations include:
|
||||
|
||||
- CPU Exceptions: |CPU_EXCEPTIONS_LIST|
|
||||
- System level checks and safeguards:
|
||||
@ -67,7 +67,7 @@ Subsequent behavior of the panic handler can be set using :ref:`CONFIG_ESP_SYSTE
|
||||
|
||||
- Invoke dynamic GDB Stub (``ESP_SYSTEM_GDBSTUB_RUNTIME``)
|
||||
|
||||
Start GDB server which can communicate with GDB over console UART port. This option allows the user to debug a program at run time and set break points, alter the execution, etc. See `GDB Stub`_ for more details.
|
||||
Start the GDB server which can communicate with GDB over the console UART port. This option allows the user to debug a program at run time and set breakpoints, alter the execution, etc. See `GDB Stub`_ for more details.
|
||||
|
||||
The behavior of the panic handler is affected by three other configuration options.
|
||||
|
||||
@ -216,7 +216,7 @@ If :doc:`IDF Monitor <tools/idf-monitor>` is used, Program Counter values will b
|
||||
MSTATUS : 0x00001881 MTVEC : 0x40380001 MCAUSE : 0x00000007 MTVAL : 0x00000000
|
||||
MHARTID : 0x00000000
|
||||
|
||||
Moreover, the :doc:`IDF Monitor <tools/idf-monitor>` is also capable of generating and printing a backtrace thanks to the stack dump provided by the board in the panic handler.
|
||||
Moreover, :doc:`IDF Monitor <tools/idf-monitor>` is also capable of generating and printing a backtrace thanks to the stack dump provided by the board in the panic handler.
|
||||
The output looks like this:
|
||||
|
||||
::
|
||||
@ -313,7 +313,7 @@ This section explains the meaning of different error causes, printed in parens a
|
||||
|ILLEGAL_INSTR_MSG|
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This CPU exception indicates that the instruction which was executed was not a valid instruction. Most common reasons for this error include:
|
||||
This CPU exception indicates that the instruction which was executed was not a valid instruction. The most common reasons for this error include:
|
||||
|
||||
- FreeRTOS task function has returned. In FreeRTOS, if a task function needs to terminate, it should call :cpp:func:`vTaskDelete` and delete itself, instead of returning.
|
||||
|
||||
@ -361,11 +361,7 @@ This CPU exception indicates that the instruction which was executed was not a v
|
||||
Unhandled debug exception
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This will usually be followed by a message like::
|
||||
|
||||
Debug exception reason: Stack canary watchpoint triggered (task_name)
|
||||
|
||||
This error indicates that the application has written past the end of the stack of the task with name ``task_name``. Note that not every stack overflow is guaranteed to trigger this error. It is possible that the task writes to memory beyond the stack canary location, in which case the watchpoint will not be triggered.
|
||||
This CPU exception happens when the instruction ``BREAK`` is executed.
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
@ -382,7 +378,7 @@ This CPU exception indicates that the instruction which was executed was not a v
|
||||
Breakpoint
|
||||
^^^^^^^^^^
|
||||
|
||||
This CPU exception happens when the instruction ``EBREAK`` is executed.
|
||||
This CPU exception happens when the instruction ``EBREAK`` is executed. See also :ref:`FreeRTOS-End-Of-Stack-Watchpoint`.
|
||||
|
||||
Load address misaligned, Store address misaligned
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -440,6 +436,64 @@ ESP-IDF's heap implementation contains a number of run-time checks of the heap s
|
||||
|
||||
Consult :doc:`Heap Memory Debugging <../api-reference/system/heap_debug>` documentation for further information.
|
||||
|
||||
|STACK_OVERFLOW|
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
.. only:: SOC_ASSIST_DEBUG_SUPPORTED
|
||||
|
||||
Hardware Stack Guard
|
||||
""""""""""""""""""""
|
||||
|
||||
{IDF_TARGET_NAME} has an integrated assist-debug module that can watch the SP register to ensure that it is within the bounds of allocated stack memory. The assist-debug module needs to set new stack bounds on every interrupt handling and FreeRTOS context switch. This can have a small impact on performance.
|
||||
|
||||
Here are some additional details about the assist-debug module:
|
||||
|
||||
- Implemented in hardware
|
||||
- Watches Stack Pointer register value
|
||||
- Requires no additional CPU time or memory while watching stack bounds
|
||||
|
||||
When the assist-debug module detects a stack overflow, the panic handler will run and display a message that resembles the following:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
Guru Meditation Error: Core 0 panic'ed (Stack protection fault).
|
||||
|
||||
Hardware stack guard can be disabled using :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` options.
|
||||
|
||||
.. _FreeRTOS-End-Of-Stack-Watchpoint:
|
||||
|
||||
FreeRTOS End of Stack Watchpoint
|
||||
""""""""""""""""""""""""""""""""
|
||||
|
||||
ESP-IDF provides a custom FreeRTOS stack overflow detecting mechanism based on watchpoints. Every time FreeRTOS switches task context, one of the watchpoints is set to watch the last 32 bytes of stack.
|
||||
|
||||
Generally, this may cause the watchpoint to be triggered up to 28 bytes earlier than expected. The value 32 is chosen because it is larger than the stack canary size in FreeRTOS (20 bytes). Adopting this approach ensures that the watchpoint triggers before the stack canary is corrupted, not after.
|
||||
|
||||
.. note::
|
||||
Not every stack overflow is guaranteed to trigger the watchpoint. It is possible that the task writes to memory beyond the stack canary location, in which case the watchpoint will not be triggered.
|
||||
|
||||
If watchpoint triggers, the message will be similar to:
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
|
||||
::
|
||||
|
||||
Debug exception reason: Stack canary watchpoint triggered (task_name)
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
::
|
||||
|
||||
Guru Meditation Error: Core 0 panic'ed (Breakpoint). Exception was unhandled.
|
||||
|
||||
This feature can be enabled by using the :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` option.
|
||||
|
||||
|
||||
FreeRTOS Stack Checks
|
||||
"""""""""""""""""""""
|
||||
|
||||
See :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW`
|
||||
|
||||
Stack Smashing
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
@ -459,12 +513,14 @@ The backtrace should point to the function where stack smashing has occurred. Ch
|
||||
.. |CPU_EXCEPTIONS_LIST| replace:: Illegal Instruction, Load/Store Alignment Error, Load/Store Prohibited error, Double Exception.
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: IllegalInstruction
|
||||
.. |CACHE_ERR_MSG| replace:: Cache disabled but cached memory region accessed
|
||||
.. |STACK_OVERFLOW| replace:: Stack overflow
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
.. |CPU_EXCEPTIONS_LIST| replace:: Illegal Instruction, Load/Store Alignment Error, Load/Store Prohibited error.
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: Illegal instruction
|
||||
.. |CACHE_ERR_MSG| replace:: Cache error
|
||||
.. |STACK_OVERFLOW| replace:: Stack overflow
|
||||
|
||||
Undefined Behavior Sanitizer (UBSAN) Checks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -82,6 +82,7 @@ The following optimizations improve the execution of nearly all code, including
|
||||
:esp32: - Set :ref:`CONFIG_ESPTOOLPY_FLASHFREQ` to 80 MHz. This is double the 40 MHz default value and doubles the speed at which code is loaded or executed from flash. You should verify that the board or module that connects the {IDF_TARGET_NAME} to the flash chip is rated for 80 MHz operation at the relevant temperature ranges before changing this setting. This information is contained in the hardware datasheet(s).
|
||||
- Set :ref:`CONFIG_ESPTOOLPY_FLASHMODE` to QIO or QOUT mode (Quad I/O). Both almost double the speed at which code is loaded or executed from flash compared to the default DIO mode. QIO is slightly faster than QOUT if both are supported. Note that both the flash chip model, and the electrical connections between the {IDF_TARGET_NAME} and the flash chip must support quad I/O modes or the SoC will not work correctly.
|
||||
- Set :ref:`CONFIG_COMPILER_OPTIMIZATION` to ``Optimize for performance (-O2)`` . This may slightly increase binary size compared to the default setting, but almost certainly increases the performance of some code. Note that if your code contains C or C++ Undefined Behavior, then increasing the compiler optimization level may expose bugs that otherwise are not seen.
|
||||
:SOC_ASSIST_DEBUG_SUPPORTED: - Set :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` to disabled. This may slightly increase the performance of some code, especially in cases where a lot of interrupts occur on the device.
|
||||
:esp32: - If the application uses PSRAM and is based on ESP32 rev. 3 (ECO3), setting :ref:`CONFIG_ESP32_REV_MIN` to ``3`` disables PSRAM bug workarounds, reducing the code size and improving overall performance.
|
||||
:SOC_CPU_HAS_FPU: - Avoid using floating point arithmetic ``float``. Even though {IDF_TARGET_NAME} has a single precision hardware floating point unit, floating point calculations are always slower than integer calculations. If possible then use fixed point representations, a different method of integer representation, or convert part of the calculation to be integer only before switching to floating point.
|
||||
:not SOC_CPU_HAS_FPU: - Avoid using floating point arithmetic ``float``. On {IDF_TARGET_NAME} these calculations are emulated in software and are very slow. If possible, use fixed point representations, a different method of integer representation, or convert part of the calculation to be integer only before switching to floating point.
|
||||
|
@ -361,11 +361,7 @@ Guru Meditation 错误
|
||||
Unhandled debug exception
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
这后面通常会再跟一条消息::
|
||||
|
||||
Debug exception reason: Stack canary watchpoint triggered (task_name)
|
||||
|
||||
此错误表示应用程序写入的位置越过了 ``task_name`` 任务堆栈的末尾,请注意,并非每次堆栈溢出都会触发此错误。任务有可能会绕过堆栈金丝雀(stack canary)的位置访问内存,在这种情况下,监视点就不会被触发。
|
||||
执行指令 ``BREAK`` 时,会发生此 CPU 异常。
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
@ -382,7 +378,7 @@ Guru Meditation 错误
|
||||
Breakpoint
|
||||
^^^^^^^^^^
|
||||
|
||||
当执行 ``EBREAK`` 指令时,会发生此 CPU 异常。
|
||||
执行 ``EBREAK`` 指令时,会发生此 CPU 异常。请参见 :ref:`FreeRTOS-End-Of-Stack-Watchpoint`。
|
||||
|
||||
Load address misaligned, Store address misaligned
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -440,6 +436,64 @@ ESP-IDF 堆的实现包含许多运行时的堆结构检查,可以在 menuconf
|
||||
|
||||
更多详细信息,请查阅 :doc:`堆内存调试 <../api-reference/system/heap_debug>` 文档。
|
||||
|
||||
|STACK_OVERFLOW|
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
.. only:: SOC_ASSIST_DEBUG_SUPPORTED
|
||||
|
||||
硬件堆栈保护
|
||||
""""""""""""""""""""
|
||||
|
||||
{IDF_TARGET_NAME} 集成了辅助调试模块,支持监测堆栈指针 (SP) 寄存器,确保其值位于已分配给堆栈的内存范围内。发生中断处理或 FreeRTOS 切换上下文时,辅助调试模块都会设置新的堆栈监测范围。注意,该操作会对性能产生一定影响。
|
||||
|
||||
以下为辅助调试模块的部分相关特性:
|
||||
|
||||
- 采用硬件实现
|
||||
- 支持监测堆栈指针寄存器的值
|
||||
- 无需占用额外 CPU 时间或内存,即可监测堆栈内存范围
|
||||
|
||||
当辅助调试模块检测到堆栈溢出时,将触发紧急处理程序并打印类似如下信息:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
Guru Meditation Error: Core 0 panic'ed (Stack protection fault).
|
||||
|
||||
可以通过 :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` 选项,禁用硬件堆栈保护。
|
||||
|
||||
.. _FreeRTOS-End-Of-Stack-Watchpoint:
|
||||
|
||||
FreeRTOS 任务堆栈末尾监视点
|
||||
""""""""""""""""""""""""""""""""
|
||||
|
||||
ESP-IDF 支持基于监视点的 FreeRTOS 堆栈溢出检测机制。每次 FreeRTOS 切换任务上下文时,都会设置一个监视点,用于监视堆栈的最后 32 字节。
|
||||
|
||||
通常,该设置会提前触发监视点,触发点可能会比预期提前多达 28 字节。基于 FreeRTOS 中堆栈金丝雀的大小为 20 字节,故将观察范围设置为 32 字节,确保可以在堆栈金丝雀遭到破坏前及时触发监测点。
|
||||
|
||||
.. note::
|
||||
并非每次堆栈溢出都能触发监视点。如果任务绕过堆栈金丝雀的位置访问堆栈,则无法触发监视点。
|
||||
|
||||
监视点触发后,将打印类似如下信息:
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
|
||||
::
|
||||
|
||||
Debug exception reason: Stack canary watchpoint triggered (task_name)
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
::
|
||||
|
||||
Guru Meditation Error: Core 0 panic'ed (Breakpoint). Exception was unhandled.
|
||||
|
||||
可以通过 :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 选项启用该功能。
|
||||
|
||||
|
||||
FreeRTOS 堆栈检查
|
||||
"""""""""""""""""""""
|
||||
|
||||
请参见 :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW`。
|
||||
|
||||
堆栈粉碎
|
||||
^^^^^^^^^^
|
||||
|
||||
@ -457,16 +511,18 @@ ESP-IDF 堆的实现包含许多运行时的堆结构检查,可以在 menuconf
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
|
||||
.. |CPU_EXCEPTIONS_LIST| replace:: 非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误,双重异常。
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: IllegalInstruction
|
||||
.. |CACHE_ERR_MSG| replace:: Cache disabled but cached memory region accessed
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: 非法指令
|
||||
.. |CACHE_ERR_MSG| replace:: cache 已禁用,但仍可访问缓存内存区域
|
||||
.. |STACK_OVERFLOW| replace:: 堆栈溢出
|
||||
|
||||
.. only:: CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
|
||||
.. |CPU_EXCEPTIONS_LIST| replace:: 非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误。
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: Illegal instruction
|
||||
.. |CACHE_ERR_MSG| replace:: Cache error
|
||||
.. |ILLEGAL_INSTR_MSG| replace:: 非法指令
|
||||
.. |CACHE_ERR_MSG| replace:: cache 错误
|
||||
.. |STACK_OVERFLOW| replace:: 堆栈溢出
|
||||
|
||||
未定义行为清理器(UBSAN)检查
|
||||
未定义行为清理器 (UBSAN) 检查
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
未定义行为清理器 (UBSAN) 是一种编译器功能,它会为可能不正确的操作添加运行时检查,例如:
|
||||
|
@ -15,3 +15,6 @@ idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES spi_flash esp_psram esp_system esp_partition
|
||||
PRIV_REQUIRES esp_gdbstub)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-unused-variable"
|
||||
"-Wno-infinite-recursion")
|
||||
|
@ -24,6 +24,8 @@ void test_int_wdt(void);
|
||||
|
||||
void test_task_wdt_cpu0(void);
|
||||
|
||||
void test_hw_stack_guard_cpu0(void);
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
void test_panic_extram_stack(void);
|
||||
#endif
|
||||
|
@ -83,6 +83,7 @@ void app_main(void)
|
||||
HANDLE_TEST(test_name, test_abort_cache_disabled);
|
||||
HANDLE_TEST(test_name, test_int_wdt);
|
||||
HANDLE_TEST(test_name, test_task_wdt_cpu0);
|
||||
HANDLE_TEST(test_name, test_hw_stack_guard_cpu0);
|
||||
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
HANDLE_TEST(test_name, test_panic_extram_stack);
|
||||
#endif
|
||||
|
@ -61,6 +61,13 @@ void test_task_wdt_cpu0(void)
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((optimize("-O0")))
|
||||
void test_hw_stack_guard_cpu0(void)
|
||||
{
|
||||
uint32_t buf[128];
|
||||
test_hw_stack_guard_cpu0();
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
|
||||
static void stack_in_extram(void* arg) {
|
||||
|
@ -52,6 +52,21 @@ CONFIGS_EXTRAM_STACK = [
|
||||
pytest.param('coredump_extram_stack', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.psram, pytest.mark.esp32s3, pytest.mark.quad_psram])
|
||||
]
|
||||
|
||||
TARGETS_HW_STACK_GUARD = [
|
||||
pytest.mark.esp32c2,
|
||||
pytest.mark.esp32c3,
|
||||
pytest.mark.esp32c6,
|
||||
pytest.mark.esp32h2,
|
||||
]
|
||||
|
||||
CONFIGS_HW_STACK_GUARD = [
|
||||
pytest.param('coredump_flash_bin_crc', marks=TARGETS_HW_STACK_GUARD),
|
||||
pytest.param('coredump_uart_bin_crc', marks=TARGETS_HW_STACK_GUARD),
|
||||
pytest.param('coredump_uart_elf_crc', marks=TARGETS_HW_STACK_GUARD),
|
||||
pytest.param('gdbstub', marks=TARGETS_HW_STACK_GUARD),
|
||||
pytest.param('panic', marks=TARGETS_HW_STACK_GUARD),
|
||||
]
|
||||
|
||||
|
||||
def get_default_backtrace(config: str) -> List[str]:
|
||||
return [config, 'app_main', 'main_task', 'vPortTaskWrapper']
|
||||
@ -773,3 +788,15 @@ def test_gdbstub_coredump(dut: PanicTestDut) -> None:
|
||||
dut.verify_gdb_backtrace(frames, get_default_backtrace(test_func_name))
|
||||
dut.revert_log_level()
|
||||
return # don't expect "Rebooting" output below
|
||||
|
||||
|
||||
@pytest.mark.parametrize('config', CONFIGS_HW_STACK_GUARD, indirect=True)
|
||||
@pytest.mark.generic
|
||||
def test_hw_stack_guard_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||
dut.run_test_func(test_func_name)
|
||||
dut.expect_exact('Guru Meditation Error: Core 0 panic\'ed (Stack protection fault).')
|
||||
dut.expect_none('ASSIST_DEBUG is not triggered BUT interrupt occured!')
|
||||
dut.expect(r'Detected in task(.*)at 0x')
|
||||
dut.expect_exact('Stack pointer: 0x')
|
||||
dut.expect(r'Stack bounds: 0x(.*) - 0x')
|
||||
common_test(dut, config)
|
||||
|
Loading…
x
Reference in New Issue
Block a user