fix(riscv): supports 1 byte and larger than 64byte range watchpoint setting

This commit is contained in:
wuzhenghui 2023-11-15 14:00:09 +08:00 committed by BOT
parent 0a17593a7f
commit 8c34ab0e67
4 changed files with 36 additions and 19 deletions

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -575,11 +575,19 @@ esp_err_t esp_cpu_set_watchpoint(int wp_num, const void *wp_addr, size_t size, e
{ {
/* /*
Todo: Todo:
- Check that wp_num is in range
- Check if the wp_num is already in use - Check if the wp_num is already in use
*/ */
// Check if size is 2^n, where n is in [0...6] if (wp_num < 0 || wp_num >= SOC_CPU_WATCHPOINTS_NUM) {
if (size < 1 || size > 64 || (size & (size - 1)) != 0) { 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; return ESP_ERR_INVALID_ARG;
} }
bool on_read = (trigger == ESP_CPU_WATCHPOINT_LOAD || trigger == ESP_CPU_WATCHPOINT_ACCESS); bool on_read = (trigger == ESP_CPU_WATCHPOINT_LOAD || trigger == ESP_CPU_WATCHPOINT_ACCESS);

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -468,9 +468,15 @@ esp_err_t esp_cpu_clear_breakpoint(int bp_num);
* the CPU accesses (according to the trigger type) on a certain memory range. * the CPU accesses (according to the trigger type) on a certain memory range.
* *
* @note Overwrites previously set watchpoint with same watchpoint number. * @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_num Hardware watchpoint number [0..SOC_CPU_WATCHPOINTS_NUM - 1]
* @param wp_addr Watchpoint's base address * @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, with n in [0..6]. * @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 * @param trigger Trigger type
* @return ESP_ERR_INVALID_ARG on invalid arg, ESP_OK otherwise * @return ESP_ERR_INVALID_ARG on invalid arg, ESP_OK otherwise
*/ */

View File

@ -99,7 +99,8 @@ extern "C" {
#define TDATA1_EXECUTE (1<<2) /*R/W,Fire trigger on instruction fetch address match*/ #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_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_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_V (0xF) /*R/W,Address match type :0 : Exact byte match 1 : NAPOT range match */
#define TDATA1_MATCH_S (7) #define TDATA1_MATCH_S (7)
#define TDATA1_HIT_S (20) #define TDATA1_HIT_S (20)

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -147,30 +147,32 @@ FORCE_INLINE_ATTR void rv_utils_set_watchpoint(int wp_num,
RV_WRITE_CSR(tcontrol, TCONTROL_MPTE | TCONTROL_MTE); RV_WRITE_CSR(tcontrol, TCONTROL_MPTE | TCONTROL_MTE);
RV_WRITE_CSR(tdata1, TDATA1_USER | RV_WRITE_CSR(tdata1, TDATA1_USER |
TDATA1_MACHINE | TDATA1_MACHINE |
TDATA1_MATCH | ((size == 1) ? TDATA1_MATCH_EXACT : TDATA1_MATCH_NAPOT) |
(on_read ? TDATA1_LOAD : 0) | (on_read ? TDATA1_LOAD : 0) |
(on_write ? TDATA1_STORE : 0)); (on_write ? TDATA1_STORE : 0));
/* From RISC-V Debug Specification: /* 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. * 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. * 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 match pattern to tdata2:
*
* Examples for understanding how to calculate NAPOT:
* *
* nnnn...nnnnn 1-byte Exact byte match
* nnnn...nnnn0 2-byte NAPOT range * nnnn...nnnn0 2-byte NAPOT range
* nnnn...nnn01 4-byte NAPOT range * nnnn...nnn01 4-byte NAPOT range
* nnnn...nn011 8-byte NAPOT range * nnnn...nn011 8-byte NAPOT range
* nnnn...n0111 16-byte NAPOT range * nnnn...n0111 16-byte NAPOT range
* nnnn...01111 32-byte NAPOT range * nnnn...01111 32-byte NAPOT range
* ...
* n011...11111 2^31 byte NAPOT range
* * where n are bits from original address * * where n are bits from original address
*/ */
const uint32_t half_size = size >> 1; uint32_t match_pattern = (wp_addr & ~(size-1)) | ((size-1) >> 1);
uint32_t napot = wp_addr;
napot &= ~half_size; /* set the least-significant bit with zero */ RV_WRITE_CSR(tdata2, match_pattern);
napot |= half_size - 1; /* fill all bits with ones after least-significant bit */
RV_WRITE_CSR(tdata2, napot);
} }
FORCE_INLINE_ATTR void rv_utils_clear_breakpoint(int bp_num) FORCE_INLINE_ATTR void rv_utils_clear_breakpoint(int bp_num)