Przeglądaj źródła

Merge branch 'bugfix/fix_onebyte_watchpoint_setting' into 'master'

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

See merge request espressif/esp-idf!27159
Wu Zheng Hui 2 lat temu
rodzic
commit
a2f0198cd1

+ 11 - 3
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);

+ 8 - 2
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
  */

+ 2 - 1
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)

+ 12 - 10
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)

+ 1 - 1
components/soc/esp32/include/soc/Kconfig.soc_caps.in

@@ -283,7 +283,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 2
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     int
     default 64
 

+ 3 - 3
components/soc/esp32/include/soc/soc_caps.h

@@ -155,9 +155,9 @@
 #define SOC_CPU_INTR_NUM                32
 #define SOC_CPU_HAS_FPU                 1
 
-#define SOC_CPU_BREAKPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINT_SIZE         64 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  64 // bytes
 
 /*-------------------------- DAC CAPS ----------------------------------------*/
 #define SOC_DAC_CHAN_NUM              2

+ 1 - 1
components/soc/esp32c2/include/soc/Kconfig.soc_caps.in

@@ -223,7 +223,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 2
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     hex
     default 0x80000000
 

+ 3 - 3
components/soc/esp32c2/include/soc/soc_caps.h

@@ -101,9 +101,9 @@
 #define SOC_CPU_INTR_NUM                32
 #define SOC_CPU_HAS_FLEXIBLE_INTC       1
 
-#define SOC_CPU_BREAKPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINT_SIZE         0x80000000 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  0x80000000 // bytes
 
 #define SOC_CPU_IDRAM_SPLIT_USING_PMP   1
 

+ 1 - 1
components/soc/esp32c3/include/soc/Kconfig.soc_caps.in

@@ -311,7 +311,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 8
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     hex
     default 0x80000000
 

+ 3 - 3
components/soc/esp32c3/include/soc/soc_caps.h

@@ -133,9 +133,9 @@
 #define SOC_CPU_INTR_NUM                32
 #define SOC_CPU_HAS_FLEXIBLE_INTC       1
 
-#define SOC_CPU_BREAKPOINTS_NUM         8
-#define SOC_CPU_WATCHPOINTS_NUM         8
-#define SOC_CPU_WATCHPOINT_SIZE         0x80000000 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             8
+#define SOC_CPU_WATCHPOINTS_NUM             8
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  0x80000000 // bytes
 
 /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/
 /** The maximum length of a Digital Signature in bits. */

+ 1 - 1
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -375,7 +375,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 4
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     hex
     default 0x80000000
 

+ 3 - 3
components/soc/esp32c6/include/soc/soc_caps.h

@@ -149,9 +149,9 @@
 #define SOC_CPU_HAS_FLEXIBLE_INTC       1
 #define SOC_INT_PLIC_SUPPORTED          1       //riscv platform-level interrupt controller
 
-#define SOC_CPU_BREAKPOINTS_NUM         4
-#define SOC_CPU_WATCHPOINTS_NUM         4
-#define SOC_CPU_WATCHPOINT_SIZE         0x80000000 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             4
+#define SOC_CPU_WATCHPOINTS_NUM             4
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  0x80000000 // bytes
 
 #define SOC_CPU_HAS_PMA                 1
 #define SOC_CPU_IDRAM_SPLIT_USING_PMP   1

+ 1 - 1
components/soc/esp32h2/include/soc/Kconfig.soc_caps.in

@@ -359,7 +359,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 4
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     hex
     default 0x80000000
 

+ 3 - 3
components/soc/esp32h2/include/soc/soc_caps.h

@@ -146,9 +146,9 @@
 #define SOC_CPU_HAS_FLEXIBLE_INTC       1
 #define SOC_INT_PLIC_SUPPORTED          1       //riscv platform-level interrupt controller
 
-#define SOC_CPU_BREAKPOINTS_NUM         4
-#define SOC_CPU_WATCHPOINTS_NUM         4
-#define SOC_CPU_WATCHPOINT_SIZE         0x80000000 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             4
+#define SOC_CPU_WATCHPOINTS_NUM             4
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  0x80000000 // bytes
 
 #define SOC_CPU_HAS_PMA                 1
 #define SOC_CPU_IDRAM_SPLIT_USING_PMP   1

+ 4 - 4
components/soc/esp32p4/include/soc/Kconfig.soc_caps.in

@@ -305,15 +305,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_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     hex
-    default 0x80000000
+    default 0x100
 
 config SOC_CPU_HAS_PMA
     bool

+ 3 - 3
components/soc/esp32p4/include/soc/soc_caps.h

@@ -154,9 +154,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_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

+ 1 - 1
components/soc/esp32s2/include/soc/Kconfig.soc_caps.in

@@ -323,7 +323,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 2
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     int
     default 64
 

+ 3 - 3
components/soc/esp32s2/include/soc/soc_caps.h

@@ -142,9 +142,9 @@
 #define SOC_CPU_CORES_NUM               (1U)
 #define SOC_CPU_INTR_NUM                32
 
-#define SOC_CPU_BREAKPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINT_SIZE         64 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  64 // bytes
 
 /*-------------------------- DAC CAPS ----------------------------------------*/
 #define SOC_DAC_CHAN_NUM      2

+ 1 - 1
components/soc/esp32s3/include/soc/Kconfig.soc_caps.in

@@ -371,7 +371,7 @@ config SOC_CPU_WATCHPOINTS_NUM
     int
     default 2
 
-config SOC_CPU_WATCHPOINT_SIZE
+config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
     int
     default 64
 

+ 3 - 3
components/soc/esp32s3/include/soc/soc_caps.h

@@ -137,9 +137,9 @@
 #define SOC_CPU_INTR_NUM                32
 #define SOC_CPU_HAS_FPU                 1
 
-#define SOC_CPU_BREAKPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINTS_NUM         2
-#define SOC_CPU_WATCHPOINT_SIZE         64 // bytes
+#define SOC_CPU_BREAKPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINTS_NUM             2
+#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE  64 // bytes
 
 /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/
 /** The maximum length of a Digital Signature in bits. */