From d1d6034d170ae2ee9330228eba66dd90c157756a Mon Sep 17 00:00:00 2001 From: sinceforYy <1017657683@qq.com> Date: Thu, 6 Feb 2025 10:59:53 +0800 Subject: [PATCH] feat(PMA, CSR): support PMA Custom CSR configurable * We implements 16 PMA entries, all PMA CSR fields are WARL and may be read-only zero. * That means that accessing CSRs of implemented PMA entries should not rasie illegal instruction exception. * We adds initial configuration of PMA custom CSRs, and adds CSR reading and writing of PMA custom registers. * NOTE: This patch adds some key config of PMA in Kconfig. --- configs/riscv64-dual-xs-ref-debug_defconfig | 5 + configs/riscv64-dual-xs-ref_defconfig | 5 + configs/riscv64-xs-ref-debug_defconfig | 5 + configs/riscv64-xs-ref_defconfig | 5 + configs/riscv64-xs_defconfig | 5 + src/isa/riscv64/Kconfig | 53 ++++++ src/isa/riscv64/init.c | 5 + src/isa/riscv64/local-include/csr.h | 41 +++++ src/isa/riscv64/local-include/reg.h | 16 ++ src/isa/riscv64/reg.c | 10 + src/isa/riscv64/system/priv.c | 191 +++++++++++++++++++- 11 files changed, 338 insertions(+), 3 deletions(-) diff --git a/configs/riscv64-dual-xs-ref-debug_defconfig b/configs/riscv64-dual-xs-ref-debug_defconfig index 1288718a3..29f634724 100644 --- a/configs/riscv64-dual-xs-ref-debug_defconfig +++ b/configs/riscv64-dual-xs-ref-debug_defconfig @@ -62,6 +62,11 @@ CONFIG_RV_PMP_NUM=16 CONFIG_RV_PMP_ACTIVE_NUM=16 CONFIG_PMP_GRANULARITY=12 CONFIG_RV_PMP_CHECK=y +# CONFIG_RV_PMA_ENTRY_0 is not set +CONFIG_RV_PMA_ENTRY_16=y +CONFIG_RV_PMA_CSR=y +CONFIG_RV_PMA_NUM=16 +CONFIG_RV_PMA_ACTIVE_NUM=16 CONFIG_RV_SVINVAL=y # CONFIG_RV_SV39 is not set CONFIG_RV_SV48=y diff --git a/configs/riscv64-dual-xs-ref_defconfig b/configs/riscv64-dual-xs-ref_defconfig index 51e4c8015..be15c071e 100644 --- a/configs/riscv64-dual-xs-ref_defconfig +++ b/configs/riscv64-dual-xs-ref_defconfig @@ -63,6 +63,11 @@ CONFIG_RV_PMP_NUM=16 CONFIG_RV_PMP_ACTIVE_NUM=16 CONFIG_PMP_GRANULARITY=12 CONFIG_RV_PMP_CHECK=y +# CONFIG_RV_PMA_ENTRY_0 is not set +CONFIG_RV_PMA_ENTRY_16=y +CONFIG_RV_PMA_CSR=y +CONFIG_RV_PMA_NUM=16 +CONFIG_RV_PMA_ACTIVE_NUM=16 CONFIG_RV_SVINVAL=y # CONFIG_RV_SV39 is not set CONFIG_RV_SV48=y diff --git a/configs/riscv64-xs-ref-debug_defconfig b/configs/riscv64-xs-ref-debug_defconfig index 89112e5dd..edd65aae4 100644 --- a/configs/riscv64-xs-ref-debug_defconfig +++ b/configs/riscv64-xs-ref-debug_defconfig @@ -62,6 +62,11 @@ CONFIG_RV_PMP_NUM=16 CONFIG_RV_PMP_ACTIVE_NUM=16 CONFIG_PMP_GRANULARITY=12 CONFIG_RV_PMP_CHECK=y +# CONFIG_RV_PMA_ENTRY_0 is not set +CONFIG_RV_PMA_ENTRY_16=y +CONFIG_RV_PMA_CSR=y +CONFIG_RV_PMA_NUM=16 +CONFIG_RV_PMA_ACTIVE_NUM=16 CONFIG_RV_SVINVAL=y # CONFIG_RV_SV39 is not set CONFIG_RV_SV48=y diff --git a/configs/riscv64-xs-ref_defconfig b/configs/riscv64-xs-ref_defconfig index 274dfccb3..1ae6e3c94 100644 --- a/configs/riscv64-xs-ref_defconfig +++ b/configs/riscv64-xs-ref_defconfig @@ -62,6 +62,11 @@ CONFIG_RV_PMP_NUM=16 CONFIG_RV_PMP_ACTIVE_NUM=16 CONFIG_PMP_GRANULARITY=12 CONFIG_RV_PMP_CHECK=y +# CONFIG_RV_PMA_ENTRY_0 is not set +CONFIG_RV_PMA_ENTRY_16=y +CONFIG_RV_PMA_CSR=y +CONFIG_RV_PMA_NUM=16 +CONFIG_RV_PMA_ACTIVE_NUM=16 CONFIG_RV_SVINVAL=y # CONFIG_RV_SV39 is not set CONFIG_RV_SV48=y diff --git a/configs/riscv64-xs_defconfig b/configs/riscv64-xs_defconfig index 3eb6419d8..04a2c8b59 100644 --- a/configs/riscv64-xs_defconfig +++ b/configs/riscv64-xs_defconfig @@ -58,6 +58,11 @@ CONFIG_RV_PMP_CSR=y CONFIG_RV_PMP_NUM=16 CONFIG_RV_PMP_ACTIVE_NUM=16 CONFIG_PMP_GRANULARITY=12 +# CONFIG_RV_PMA_ENTRY_0 is not set +CONFIG_RV_PMA_ENTRY_16=y +CONFIG_RV_PMA_CSR=y +CONFIG_RV_PMA_NUM=16 +CONFIG_RV_PMA_ACTIVE_NUM=16 # # PMP Check Disabled when enabling PERF_OPT diff --git a/src/isa/riscv64/Kconfig b/src/isa/riscv64/Kconfig index f72a67f09..282bed070 100644 --- a/src/isa/riscv64/Kconfig +++ b/src/isa/riscv64/Kconfig @@ -360,6 +360,59 @@ config RV_PMP_CHECK bool "Enable PMP Check" default y +choice + prompt "Number of implement PMA entries" + default RV_PMA_ENTRY_16 + help + This config decided the number of PMA entries are implemented. An + attempt to access unimplemented PMA CSRs raises illegal-instruction + exception. + + We supported up to 16 PMA entries. + +config RV_PMA_ENTRY_0 + bool "0 PMA entry (Disabled)" + help + An attempt to access any pmacfg or pmaaddr CSRs raises an illegal- + instruction exception. + +config RV_PMA_ENTRY_16 + bool "16 PMA entries" + help + Only pmacfg0, pmacfg2, pmaaddr0 - pmaaddr15 are accessible. An attempt + to access pmacfg4 - pmacfg14, pmaaddr16 - pmaaddr63 raises an illegal- + instruction exception. + +endchoice + +config RV_PMA_CSR + depends on RV_PMP_CSR + bool + default n if RV_PMA_ENTRY_0 + default y + +config RV_PMA_NUM + int + default 0 if RV_PMA_ENTRY_0 + default 16 if RV_PMA_ENTRY_16 + +config RV_PMA_ACTIVE_NUM + depends on !RV_PMA_ENTRY_0 + int "Number of active PMA entries" + range 0 16 if RV_PMA_ENTRY_16 + default 16 if RV_PMA_ENTRY_16 + help + This config decided the number of PMA entries are active. Implemented but + inactive PMA entries are read-only zero. + + Any number of PMA entries may be read-only zero. NEMU assumes that the + lowest-numbered PMA entries are active, and the other are read-only zero. + + For example, if + Number of implemented PMA entries = 16, + then + pmaaddr0 ~ pmaaddr15 are ready for use. + config RV_SVINVAL bool "Enable VM Extension Svinval" default y diff --git a/src/isa/riscv64/init.c b/src/isa/riscv64/init.c index 4eda4c52e..f05edfa7d 100644 --- a/src/isa/riscv64/init.c +++ b/src/isa/riscv64/init.c @@ -27,6 +27,7 @@ void init_trigger(); void init_iprio(); #endif void init_custom_csr(); +void init_pma(); void init_riscv_timer(); void init_device(); @@ -123,6 +124,10 @@ void init_isa() { pmpcfg14->val = 0; #endif // CONFIG_RV_PMP_ENTRY_64 +#ifdef CONFIG_RV_PMA_ENTRY_16 + init_pma(); +#endif // CONFIG_RV_PMA_ENRTY_16 + #define ext(e) (1 << ((e) - 'a')) misa->extensions = ext('i') | ext('m') | ext('a') | ext('c') | ext('s') | ext('u'); #ifndef CONFIG_FPU_NONE diff --git a/src/isa/riscv64/local-include/csr.h b/src/isa/riscv64/local-include/csr.h index 86e6ee94d..59ae9182b 100644 --- a/src/isa/riscv64/local-include/csr.h +++ b/src/isa/riscv64/local-include/csr.h @@ -365,6 +365,19 @@ f(pmpaddr60 , 0x3EC) f(pmpaddr61 , 0x3ED) f(pmpaddr62 , 0x3EE) f(pmpaddr63 , 0x3EF) #endif // CONFIG_RV_PMP_ENTRY_64 +/** Machine Memory Attributes (PMA) **/ +#ifdef CONFIG_RV_PMA_ENTRY_0 + #define CSRS_M_MEMORY_ATTRIBUTE(f) +#endif // CONFIG_RV_PMA_ENTRY_0 +#ifdef CONFIG_RV_PMA_ENTRY_16 + #define CSRS_M_MEMORY_ATTRIBUTE(f) \ + f(pmacfg0 , 0x7C0) f(pmacfg2 , 0x7C2) \ + f(pmaaddr0 , 0x7C8) f(pmaaddr1 , 0x7C9) f(pmaaddr2 , 0x7CA) f(pmaaddr3 , 0x7CB) \ + f(pmaaddr4 , 0x7CC) f(pmaaddr5 , 0x7CD) f(pmaaddr6 , 0x7CE) f(pmaaddr7 , 0x7CF) \ + f(pmaaddr8 , 0x7D0) f(pmaaddr9 , 0x7D1) f(pmaaddr10 , 0x7D2) f(pmaaddr11 , 0x7D3) \ + f(pmaaddr12 , 0x7D4) f(pmaaddr13 , 0x7D5) f(pmaaddr14 , 0x7D6) f(pmaaddr15 , 0x7D7) +#endif // CONFIG_RV_PMA_ENTRY_16 + /** Machine State Enable Registers **/ #ifdef CONFIG_RV_SMSTATEEN #define CSRS_M_STATE_ENABLE(f) \ @@ -475,6 +488,7 @@ CSRS_M_TRAP_HANDLING(f) \ CSRS_M_CONFIGURATION(f) \ CSRS_M_MEMORY_PROTECTION(f) \ + CSRS_M_MEMORY_ATTRIBUTE(f) \ CSRS_M_STATE_ENABLE(f) \ CSRS_M_NON_MASKABLE_INTERRUPT_HANDLING(f) \ CSRS_M_COUNTER_TIMERS(f) \ @@ -789,6 +803,10 @@ CSR_STRUCT_END(mtinst) CSR_STRUCT_DUMMY_LIST(CSRS_M_MEMORY_PROTECTION) +/** Physical Memory Attributes CSRs */ + +CSR_STRUCT_DUMMY_LIST(CSRS_M_MEMORY_ATTRIBUTE) + /** Debug Mode Registers (Core Debug Registers) **/ #ifdef CONFIG_RV_SDEXT @@ -1525,6 +1543,25 @@ MAP(CSRS, CSRS_DECL) #define CSR_PMPCFG_MAX_NUM 16 #define CSR_PMPADDR_MAX_NUM 64 +/** Machine Memory Attributes (PMA) **/ +#define PMA_R PMP_R +#define PMA_W PMP_W +#define PMA_X PMP_X +#define PMA_A PMP_A +#define PMA_T 0x20 +#define PMA_C 0x40 +#define PMA_L PMP_L +#define PMA_SHIFT PMP_SHIFT + +#define PMA_TOR PMP_TOR +#define PMA_NA4 PMP_NA4 +#define PMA_NAPOT PMP_NAPOT + +#define CSR_PMACFG_BASE 0x7c0 +#define CSR_PMAADDR_BASE 0x7c8 +#define CSR_PMACFG_MAX_NUM 2 +#define CSR_PMAADDR_MAX_NUM 16 + /** Vector **/ #define IDXVSTART 0x008 #define IDXVXSAT 0x009 @@ -1633,4 +1670,8 @@ uint8_t pmpcfg_from_index(int idx); word_t pmpaddr_from_index(int idx); word_t pmp_tor_mask(); +/** PMA */ +uint8_t pmacfg_from_index(int idx); +word_t pmaaddr_from_index(int idx); + #endif // __CSR_H__ diff --git a/src/isa/riscv64/local-include/reg.h b/src/isa/riscv64/local-include/reg.h index 016b04a31..a6ff01dcf 100644 --- a/src/isa/riscv64/local-include/reg.h +++ b/src/isa/riscv64/local-include/reg.h @@ -41,4 +41,20 @@ static inline const char* fpreg_name(int index, int width){ return fpregsl[index]; } +typedef struct { + uint64_t base_addr; + uint64_t range; + uint64_t l; + uint64_t c; + uint64_t t; // atomic + uint64_t a; + uint64_t x; + uint64_t w; + uint64_t r; +} PMAConfig; + +typedef struct PMAConfigModule { + PMAConfig pmaconfigs[CONFIG_RV_PMA_ACTIVE_NUM]; +} PMAConfigModule; + #endif diff --git a/src/isa/riscv64/reg.c b/src/isa/riscv64/reg.c index 113119dd1..b2d31e361 100644 --- a/src/isa/riscv64/reg.c +++ b/src/isa/riscv64/reg.c @@ -228,6 +228,16 @@ void isa_reg_display() { #endif #endif // CONFIG_RV_PMP_CSR + #ifdef CONFIG_RV_PMA_CSR + DISPLAY_HR("PMA CSRs"); + printf("pma: %d entries active, details:\n", CONFIG_RV_PMA_ACTIVE_NUM); + for (int i = 0; i < CONFIG_RV_PMA_NUM; i++) { + printf("%2d: cfg:0x%02x addr:0x%016lx", i, pmacfg_from_index(i), pmaaddr_from_index(i)); + if (i % 2 == 1) printf("\n"); + else printf("|"); + } + #endif // CONFIG_RV_PMA_CSR + #ifdef CONFIG_RVV //vector register DISPLAY_HR("Vector Registers"); diff --git a/src/isa/riscv64/system/priv.c b/src/isa/riscv64/system/priv.c index 052bdfad8..8c6ce5a51 100644 --- a/src/isa/riscv64/system/priv.c +++ b/src/isa/riscv64/system/priv.c @@ -24,6 +24,7 @@ #include #include #include +#include int update_mmu_state(); uint64_t get_htime(); @@ -65,8 +66,6 @@ bool access_table[4][4] = { {T, T, T, T} }; #endif -#undef T -#undef F #define CSRS_DEF(name, addr) \ concat(name, _t)* const name = (concat(name, _t) *)&csr_array[addr]; @@ -180,6 +179,80 @@ void init_custom_csr() { mflushpwr->l2flushed = 0; } +void init_pma() { + unsigned long long pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM][9] = { + // base_addr, range, l, c, t, a, x, w, r + {0, 0x1000000000000ULL, F, F, F, 3, F, F, F}, + {0x80000000000ULL, 0, F, T, T, 1, T, T, T}, + {0x80000000ULL, 0, F, F, F, 1, F, T, T}, + {0x3A000000ULL, 0, F, F, F, 1, F, F, F}, + {0x38022000ULL, 0, F, F, F, 1, F, T, T}, + {0x38021000ULL, 0, F, F, F, 1, T, T, T}, + {0x38020000ULL, 0, F, F, F, 1, F, T, T}, + {0x30050000ULL, 0, F, F, F, 1, F, T, T}, + {0x30010000ULL, 0, F, F, F, 1, F, T, T}, + {0x20000000ULL, 0, F, F, F, 1, T, T, T}, + {0x10000000ULL, 0, F, F, F, 1, F, T, T}, + {0}, + {0}, + {0}, + {0}, + {0}, + }; + + PMAConfigModule* pmaconfigs = (PMAConfigModule *)malloc(sizeof (PMAConfigModule)); + for (int i = 0; i < CONFIG_RV_PMA_ACTIVE_NUM; i++) { + pmaconfigs->pmaconfigs[i].base_addr = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][0]; + pmaconfigs->pmaconfigs[i].range = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][1]; + pmaconfigs->pmaconfigs[i].l = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][2]; + pmaconfigs->pmaconfigs[i].c = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][3]; + pmaconfigs->pmaconfigs[i].t = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][4]; + pmaconfigs->pmaconfigs[i].a = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][5]; + pmaconfigs->pmaconfigs[i].x = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][6]; + pmaconfigs->pmaconfigs[i].w = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][7]; + pmaconfigs->pmaconfigs[i].r = pmaConfigInit[CONFIG_RV_PMA_ACTIVE_NUM - 1 - i][8]; + } + + // set pmacfg init value + for (int i = 0; i < CONFIG_RV_PMA_ACTIVE_NUM; i++) { + int pmaCfgIdx = CSR_PMACFG_BASE + i/8*2; + uint64_t pmaCfgOld = *(uint64_t *)&csr_array[pmaCfgIdx]; + + pmaCfgOld |= ((pmaconfigs->pmaconfigs[i].l & 0x1) << (8*(i%8) + 7)) | + ((pmaconfigs->pmaconfigs[i].c & 0x1) << (8*(i%8) + 6)) | + ((pmaconfigs->pmaconfigs[i].t & 0x1) << (8*(i%8) + 5)) | + ((pmaconfigs->pmaconfigs[i].a & 0x3) << (8*(i%8) + 3)) | + ((pmaconfigs->pmaconfigs[i].x & 0x1) << (8*(i%8) + 2)) | + ((pmaconfigs->pmaconfigs[i].w & 0x1) << (8*(i%8) + 1)) | + ((pmaconfigs->pmaconfigs[i].r & 0x1) << (8*(i%8))); + + word_t *pmaCfg = &csr_array[pmaCfgIdx]; + *pmaCfg = pmaCfgOld; + } + + // set pmaaddr init value + for (int i = 0; i < CONFIG_RV_PMA_ACTIVE_NUM; i++) { + int pmaAddrIdx = CSR_PMAADDR_BASE + i%8; + uint64_t addr = 0; + uint64_t baseAddr = pmaconfigs->pmaconfigs[i].base_addr; + uint64_t range = pmaconfigs->pmaconfigs[i].range; + uint64_t a = pmaconfigs->pmaconfigs[i].a & 0x3; + if (a < 2) { + addr = baseAddr >> 2; + } else { + int platformGrainBytes = 1 << (int)ceil(log2(4*1024)); // 4KB, a normal page + Assert(baseAddr % platformGrainBytes == 0, "base=%lx", baseAddr); + Assert(range % platformGrainBytes == 0, "range=%lx", range); + addr = (baseAddr + ((range >> 1) - 1)) >> PMA_SHIFT; + } + + word_t *pmaCfg = &csr_array[pmaAddrIdx]; + *pmaCfg = addr; + } +} +#undef T +#undef F + // check s/h/mcounteren for counters, throw exception if counter is not enabled. // also check h/mcounteren h/menvcfg for sstc static inline bool csr_counter_enable_check(uint32_t addr) { @@ -688,6 +761,26 @@ word_t inline pmp_tor_mask() { } #endif // CONFIG_RV_PMP_CSR +#ifdef CONFIG_RV_PMA_CSR +// get 8-bit config of one PMA entries by index. +uint8_t pmacfg_from_index(int idx) { + int xlen = 64; + // Configuration register of one entry is 8-bit. + int bits_per_cfg = 8; + // For RV64, one pmacfg CSR contains configuration of 8 entries (64 / 8 = 8). + int cfgs_per_csr = xlen / bits_per_cfg; + // For RV64, only 8 even-numbered pmacfg CSRs hold the configuration. + int pmacfg_csr_addr = CSR_PMACFG_BASE + idx / cfgs_per_csr * 2; + + uint8_t *cfg_reg = (uint8_t *)&csr_array[pmacfg_csr_addr]; + return *(cfg_reg + (idx % cfgs_per_csr)); +} + +word_t pmaaddr_from_index(int idx) { + return csr_array[CSR_PMAADDR_BASE + idx]; +} +#endif // CONFIG_RV_PMA_CSR + #ifndef CONFIG_FPU_NONE static inline bool require_fs() { if ((mstatus->val & MSTATUS_WMASK_FS) != 0) { @@ -1589,6 +1682,32 @@ static word_t csr_read(uint32_t csrid) { } #endif // CONFIG_RV_PMP_CSR +#ifdef CONFIG_RV_PMA_CSR + case CSR_PMAADDR_BASE ... CSR_PMAADDR_BASE+CSR_PMAADDR_MAX_NUM-1: + { + int idx = (src - &csr_array[CSR_PMAADDR_BASE]); + if (idx >= CONFIG_RV_PMA_ACTIVE_NUM) { + return 0; + } + + uint8_t cfg = pmacfg_from_index(idx); +#ifdef CONFIG_SHARE + if (dynamic_config.debug_difftest) { + fprintf(stderr, "[NEMU] pma addr read %d : 0x%016lx\n", idx, + (cfg & PMA_A) >= PMA_NAPOT ? *src | (~pmp_tor_mask() >> 1) : *src & pmp_tor_mask()); + } +#endif // CONFIG_SHARE + if ((cfg & PMA_A) >= PMA_NAPOT) + return *src | (~pmp_tor_mask() >> 1); + else + return *src & pmp_tor_mask(); + + // No need to handle read pmacfg specifically, because + // - pmacfg CSRs are all initialized in init_pma(). + // - writing to inactive pmacfg CSRs is handled. + } +#endif // CONFIG_RV_PMA_CSR + #ifdef CONFIG_RV_SMRNMI case CSR_MNEPC: return mnepc->val & (~0x1UL) ; case CSR_MNSTATUS: return mnstatus->val & MNSTATUS_MASK; @@ -2104,6 +2223,7 @@ static void csr_write(uint32_t csrid, word_t src) { } case CSR_PMPADDR_BASE ... CSR_PMPADDR_BASE+CSR_PMPADDR_MAX_NUM-1: + { Logtr("Writing pmp addr"); int idx = dest - &csr_array[CSR_PMPADDR_BASE]; @@ -2127,9 +2247,74 @@ static void csr_write(uint32_t csrid, word_t src) { #endif // CONFIG_SHARE mmu_tlb_flush(0); break; - + } #endif // CONFIG_RV_PMP_CSR +#ifdef CONFIG_RV_PMA_CSR + case CSR_PMACFG_BASE ... CSR_PMACFG_BASE+CSR_PMACFG_MAX_NUM-1: + { + // Logtr("Writing pma config"); + + int idx_base = (dest - &csr_array[CSR_PMACFG_BASE]) * 4; + + int xlen = 64; + word_t cfg_data = 0; + for (int i = 0; i < xlen / 8; i++) { + if (idx_base + i >= CONFIG_RV_PMA_ACTIVE_NUM) { + break; + } + word_t oldCfg = pmacfg_from_index(idx_base + i); + + word_t cfg = ((src >> (i*8)) & 0xff); + if ((oldCfg & PMA_L) == 0) { + cfg &= ~PMA_W | ((cfg & PMA_R) ? PMA_W : 0); + if (CONFIG_PMP_GRANULARITY != PMA_SHIFT && (cfg & PMA_A) == PMA_NA4) + cfg |= PMA_NAPOT; + cfg_data |= (cfg << (i*8)); + } else { + cfg_data |= (oldCfg << (i*8)); + } + } +#ifdef CONFIG_SHARE + if (dynamic_config.debug_difftest) { + int idx = dest - &csr_array[CSR_PMACFG_BASE]; + Logtr("[NEMU] write pmacfg%d to %016lx\n", idx, cfg_data); + } +#endif // CONFIG_SHARE + + *dest = cfg_data; + + mmu_tlb_flush(0); + break; + } + + case CSR_PMAADDR_BASE ... CSR_PMAADDR_BASE+CSR_PMAADDR_MAX_NUM-1: + { + Logtr("Writing pma addr"); + + int idx = dest - &csr_array[CSR_PMAADDR_BASE]; + if (idx >= CONFIG_RV_PMA_ACTIVE_NUM) { + return; + } + + word_t cfg = pmacfg_from_index(idx); + bool locked = cfg & PMA_L; + // Note that the last pma cfg do not have next_locked or next_tor + bool next_locked = idx < (CONFIG_RV_PMA_ACTIVE_NUM - 1) && (pmacfg_from_index(idx+1) & PMA_L); + bool next_tor = idx < (CONFIG_RV_PMA_ACTIVE_NUM - 1) && (pmacfg_from_index(idx+1) & PMA_A) == PMA_TOR; + if (idx < CONFIG_RV_PMA_ACTIVE_NUM && !locked && !(next_locked && next_tor)) { + *dest = src & (((word_t)1 << (CONFIG_PADDRBITS - PMA_SHIFT)) - 1); + } +#ifdef CONFIG_SHARE + if (dynamic_config.debug_difftest) { + fprintf(stderr, "[NEMU] write pma addr%d to %016lx\n", idx, *dest); + } +#endif // CONFIG_SHARE + mmu_tlb_flush(0); + break; + } +#endif // CONFIG_RV_PMA_CSR + #ifdef CONFIG_RV_SMRNMI case CSR_MNEPC: *dest = src & (~0x1UL); break; case CSR_MNSTATUS: