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:
parent
6734304f8c
commit
7ccf6bf54c
|
@ -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__ */
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue