diff --git a/components/esp_hw_support/cpu.c b/components/esp_hw_support/cpu.c index 74b521ff76..7fefa9d432 100644 --- a/components/esp_hw_support/cpu.c +++ b/components/esp_hw_support/cpu.c @@ -387,11 +387,19 @@ esp_err_t esp_cpu_set_watchpoint(int wp_num, const void *wp_addr, size_t size, e { /* Todo: - - Check that wp_num is in range - Check if the wp_num is already in use */ - // Check if size is 2^n, where n is in [0...6] - if (size < 1 || size > 64 || (size & (size - 1)) != 0) { + if (wp_num < 0 || wp_num >= SOC_CPU_WATCHPOINTS_NUM) { + return ESP_ERR_INVALID_ARG; + } + + // Check that the watched region's start address is naturally aligned to the size of the region + if ((uint32_t)wp_addr % size) { + return ESP_ERR_INVALID_ARG; + } + + // Check if size is 2^n, and size is in the range of [1 ... SOC_CPU_WATCHPOINT_MAX_REGION_SIZE] + if (size < 1 || size > SOC_CPU_WATCHPOINT_MAX_REGION_SIZE || (size & (size - 1)) != 0) { return ESP_ERR_INVALID_ARG; } bool on_read = (trigger == ESP_CPU_WATCHPOINT_LOAD || trigger == ESP_CPU_WATCHPOINT_ACCESS); diff --git a/components/esp_hw_support/include/esp_cpu.h b/components/esp_hw_support/include/esp_cpu.h index 46ea42a2ae..45b7df7556 100644 --- a/components/esp_hw_support/include/esp_cpu.h +++ b/components/esp_hw_support/include/esp_cpu.h @@ -482,9 +482,15 @@ esp_err_t esp_cpu_clear_breakpoint(int bp_num); * the CPU accesses (according to the trigger type) on a certain memory range. * * @note Overwrites previously set watchpoint with same watchpoint number. + * On RISC-V chips, this API uses method0(Exact matching) and method1(NAPOT matching) according to the + * riscv-debug-spec-0.13 specification for address matching. + * If the watch region size is 1byte, it uses exact matching (method 0). + * If the watch region size is larger than 1byte, it uses NAPOT matching (method 1). This mode requires + * the watching region start address to be aligned to the watching region size. + * * @param wp_num Hardware watchpoint number [0..SOC_CPU_WATCHPOINTS_NUM - 1] - * @param wp_addr Watchpoint's base address - * @param size Size of the region to watch. Must be one of 2^n, with n in [0..6]. + * @param wp_addr Watchpoint's base address, must be naturally aligned to the size of the region + * @param size Size of the region to watch. Must be one of 2^n and in the range of [1 ... SOC_CPU_WATCHPOINT_MAX_REGION_SIZE] * @param trigger Trigger type * @return ESP_ERR_INVALID_ARG on invalid arg, ESP_OK otherwise */ diff --git a/components/riscv/include/riscv/csr.h b/components/riscv/include/riscv/csr.h index ebbda1d2fe..17e1f723e3 100644 --- a/components/riscv/include/riscv/csr.h +++ b/components/riscv/include/riscv/csr.h @@ -148,7 +148,8 @@ extern "C" { #define TDATA1_EXECUTE (1<<2) /*R/W,Fire trigger on instruction fetch address match*/ #define TDATA1_USER (1<<3) /*R/W,allow trigger to be fired in user mode*/ #define TDATA1_MACHINE (1<<6) /*R/W,Allow trigger to be fired while hart is executing in machine mode*/ -#define TDATA1_MATCH (1<<7) +#define TDATA1_MATCH_EXACT (0) +#define TDATA1_MATCH_NAPOT (1<<7) #define TDATA1_MATCH_V (0xF) /*R/W,Address match type :0 : Exact byte match 1 : NAPOT range match */ #define TDATA1_MATCH_S (7) #define TDATA1_HIT_S (20) diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 92f493ed88..23f65db3f6 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -298,30 +298,32 @@ FORCE_INLINE_ATTR void rv_utils_set_watchpoint(int wp_num, RV_WRITE_CSR(tcontrol, TCONTROL_MPTE | TCONTROL_MTE); RV_WRITE_CSR(tdata1, TDATA1_USER | TDATA1_MACHINE | - TDATA1_MATCH | + ((size == 1) ? TDATA1_MATCH_EXACT : TDATA1_MATCH_NAPOT) | (on_read ? TDATA1_LOAD : 0) | (on_write ? TDATA1_STORE : 0)); /* From RISC-V Debug Specification: - * NAPOT (Naturally Aligned Power-Of-Two): + * tdata1(mcontrol) match = 0 : Exact byte match + * + * tdata1(mcontrol) match = 1 : NAPOT (Naturally Aligned Power-Of-Two): * Matches when the top M bits of any compare value match the top M bits of tdata2. * M is XLEN − 1 minus the index of the least-significant bit containing 0 in tdata2. + * Note: Expecting that size is number power of 2 (numbers should be in the range of 1 ~ 31) * - * Note: Expectng that size is number power of 2 - * - * Examples for understanding how to calculate NAPOT: + * Examples for understanding how to calculate match pattern to tdata2: * + * nnnn...nnnnn 1-byte Exact byte match * nnnn...nnnn0 2-byte NAPOT range * nnnn...nnn01 4-byte NAPOT range * nnnn...nn011 8-byte NAPOT range * nnnn...n0111 16-byte NAPOT range * nnnn...01111 32-byte NAPOT range + * ... + * n011...11111 2^31 byte NAPOT range * * where n are bits from original address */ - const uint32_t half_size = size >> 1; - uint32_t napot = wp_addr; - napot &= ~half_size; /* set the least-significant bit with zero */ - napot |= half_size - 1; /* fill all bits with ones after least-significant bit */ - RV_WRITE_CSR(tdata2, napot); + uint32_t match_pattern = (wp_addr & ~(size-1)) | ((size-1) >> 1); + + RV_WRITE_CSR(tdata2, match_pattern); } FORCE_INLINE_ATTR void rv_utils_clear_breakpoint(int bp_num) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index e35c6d7fb3..76fc89ae6b 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -301,15 +301,15 @@ config SOC_CPU_COPROC_NUM config SOC_CPU_BREAKPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE hex - default 0x80000000 + default 0x100 config SOC_CPU_HAS_PMA bool diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 0a815b6431..188117b872 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -153,9 +153,9 @@ #define SOC_CPU_HAS_FPU_EXT_ILL_BUG 1 // EXT_ILL CSR doesn't support FLW/FSW #define SOC_CPU_COPROC_NUM 2 -#define SOC_CPU_BREAKPOINTS_NUM 4 -#define SOC_CPU_WATCHPOINTS_NUM 4 -#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x80000000 // bytes +#define SOC_CPU_BREAKPOINTS_NUM 3 +#define SOC_CPU_WATCHPOINTS_NUM 3 +#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x100 // bytes #define SOC_CPU_HAS_PMA 1 #define SOC_CPU_IDRAM_SPLIT_USING_PMP 1