lib: sbi: Allow specifying mode in sbi_hart_pmp_check_addr() API

We extend sbi_hart_pmp_check_addr() API so that users can specify
privilege mode of the address for checking PMP access permissions.

To achieve this, we end-up converting "unsigned long *size" parameter
to "unsigned long *log2len" for pmp_get() implementation so that we
can deal with regions of "1UL << __riscv_xlen" size in a special case
in sbi_hart_pmp_check_addr() implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
Anup Patel 2020-09-07 15:50:33 +05:30 committed by Anup Patel
parent 6734304f8c
commit 7ccf6bf54c
5 changed files with 33 additions and 20 deletions

View File

@ -180,7 +180,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len); unsigned long log2len);
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out, int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size); unsigned long *log2len);
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */

View File

@ -42,7 +42,8 @@ int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
unsigned long *prot_out, unsigned long *addr_out, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size); unsigned long *size);
void sbi_hart_pmp_dump(struct sbi_scratch *scratch); void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr, int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
unsigned long daddr, unsigned long mode,
unsigned long attr); unsigned long attr);
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature); bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
void sbi_hart_get_features_str(struct sbi_scratch *scratch, void sbi_hart_get_features_str(struct sbi_scratch *scratch,

View File

@ -239,16 +239,16 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
} }
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out, int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size) unsigned long *log2len)
{ {
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr; int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg, prot; unsigned long cfgmask, pmpcfg, prot;
unsigned long t1, addr, log2len; unsigned long t1, addr, len;
/* check parameters */ /* check parameters */
if (n >= PMP_COUNT || !prot_out || !addr_out || !size) if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
return SBI_EINVAL; return SBI_EINVAL;
*prot_out = *addr_out = *size = 0; *prot_out = *addr_out = *log2len = 0;
/* calculate PMP register and offset */ /* calculate PMP register and offset */
#if __riscv_xlen == 32 #if __riscv_xlen == 32
@ -275,23 +275,21 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
addr = csr_read_num(pmpaddr_csr); addr = csr_read_num(pmpaddr_csr);
if (addr == -1UL) { if (addr == -1UL) {
addr = 0; addr = 0;
log2len = __riscv_xlen; len = __riscv_xlen;
} else { } else {
t1 = ctz(~addr); t1 = ctz(~addr);
addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT; addr = (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
log2len = (t1 + PMP_SHIFT + 1); len = (t1 + PMP_SHIFT + 1);
} }
} else { } else {
addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT; addr = csr_read_num(pmpaddr_csr) << PMP_SHIFT;
log2len = PMP_SHIFT; len = PMP_SHIFT;
} }
/* return details */ /* return details */
*prot_out = prot; *prot_out = prot;
*addr_out = addr; *addr_out = addr;
*log2len = len;
if (log2len < __riscv_xlen)
*size = (1UL << log2len);
return 0; return 0;
} }

View File

@ -156,22 +156,31 @@ int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
unsigned long *prot_out, unsigned long *addr_out, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *size) unsigned long *size)
{ {
int err;
unsigned long log2size;
if (sbi_hart_pmp_count(scratch) <= n) if (sbi_hart_pmp_count(scratch) <= n)
return SBI_EINVAL; return SBI_EINVAL;
return pmp_get(n, prot_out, addr_out, size); err = pmp_get(n, prot_out, addr_out, &log2size);
if (err)
return err;
*size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
return 0;
} }
void sbi_hart_pmp_dump(struct sbi_scratch *scratch) void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
{ {
unsigned long prot, addr, size; unsigned long prot, addr, size, log2size;
unsigned int i, pmp_count; unsigned int i, pmp_count;
pmp_count = sbi_hart_pmp_count(scratch); pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) { for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &addr, &size); pmp_get(i, &prot, &addr, &log2size);
if (!(prot & PMP_A)) if (!(prot & PMP_A))
continue; continue;
size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
#if __riscv_xlen == 32 #if __riscv_xlen == 32
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A", sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#else #else
@ -190,18 +199,23 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
} }
} }
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr, int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch,
unsigned long addr, unsigned long mode,
unsigned long attr) unsigned long attr)
{ {
unsigned long prot, size, tempaddr; unsigned long prot, size, log2size, tempaddr;
unsigned int i, pmp_count; unsigned int i, pmp_count;
pmp_count = sbi_hart_pmp_count(scratch); pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) { for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &tempaddr, &size); pmp_get(i, &prot, &tempaddr, &log2size);
if (!(prot & PMP_A)) if (!(prot & PMP_A))
continue; continue;
if (tempaddr <= addr && addr <= tempaddr + size) if (mode == PRV_M && !(prot & PMP_L))
continue;
size = 1UL << log2size;
if ((log2size >= __riscv_xlen) ||
((tempaddr <= addr && addr <= tempaddr + size)))
if (!(prot & attr)) if (!(prot & attr))
return SBI_EINVALID_ADDR; return SBI_EINVALID_ADDR;
} }

View File

@ -231,7 +231,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
if (hstate != SBI_HART_STOPPED) if (hstate != SBI_HART_STOPPED)
return SBI_EINVAL; return SBI_EINVAL;
rc = sbi_hart_pmp_check_addr(scratch, saddr, PMP_X); rc = sbi_hart_pmp_check_addr(scratch, saddr, smode, PMP_X);
if (rc) if (rc)
return rc; return rc;
//TODO: We also need to check saddr for valid physical address as well. //TODO: We also need to check saddr for valid physical address as well.