From: openocd-gerrit <ope...@us...> - 2024-05-11 11:56:24
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via 2c8376b79d104a855bd3a559e59edf330309bcad (commit) from 22ddf62d759b10a89e9c4c3f3929a66c9d72572d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2c8376b79d104a855bd3a559e59edf330309bcad Author: Ian Thompson <ia...@ca...> 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...@ca...> Reviewed-on: https://review.openocd.org/c/openocd/+/8080 Reviewed-by: Erhan Kurubas <erh...@es...> Tested-by: jenkins Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index fb7748aa2..f7c82efed 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) { ----------------------------------------------------------------------- Summary of changes: src/target/xtensa/xtensa.c | 89 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 8 deletions(-) hooks/post-receive -- Main OpenOCD repository |