arm/mpu: Populate a new region in Xen MPU mapping table

Introduce map_pages_to_xen() that is implemented using a new helper,
xen_mpumap_update(), which is responsible for updating Xen MPU memory
mapping table(xen_mpumap), including creating a new entry, updating
or destroying an existing one, it is equivalent to xen_pt_update in MMU.

This commit only implements populating a new entry in Xen MPU memory mapping
table(xen_mpumap).

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
Signed-off-by: Wei Chen <wei.chen@arm.com>
Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
This commit is contained in:
Penny Zheng authored and Michal Orzel committed 2025-07-23 09:50:43 +02:00
1 parent 0b61063c6e
commit 37671e52cf
2 files changed
+115

No files matched your search

+12
View File
@@ -64,6 +64,7 @@ static inline void context_sync_mpu(void)
* The following API requires context_sync_mpu() after being used to modify MPU
* regions:
* - write_protection_region
* - xen_mpumap_update
*/
/* Reads the MPU region (into @pr_read) with index @sel from the HW */
@@ -72,6 +73,17 @@ void read_protection_region(pr_t *pr_read, uint8_t sel);
/* Writes the MPU region (from @pr_write) with index @sel to the HW */
void write_protection_region(const pr_t *pr_write, uint8_t sel);
/*
* Maps an address range into the MPU data structure and updates the HW.
* Equivalent to xen_pt_update in an MMU system.
*
* @param base Base address of the range to map (inclusive).
* @param limit Limit address of the range to map (exclusive).
* @param flags Flags for the memory range to map.
* @return 0 on success, negative on error.
*/
int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags);
/*
* Creates a pr_t structure describing a protection region.
*
+103
View File
@@ -6,6 +6,7 @@
#include <xen/lib.h>
#include <xen/mm.h>
#include <xen/sizes.h>
#include <xen/spinlock.h>
#include <xen/types.h>
#include <asm/mpu.h>
#include <asm/mpu/mm.h>
@@ -29,6 +30,8 @@ DECLARE_BITMAP(xen_mpumap_mask, MAX_MPU_REGION_NR) \
/* EL2 Xen MPU memory region mapping table. */
pr_t __cacheline_aligned __section(".data") xen_mpumap[MAX_MPU_REGION_NR];
static DEFINE_SPINLOCK(xen_mpumap_lock);
static void __init __maybe_unused build_assertions(void)
{
/*
@@ -165,6 +168,106 @@ int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
return MPUMAP_REGION_NOTFOUND;
}
/*
* Allocate an entry for a new EL2 MPU region in the bitmap xen_mpumap_mask.
* @param idx Set to the index of the allocated EL2 MPU region on success.
* @return 0 on success, otherwise -ENOENT on failure.
*/
static int xen_mpumap_alloc_entry(uint8_t *idx)
{
ASSERT(spin_is_locked(&xen_mpumap_lock));
*idx = find_first_zero_bit(xen_mpumap_mask, max_mpu_regions);
if ( *idx == max_mpu_regions )
{
printk(XENLOG_ERR "EL2 MPU memory region mapping pool exhausted\n");
return -ENOENT;
}
set_bit(*idx, xen_mpumap_mask);
return 0;
}
/*
* Update the entry in the MPU memory region mapping table (xen_mpumap) for the
* given memory range and flags, creating one if none exists.
*
* @param base Base address (inclusive).
* @param limit Limit address (exclusive).
* @param flags Region attributes (a combination of PAGE_HYPERVISOR_XXX)
* @return 0 on success, otherwise negative on error.
*/
static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
unsigned int flags)
{
uint8_t idx;
int rc;
ASSERT(spin_is_locked(&xen_mpumap_lock));
/* Currently only region creation is supported. */
if ( !(flags & _PAGE_PRESENT) )
return -EINVAL;
rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
if ( rc != MPUMAP_REGION_NOTFOUND )
return -EINVAL;
/* We are inserting a mapping => Create new region. */
rc = xen_mpumap_alloc_entry(&idx);
if ( rc )
return -ENOENT;
xen_mpumap[idx] = pr_of_addr(base, limit, flags);
write_protection_region(&xen_mpumap[idx], idx);
return 0;
}
int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags)
{
int rc;
if ( flags_has_rwx(flags) )
{
printk("Mappings should not be both Writeable and Executable\n");
return -EINVAL;
}
if ( base >= limit )
{
printk("Base address %#"PRIpaddr" must be smaller than limit address %#"PRIpaddr"\n",
base, limit);
return -EINVAL;
}
if ( !IS_ALIGNED(base, PAGE_SIZE) || !IS_ALIGNED(limit, PAGE_SIZE) )
{
printk("base address %#"PRIpaddr", or limit address %#"PRIpaddr" is not page aligned\n",
base, limit);
return -EINVAL;
}
spin_lock(&xen_mpumap_lock);
rc = xen_mpumap_update_entry(base, limit, flags);
if ( !rc )
context_sync_mpu();
spin_unlock(&xen_mpumap_lock);
return rc;
}
int map_pages_to_xen(unsigned long virt, mfn_t mfn, unsigned long nr_mfns,
unsigned int flags)
{
/* MPU systems have no translation, ma == va, so pass virt directly */
return xen_mpumap_update(virt, mfn_to_maddr(mfn_add(mfn, nr_mfns)), flags);
}
void __init setup_mm(void)
{
BUG_ON("unimplemented");
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.