Function p2m_lookup() is responsible for looking up an entry in p2m table. In MPU system, We check whether mapping exists. If it does, we get the details of the guest MPU memory region in domain P2M table(p2m->root) through p2m_get_mpu_region()
Signed-off-by: Penny Zheng <penny.zh...@arm.com> Signed-off-by: Wei Chen <wei.c...@arm.com> --- v3: - new commit --- xen/arch/arm/include/asm/mpu/p2m.h | 18 ++++++++ xen/arch/arm/include/asm/p2m.h | 2 + xen/arch/arm/mpu/p2m.c | 73 ++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 xen/arch/arm/include/asm/mpu/p2m.h diff --git a/xen/arch/arm/include/asm/mpu/p2m.h b/xen/arch/arm/include/asm/mpu/p2m.h new file mode 100644 index 0000000000..bdb33148e3 --- /dev/null +++ b/xen/arch/arm/include/asm/mpu/p2m.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _XEN_P2M_MPU_H +#define _XEN_P2M_MPU_H + +static inline bool region_is_p2m_valid(pr_t *pr) +{ + return (pr->prbar.reg.p2m_type != p2m_invalid); +} + +#endif /* _XEN_P2M_MPU_H */ +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index 68837b6df7..395bfd4f69 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -188,6 +188,8 @@ typedef enum { #ifdef CONFIG_HAS_MMU #include <asm/mmu/p2m.h> +#else +#include <asm/mpu/p2m.h> #endif static inline bool arch_acquire_resource_check(struct domain *d) diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c index 4838d5b625..d403479229 100644 --- a/xen/arch/arm/mpu/p2m.c +++ b/xen/arch/arm/mpu/p2m.c @@ -338,6 +338,79 @@ int p2m_set_entry(struct p2m_domain *p2m, gfn_t sgfn, unsigned long nr, return __p2m_set_entry(p2m, sgfn, nr, smfn, t, a); } +/* + * Get the details of guest MPU memory region [gfn, gfn + nr_gfns). + * + * If it is mapped, the starting MFN will be returned and according + * p2m type will get filled up. + * If it is not mapped, INVALID_MFN will be returned. + */ +static mfn_t p2m_get_mpu_region(struct p2m_domain *p2m, gfn_t gfn, + unsigned long nr_gfns, p2m_type_t *t, + bool *valid) +{ + pr_t *table, *region = NULL; + p2m_type_t _t; + uint8_t idx = INVALID_REGION_IDX; + gfn_t egfn = gfn_add(gfn, nr_gfns); + + ASSERT(p2m_is_locked(p2m)); + + /* Allow t to be NULL. */ + t = t ? : &_t; + + *t = p2m_invalid; + + if ( valid ) + *valid = false; + + /* + * Check if the ending gfn is higher than the highest the p2m map + * currently holds, or the starting gfn lower than the lowest it holds + */ + if ( (gfn_x(egfn) > gfn_x(p2m->max_mapped_gfn)) || + (gfn_x(gfn) < gfn_x(p2m->lowest_mapped_gfn)) ) + return INVALID_MFN; + + table = (pr_t *)page_to_virt(p2m->root); + /* The table should always be non-NULL and is always present. */ + if ( !table ) + ASSERT_UNREACHABLE(); + + if ( is_gfns_mapped(p2m, gfn, nr_gfns, &idx) ) + return INVALID_MFN; + + region = &table[idx]; + if ( region_is_p2m_valid(region) ) + { + *t = region->prbar.reg.p2m_type; + + if ( valid ) + *valid = region_is_valid(region); + } + + /* Always GFN == MFN in MPU system. */ + return _mfn(gfn_x(gfn)); +} + +/* + * Get the details of a given gfn. + * + * If the entry is present, the associated MFN will be returned and the + * p2m type gets filled up. + * If the entry is not present, INVALID_MFN will be returned + * + * The page_order is meaningless in MPU system, and we keep it here + * to be compatible with MMU system. + */ +mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn, + p2m_type_t *t, p2m_access_t *a, + unsigned int *page_order, + bool *valid) +{ + return p2m_get_mpu_region(p2m, gfn, 1, t, valid); +} + /* * Local variables: * mode: C -- 2.25.1