forked from Mirrors/opensbi
lib: sbi: Add sbi_domain_check_addr_range() function
We add sbi_domain_check_addr_range() helper function to check whether a given address range is accessible under a particular domain. Signed-off-by: Anup Patel <apatel@ventanamicro.com> Reviewed-by: Atish Patra <atishp@rivosinc.com> Reviewed-by: Xiang W <wxjstz@126.com> Reviewed-by: Bin Meng <bmeng@tinylab.org> Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
This commit is contained in:
@@ -196,6 +196,21 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
|||||||
unsigned long addr, unsigned long mode,
|
unsigned long addr, unsigned long mode,
|
||||||
unsigned long access_flags);
|
unsigned long access_flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether we can access specified address range for given mode and
|
||||||
|
* memory region flags under a domain
|
||||||
|
* @param dom pointer to domain
|
||||||
|
* @param addr the start of the address range to be checked
|
||||||
|
* @param size the size of the address range to be checked
|
||||||
|
* @param mode the privilege mode of access
|
||||||
|
* @param access_flags bitmask of domain access types (enum sbi_domain_access)
|
||||||
|
* @return TRUE if access allowed otherwise FALSE
|
||||||
|
*/
|
||||||
|
bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
|
||||||
|
unsigned long addr, unsigned long size,
|
||||||
|
unsigned long mode,
|
||||||
|
unsigned long access_flags);
|
||||||
|
|
||||||
/** Dump domain details on the console */
|
/** Dump domain details on the console */
|
||||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
|
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix);
|
||||||
|
|
||||||
|
@@ -212,6 +212,44 @@ static bool is_region_before(const struct sbi_domain_memregion *regA,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct sbi_domain_memregion *find_region(
|
||||||
|
const struct sbi_domain *dom,
|
||||||
|
unsigned long addr)
|
||||||
|
{
|
||||||
|
unsigned long rstart, rend;
|
||||||
|
struct sbi_domain_memregion *reg;
|
||||||
|
|
||||||
|
sbi_domain_for_each_memregion(dom, reg) {
|
||||||
|
rstart = reg->base;
|
||||||
|
rend = (reg->order < __riscv_xlen) ?
|
||||||
|
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||||
|
if (rstart <= addr && addr <= rend)
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sbi_domain_memregion *find_next_subset_region(
|
||||||
|
const struct sbi_domain *dom,
|
||||||
|
const struct sbi_domain_memregion *reg,
|
||||||
|
unsigned long addr)
|
||||||
|
{
|
||||||
|
struct sbi_domain_memregion *sreg, *ret = NULL;
|
||||||
|
|
||||||
|
sbi_domain_for_each_memregion(dom, sreg) {
|
||||||
|
if (sreg == reg || (sreg->base <= addr) ||
|
||||||
|
!is_region_subset(sreg, reg))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ret || (sreg->base < ret->base) ||
|
||||||
|
((sreg->base == ret->base) && (sreg->order < ret->order)))
|
||||||
|
ret = sreg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int sanitize_domain(const struct sbi_platform *plat,
|
static int sanitize_domain(const struct sbi_platform *plat,
|
||||||
struct sbi_domain *dom)
|
struct sbi_domain *dom)
|
||||||
{
|
{
|
||||||
@@ -320,6 +358,37 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sbi_domain_check_addr_range(const struct sbi_domain *dom,
|
||||||
|
unsigned long addr, unsigned long size,
|
||||||
|
unsigned long mode,
|
||||||
|
unsigned long access_flags)
|
||||||
|
{
|
||||||
|
unsigned long max = addr + size;
|
||||||
|
const struct sbi_domain_memregion *reg, *sreg;
|
||||||
|
|
||||||
|
if (!dom)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (addr < max) {
|
||||||
|
reg = find_region(dom, addr);
|
||||||
|
if (!reg)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!sbi_domain_check_addr(dom, addr, mode, access_flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sreg = find_next_subset_region(dom, reg, addr);
|
||||||
|
if (sreg)
|
||||||
|
addr = sreg->base;
|
||||||
|
else if (reg->order < __riscv_xlen)
|
||||||
|
addr = reg->base + (1UL << reg->order);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
||||||
{
|
{
|
||||||
u32 i, k;
|
u32 i, k;
|
||||||
|
Reference in New Issue
Block a user