This is an automated email from Gerrit.

"Ian Thompson <ia...@cadence.com>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/8080

-- gerrit

commit 241364315c93a3de9a6d14a1931c2c320f039637
Author: Ian Thompson <ia...@cadence.com>
Date:   Wed Jan 31 15:14:25 2024 -0800

    target/xtensa: avoid IHI for writes to non-executable memory
    
    For MPU configs, determine memory access rights
    by probing protection TLB.  Issuing IHI without execute
    permissions can trigger an exception.
    
    No new clang static analyzer warnings.
    
    Change-Id: Iea8eab5c2113df3f954285c3b9a79e96d41aa941
    Signed-off-by: Ian Thompson <ia...@cadence.com>

diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c
index fb7748aa2d..f7c82efed4 100644
--- a/src/target/xtensa/xtensa.c
+++ b/src/target/xtensa/xtensa.c
@@ -158,6 +158,12 @@
 #define XT_INS_RFWU(X) (XT_ISBE(X) ? 0x005300 << 8 : 0x003500)
 #define XT_INS_RFWO_RFWU_MASK(X)   (XT_ISBE(X) ? 0xFFFFFF << 8 : 0xFFFFFF)
 
+/* Read Protection TLB Entry Info */
+#define XT_INS_PPTLB(X, S, T) _XT_INS_FORMAT_RRR(X, 0x500000, ((S) << 4) | 
(T), 0xD)
+
+#define XT_TLB1_ACC_SHIFT              8
+#define XT_TLB1_ACC_MSK                        0xF
+
 #define XT_WATCHPOINTS_NUM_MAX  2
 
 /* Special register number macro for DDR, PS, WB, A3, A4 registers.
@@ -298,6 +304,27 @@ enum xtensa_mem_region_type {
        XTENSA_MEM_REGS_NUM
 };
 
+/**
+ * Types of access rights for MPU option
+ * The first block is kernel RWX ARs; the second block is user rwx ARs.
+ */
+enum xtensa_mpu_access_type {
+       XTENSA_ACC_00X_000 = 0x2,
+       XTENSA_ACC_000_00X,
+       XTENSA_ACC_R00_000,
+       XTENSA_ACC_R0X_000,
+       XTENSA_ACC_RW0_000,
+       XTENSA_ACC_RWX_000,
+       XTENSA_ACC_0W0_0W0,
+       XTENSA_ACC_RW0_RWX,
+       XTENSA_ACC_RW0_R00,
+       XTENSA_ACC_RWX_R0X,
+       XTENSA_ACC_R00_R00,
+       XTENSA_ACC_R0X_R0X,
+       XTENSA_ACC_RW0_RW0,
+       XTENSA_ACC_RWX_RWX
+};
+
 /* Register definition as union for list allocation */
 union xtensa_reg_val_u {
        xtensa_reg_val_t val;
@@ -521,6 +548,44 @@ static void xtensa_queue_exec_ins_wide(struct xtensa 
*xtensa, uint8_t *ops, uint
        }
 }
 
+/* NOTE: Assumes A3 has already been saved and marked dirty; A3 will be 
clobbered */
+static inline bool xtensa_region_ar_exec(struct target *target, target_addr_t 
start, target_addr_t end)
+{
+       struct xtensa *xtensa = target_to_xtensa(target);
+       if (xtensa->core_config->mpu.enabled) {
+               /* For cores with the MPU option, issue PPTLB on start and end 
addresses.
+                * Parse access rights field, and confirm both have execute 
permissions.
+                */
+               for (int i = 0; i <= 1; i++) {
+                       uint32_t at, acc;
+                       uint8_t at_buf[4];
+                       bool exec_acc;
+                       target_addr_t addr = i ? end : start;
+                       xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, addr);
+                       xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, 
XT_SR_DDR, XT_REG_A3));
+                       xtensa_queue_exec_ins(xtensa, XT_INS_PPTLB(xtensa, 
XT_REG_A3, XT_REG_A3));
+                       xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, 
XT_SR_DDR, XT_REG_A3));
+                       xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, at_buf);
+                       int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+                       if (res != ERROR_OK)
+                               LOG_TARGET_ERROR(target, "Error queuing PPTLB: 
%d", res);
+                       res = xtensa_core_status_check(target);
+                       if (res != ERROR_OK)
+                               LOG_TARGET_ERROR(target, "Error issuing PPTLB: 
%d", res);
+                       at = buf_get_u32(at_buf, 0, 32);
+                       acc = (at >> XT_TLB1_ACC_SHIFT) & XT_TLB1_ACC_MSK;
+                       exec_acc = ((acc == XTENSA_ACC_00X_000) || (acc == 
XTENSA_ACC_R0X_000) ||
+                                               (acc == XTENSA_ACC_RWX_000) || 
(acc == XTENSA_ACC_RWX_R0X) ||
+                                               (acc == XTENSA_ACC_R0X_R0X) || 
(acc == XTENSA_ACC_RWX_RWX));
+                       LOG_TARGET_DEBUG(target, "PPTLB(" TARGET_ADDR_FMT ") -> 
0x%08" PRIx32 " exec_acc %d",
+                               addr, at, exec_acc);
+                       if (!exec_acc)
+                               return false;
+               }
+       }
+       return true;
+}
+
 static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, 
uint32_t data)
 {
        struct xtensa_debug_module *dm = &xtensa->dbg_mod;
@@ -2176,11 +2241,13 @@ int xtensa_write_memory(struct target *target,
                }
        } else {
                /* Invalidate ICACHE, writeback DCACHE if present */
-               uint32_t issue_ihi = xtensa_is_icacheable(xtensa, address);
-               uint32_t issue_dhwb = xtensa_is_dcacheable(xtensa, address);
-               if (issue_ihi || issue_dhwb) {
+               bool issue_ihi = xtensa_is_icacheable(xtensa, address) &&
+                                                xtensa_region_ar_exec(target, 
addrstart_al, addrend_al);
+               bool issue_dhwbi = xtensa_is_dcacheable(xtensa, address);
+               LOG_TARGET_DEBUG(target, "Cache OPs: IHI %d, DHWBI %d", 
issue_ihi, issue_dhwbi);
+               if (issue_ihi || issue_dhwbi) {
                        uint32_t ilinesize = issue_ihi ?  
xtensa->core_config->icache.line_size : UINT32_MAX;
-                       uint32_t dlinesize = issue_dhwb ? 
xtensa->core_config->dcache.line_size : UINT32_MAX;
+                       uint32_t dlinesize = issue_dhwbi ? 
xtensa->core_config->dcache.line_size : UINT32_MAX;
                        uint32_t linesize = MIN(ilinesize, dlinesize);
                        uint32_t off = 0;
                        adr = addrstart_al;
@@ -2193,7 +2260,7 @@ int xtensa_write_memory(struct target *target,
                                }
                                if (issue_ihi)
                                        xtensa_queue_exec_ins(xtensa, 
XT_INS_IHI(xtensa, XT_REG_A3, off));
-                               if (issue_dhwb)
+                               if (issue_dhwbi)
                                        xtensa_queue_exec_ins(xtensa, 
XT_INS_DHWBI(xtensa, XT_REG_A3, off));
                                off += linesize;
                                if (off > 1020) {
@@ -2205,7 +2272,11 @@ int xtensa_write_memory(struct target *target,
 
                        /* Execute cache WB/INV instructions */
                        res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
-                       xtensa_core_status_check(target);
+                       if (res != ERROR_OK)
+                               LOG_TARGET_ERROR(target,
+                                       "Error queuing cache 
writeback/invaldate instruction(s): %d",
+                                       res);
+                       res = xtensa_core_status_check(target);
                        if (res != ERROR_OK)
                                LOG_TARGET_ERROR(target,
                                        "Error issuing cache 
writeback/invaldate instruction(s): %d",
@@ -2367,7 +2438,8 @@ int xtensa_poll(struct target *target)
 static int xtensa_update_instruction(struct target *target, target_addr_t 
address, uint32_t size, const uint8_t *buffer)
 {
        struct xtensa *xtensa = target_to_xtensa(target);
-       unsigned int issue_ihi = xtensa_is_icacheable(xtensa, address);
+       unsigned int issue_ihi = xtensa_is_icacheable(xtensa, address) &&
+                                                        
xtensa_region_ar_exec(target, address, address + size);
        unsigned int issue_dhwbi = xtensa_is_dcacheable(xtensa, address);
        uint32_t icache_line_size = issue_ihi ? 
xtensa->core_config->icache.line_size : UINT32_MAX;
        uint32_t dcache_line_size = issue_dhwbi ? 
xtensa->core_config->dcache.line_size : UINT32_MAX;
@@ -2385,7 +2457,8 @@ static int xtensa_update_instruction(struct target 
*target, target_addr_t addres
                /* Write start address to A3 and invalidate */
                xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, address);
                xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, 
XT_REG_A3));
-               LOG_TARGET_DEBUG(target, "DHWBI, IHI for address 
"TARGET_ADDR_FMT, address);
+               LOG_TARGET_DEBUG(target, "IHI %d, DHWBI %d for address " 
TARGET_ADDR_FMT,
+                       issue_ihi, issue_dhwbi, address);
                if (issue_dhwbi) {
                        xtensa_queue_exec_ins(xtensa, XT_INS_DHWBI(xtensa, 
XT_REG_A3, 0));
                        if (!same_dc_line) {

-- 

Reply via email to