diff options
| author | Nicholas Piggin <npiggin@gmail.com> | 2026-04-30 14:55:22 +1000 |
|---|---|---|
| committer | Anup Patel <anup@brainfault.org> | 2026-06-10 13:23:18 +0530 |
| commit | 8f1a6164f2b81fe08d67c09400d9f7b9019c58df (patch) | |
| tree | ba0e39551f1b63ec97230a5ffd76e1c08767dc8e /lib | |
| parent | e9797b5e574c87332679a30e542b519c93e650ca (diff) | |
| download | opensbi-8f1a6164f2b81fe08d67c09400d9f7b9019c58df.tar.gz opensbi-8f1a6164f2b81fe08d67c09400d9f7b9019c58df.zip | |
lib: sbi: Add PMP CSR read and write accessors
PMPCFG CSR access is non-trivial as it requires shifting and masking, it
makes PMP manipulation code simpler if this basic CSR read/write access is
abstracted away.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20260430045528.420437-6-npiggin@gmail.com
Signed-off-by: Anup Patel <anup@brainfault.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sbi/riscv_asm.c | 114 |
1 files changed, 58 insertions, 56 deletions
diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c index da1900e9..6c1f2344 100644 --- a/lib/sbi/riscv_asm.c +++ b/lib/sbi/riscv_asm.c @@ -273,14 +273,16 @@ void csr_write_num(int csr_num, unsigned long val) #undef switchcase_csr_write } -int pmp_disable(unsigned int n) +static int hart_pmp_read(pmp_t *pmp, unsigned int n) { - int pmpcfg_csr, pmpcfg_shift; - unsigned long cfgmask, pmpcfg; + int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr; + unsigned long cfgmask; + /* check parameters */ if (n >= PMP_COUNT) return SBI_EINVAL; + /* calculate PMP register and offset */ #if __riscv_xlen == 32 pmpcfg_csr = CSR_PMPCFG0 + (n >> 2); pmpcfg_shift = (n & 3) << 3; @@ -290,48 +292,24 @@ int pmp_disable(unsigned int n) #else # error "Unexpected __riscv_xlen" #endif + pmpaddr_csr = CSR_PMPADDR0 + n; - /* Clear the address matching bits to disable the pmp entry */ - cfgmask = ~(0xffUL << pmpcfg_shift); - pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask); - - csr_write_num(pmpcfg_csr, pmpcfg); + cfgmask = (0xffUL << pmpcfg_shift); + pmp->cfg = (csr_read_num(pmpcfg_csr) & cfgmask) >> pmpcfg_shift; + pmp->addr = csr_read_num(pmpaddr_csr); return SBI_OK; } -int is_pmp_entry_mapped(unsigned long entry) -{ - unsigned long prot; - unsigned long addr; - unsigned long log2len; - - if (pmp_get(entry, &prot, &addr, &log2len) != 0) - return false; - - /* If address matching bits are non-zero, the entry is enable */ - if (prot & PMP_A) - return true; - - return false; -} - -int pmp_set(unsigned int n, unsigned long prot, unsigned long addr, - unsigned long log2len) +static int hart_pmp_write(pmp_t *pmp, unsigned int n) { int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr; unsigned long cfgmask, pmpcfg; - pmp_t pmp; - int rc; /* check parameters */ if (n >= PMP_COUNT) return SBI_EINVAL; - rc = sbi_pmp_encode(&pmp, prot, addr, log2len); - if (rc) - return rc; - /* calculate PMP register and offset */ #if __riscv_xlen == 32 pmpcfg_csr = CSR_PMPCFG0 + (n >> 2); @@ -345,41 +323,65 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr, pmpaddr_csr = CSR_PMPADDR0 + n; /* write csrs */ - csr_write_num(pmpaddr_csr, pmp.addr); + csr_write_num(pmpaddr_csr, pmp->addr); cfgmask = ~(0xffUL << pmpcfg_shift); pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask); - pmpcfg |= (((unsigned long)pmp.cfg << pmpcfg_shift) & ~cfgmask); + pmpcfg |= (((unsigned long)pmp->cfg << pmpcfg_shift) & ~cfgmask); csr_write_num(pmpcfg_csr, pmpcfg); - return 0; + return SBI_OK; } -int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out, - unsigned long *log2len) +int pmp_disable(unsigned int n) { - int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr; - unsigned long cfgmask; pmp_t pmp; + int rc; - /* check parameters */ - if (n >= PMP_COUNT) - return SBI_EINVAL; + rc = hart_pmp_read(&pmp, n); + if (rc) + return rc; - /* calculate PMP register and offset */ -#if __riscv_xlen == 32 - pmpcfg_csr = CSR_PMPCFG0 + (n >> 2); - pmpcfg_shift = (n & 3) << 3; -#elif __riscv_xlen == 64 - pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1; - pmpcfg_shift = (n & 7) << 3; -#else -# error "Unexpected __riscv_xlen" -#endif - pmpaddr_csr = CSR_PMPADDR0 + n; + pmp.cfg = 0; - cfgmask = (0xffUL << pmpcfg_shift); - pmp.cfg = (csr_read_num(pmpcfg_csr) & cfgmask) >> pmpcfg_shift; - pmp.addr = csr_read_num(pmpaddr_csr); + return hart_pmp_write(&pmp, n); +} + +int is_pmp_entry_mapped(unsigned long entry) +{ + pmp_t pmp; + + if (hart_pmp_read(&pmp, entry) != SBI_OK) + return false; + + /* If address matching bits are non-zero, the entry is enable */ + if (pmp.cfg & PMP_A) + return true; + + return false; +} + +int pmp_set(unsigned int n, unsigned long prot, unsigned long addr, + unsigned long log2len) +{ + pmp_t pmp; + int rc; + + rc = sbi_pmp_encode(&pmp, prot, addr, log2len); + if (rc) + return rc; + + return hart_pmp_write(&pmp, n); +} + +int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out, + unsigned long *log2len) +{ + pmp_t pmp; + int rc; + + rc = hart_pmp_read(&pmp, n); + if (rc) + return rc; return sbi_pmp_decode(&pmp, prot_out, addr_out, log2len); } |
