mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
arm/mpu: Implement reference counting for inclusive regions
Implement reference counting to enable inclusive MPU regions. An inclusive region is defined as a region encapsulated inside a previously allocated region sharing the same permissions. Reference counts are incremented and decremented in xen_mpumap_update_entry. A region will be destroyed if the reference count is 0 upon calling destroy_xen_mappings and if the full region range is specified. Additionally XEN_MPUMAP_ENTRY_SHIFT and XEN_MPUMAP_ENTRY_SHIFT_ZERO are no longer hardcoded and defined inside asm-offsets.c. Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> Reviewed-by: Michal Orzel <michal.orzel@amd.com>
This commit is contained in:
1 parent
5c4b1283bb
commit
1128e6fe36
6 files changed
+76
-16
No files matched your search
@@ -79,6 +79,8 @@ void __dummy__(void)
|
||||
#ifdef CONFIG_MPU
|
||||
DEFINE(XEN_MPUMAP_MASK_sizeof, sizeof(xen_mpumap_mask));
|
||||
DEFINE(XEN_MPUMAP_sizeof, sizeof(xen_mpumap));
|
||||
DEFINE(XEN_MPUMAP_ENTRY_SHIFT, ilog2(sizeof(pr_t)));
|
||||
DEFINE(XEN_MPUMAP_ENTRY_ZERO_OFFSET, sizeof(prbar_t) + sizeof(prlar_t));
|
||||
BLANK();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ void __dummy__(void)
|
||||
#ifdef CONFIG_MPU
|
||||
DEFINE(XEN_MPUMAP_MASK_sizeof, sizeof(xen_mpumap_mask));
|
||||
DEFINE(XEN_MPUMAP_sizeof, sizeof(xen_mpumap));
|
||||
DEFINE(XEN_MPUMAP_ENTRY_SHIFT, ilog2(sizeof(pr_t)));
|
||||
DEFINE(XEN_MPUMAP_ENTRY_ZERO_OFFSET, sizeof(prbar_t) + sizeof(prlar_t));
|
||||
BLANK();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ typedef union {
|
||||
typedef struct {
|
||||
prbar_t prbar;
|
||||
prlar_t prlar;
|
||||
uint8_t refcount;
|
||||
uint8_t pad[7]; /* Pad structure to 16 Bytes */
|
||||
} pr_t;
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
@@ -38,6 +38,8 @@ typedef union {
|
||||
typedef struct {
|
||||
prbar_t prbar;
|
||||
prlar_t prlar;
|
||||
uint8_t refcount;
|
||||
uint8_t pad[15]; /* Pad structure to 32 Bytes */
|
||||
} pr_t;
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
@@ -14,14 +14,12 @@
|
||||
#define PRLAR_ELx_EN 0x1
|
||||
|
||||
#ifdef CONFIG_ARM_64
|
||||
#define XEN_MPUMAP_ENTRY_SHIFT 0x4 /* 16 byte structure */
|
||||
|
||||
.macro store_pair reg1, reg2, dst
|
||||
stp \reg1, \reg2, [\dst]
|
||||
.endm
|
||||
|
||||
#else
|
||||
#define XEN_MPUMAP_ENTRY_SHIFT 0x3 /* 8 byte structure */
|
||||
|
||||
.macro store_pair reg1, reg2, dst
|
||||
strd \reg1, \reg2, [\dst]
|
||||
@@ -97,6 +95,15 @@
|
||||
|
||||
3:
|
||||
|
||||
/* Clear the rest of the xen_mpumap entry. */
|
||||
#ifdef CONFIG_ARM_64
|
||||
stp xzr, xzr, [\base, #XEN_MPUMAP_ENTRY_ZERO_OFFSET]
|
||||
#else
|
||||
mov \prbar, #0
|
||||
mov \prlar, #0
|
||||
strd \prbar, \prlar, [\base, #XEN_MPUMAP_ENTRY_ZERO_OFFSET]
|
||||
#endif
|
||||
|
||||
add \sel, \sel, #1
|
||||
|
||||
1:
|
||||
|
||||
+59
-14
@@ -106,6 +106,7 @@ pr_t pr_of_addr(paddr_t base, paddr_t limit, unsigned int flags)
|
||||
region = (pr_t) {
|
||||
.prbar = prbar,
|
||||
.prlar = prlar,
|
||||
.refcount = 0,
|
||||
};
|
||||
|
||||
/* Set base address and limit address. */
|
||||
@@ -170,6 +171,35 @@ int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
|
||||
return MPUMAP_REGION_NOTFOUND;
|
||||
}
|
||||
|
||||
static bool is_mm_attr_match(pr_t *region, unsigned int attributes)
|
||||
{
|
||||
if ( region->prbar.reg.ro != PAGE_RO_MASK(attributes) )
|
||||
{
|
||||
printk(XENLOG_WARNING
|
||||
"Mismatched Access Permission attributes (%#x instead of %#x)\n",
|
||||
region->prbar.reg.ro, PAGE_RO_MASK(attributes));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( region->prbar.reg.xn != PAGE_XN_MASK(attributes) )
|
||||
{
|
||||
printk(XENLOG_WARNING
|
||||
"Mismatched Execute Never attributes (%#x instead of %#x)\n",
|
||||
region->prbar.reg.xn, PAGE_XN_MASK(attributes));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( region->prlar.reg.ai != PAGE_AI_MASK(attributes) )
|
||||
{
|
||||
printk(XENLOG_WARNING
|
||||
"Mismatched Memory Attribute Index (%#x instead of %#x)\n",
|
||||
region->prlar.reg.ai, PAGE_AI_MASK(attributes));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Map a frame table to cover physical addresses ps through pe */
|
||||
void __init setup_frametable_mappings(paddr_t ps, paddr_t pe)
|
||||
{
|
||||
@@ -284,22 +314,26 @@ static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
|
||||
|
||||
flags_has_page_present = flags & _PAGE_PRESENT;
|
||||
|
||||
/* Currently we don't support modifying an existing entry. */
|
||||
/*
|
||||
* Currently, we only support removing/modifying a *WHOLE* MPU memory
|
||||
* region. Part-region removal/modification is not supported as in the worst
|
||||
* case it will leave two/three fragments behind.
|
||||
*/
|
||||
if ( flags_has_page_present && (rc >= MPUMAP_REGION_FOUND) )
|
||||
{
|
||||
printk("Modifying an existing entry is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( !is_mm_attr_match(&xen_mpumap[idx], flags) )
|
||||
{
|
||||
printk("Modifying an existing entry is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently, we only support removing/modifying a *WHOLE* MPU memory
|
||||
* region. Part-region removal/modification is not supported as in the worst
|
||||
* case it will leave two/three fragments behind.
|
||||
*/
|
||||
if ( rc == MPUMAP_REGION_INCLUSIVE )
|
||||
{
|
||||
printk("Part-region removal/modification is not supported\n");
|
||||
return -EINVAL;
|
||||
/* Check for overflow of refcount before incrementing. */
|
||||
if ( xen_mpumap[idx].refcount == 0xFF )
|
||||
{
|
||||
printk("Cannot allocate region as it would cause refcount overflow\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
xen_mpumap[idx].refcount += 1;
|
||||
}
|
||||
|
||||
/* We are inserting a mapping => Create new region. */
|
||||
@@ -323,7 +357,18 @@ static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
disable_mpu_region_from_index(idx);
|
||||
if ( xen_mpumap[idx].refcount == 0 )
|
||||
{
|
||||
if ( MPUMAP_REGION_FOUND == rc )
|
||||
disable_mpu_region_from_index(idx);
|
||||
else
|
||||
{
|
||||
printk("Cannot remove a partial region\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
xen_mpumap[idx].refcount -= 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||