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

@@ -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 *size)
{
int err;
unsigned long log2size;
if (sbi_hart_pmp_count(scratch) <= n)
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)
{
unsigned long prot, addr, size;
unsigned long prot, addr, size, log2size;
unsigned int i, pmp_count;
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &addr, &size);
pmp_get(i, &prot, &addr, &log2size);
if (!(prot & PMP_A))
continue;
size = (log2size < __riscv_xlen) ? 1UL << log2size : 0;
#if __riscv_xlen == 32
sbi_printf("PMP%d : 0x%08lx-0x%08lx (A",
#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 prot, size, tempaddr;
unsigned long prot, size, log2size, tempaddr;
unsigned int i, pmp_count;
pmp_count = sbi_hart_pmp_count(scratch);
for (i = 0; i < pmp_count; i++) {
pmp_get(i, &prot, &tempaddr, &size);
pmp_get(i, &prot, &tempaddr, &log2size);
if (!(prot & PMP_A))
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))
return SBI_EINVALID_ADDR;
}