|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [PATCH v2 19/40] xen/mpu: populate a new region in Xen MPU mapping table
Hi Julien
> -----Original Message-----
> From: Julien Grall <julien@xxxxxxx>
> Sent: Monday, February 6, 2023 5:46 AM
> To: Penny Zheng <Penny.Zheng@xxxxxxx>; xen-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Wei Chen <Wei.Chen@xxxxxxx>; Stefano Stabellini
> <sstabellini@xxxxxxxxxx>; Bertrand Marquis <Bertrand.Marquis@xxxxxxx>;
> Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
> Subject: Re: [PATCH v2 19/40] xen/mpu: populate a new region in Xen MPU
> mapping table
>
> Hi,
>
> On 13/01/2023 05:28, Penny Zheng wrote:
> > The new helper xen_mpumap_update() is responsible for updating an
> > entry in Xen MPU memory mapping table, including creating a new entry,
> > updating or destroying an existing one.
> >
> > This commit only talks about populating a new entry in Xen MPU mapping
> > table( xen_mpumap). Others will be introduced in the following commits.
> >
> > In xen_mpumap_update_entry(), firstly, we shall check if requested
> > address range [base, limit) is not mapped. Then we use pr_of_xenaddr()
> > to build up the structure of MPU memory region(pr_t).
> > In the last, we set memory attribute and permission based on variable
> @flags.
> >
> > To summarize all region attributes in one variable @flags, layout of
> > the flags is elaborated as follows:
> > [0:2] Memory attribute Index
> > [3:4] Execute Never
> > [5:6] Access Permission
> > [7] Region Present
> > Also, we provide a set of definitions(REGION_HYPERVISOR_RW, etc) that
> > combine the memory attribute and permission for common combinations.
> >
> > Signed-off-by: Penny Zheng <penny.zheng@xxxxxxx>
> > Signed-off-by: Wei Chen <wei.chen@xxxxxxx>
> > ---
> > xen/arch/arm/include/asm/arm64/mpu.h | 72 +++++++
> > xen/arch/arm/mm_mpu.c | 276 ++++++++++++++++++++++++++-
> > 2 files changed, 340 insertions(+), 8 deletions(-)
> >
[...]
> > +
> > +#define MPUMAP_REGION_FAILED 0
> > +#define MPUMAP_REGION_FOUND 1
> > +#define MPUMAP_REGION_INCLUSIVE 2
> > +#define MPUMAP_REGION_OVERLAP 3
> > +
> > +/*
> > + * Check whether memory range [base, limit] is mapped in MPU memory
> > + * region table \mpu. Only address range is considered, memory
> > +attributes
> > + * and permission are not considered here.
> > + * If we find the match, the associated index will be filled up.
> > + * If the entry is not present, INVALID_REGION will be set in \index
> > + *
> > + * Make sure that parameter \base and \limit are both referring
> > + * inclusive addresss
> > + *
> > + * Return values:
> > + * MPUMAP_REGION_FAILED: no mapping and no overmapping
> > + * MPUMAP_REGION_FOUND: find an exact match in address
> > + * MPUMAP_REGION_INCLUSIVE: find an inclusive match in address
> > + * MPUMAP_REGION_OVERLAP: overlap with the existing mapping */
> > +static int mpumap_contain_region(pr_t *mpu, uint64_t nr_regions,
> > + paddr_t base, paddr_t limit,
> > +uint64_t *index)
>
> Is it really possible to support 2^64 - 1 region? If so, is that the case on
> arm32
> as well?
>
No, the allowable bitwidth is 8 bit. I'll change it uint8_t instead
> > +{
> > + uint64_t i = 0;
> > + uint64_t _index = INVALID_REGION;
> > +
> > + /* Allow index to be NULL */
> > + index = index ?: &_index;
> > +
> > + for ( ; i < nr_regions; i++ )
> > + {
> > + paddr_t iter_base = pr_get_base(&mpu[i]);
> > + paddr_t iter_limit = pr_get_limit(&mpu[i]);
> > +
> > + /* Found an exact valid match */
> > + if ( (iter_base == base) && (iter_limit == limit) &&
> > + region_is_valid(&mpu[i]) )
> > + {
> > + *index = i;
> > + return MPUMAP_REGION_FOUND;
> > + }
> > +
> > + /* No overlapping */
> > + if ( (iter_limit < base) || (iter_base > limit) )
> > + continue;
> > + /* Inclusive and valid */
> > + else if ( (base >= iter_base) && (limit <= iter_limit) &&
> > + region_is_valid(&mpu[i]) )
> > + {
> > + *index = i;
> > + return MPUMAP_REGION_INCLUSIVE;
> > + }
> > + else
> > + {
> > + region_printk("Range 0x%"PRIpaddr" - 0x%"PRIpaddr" overlaps
> with the existing region 0x%"PRIpaddr" - 0x%"PRIpaddr"\n",
> > + base, limit, iter_base, iter_limit);
> > + return MPUMAP_REGION_OVERLAP;
> > + }
> > + }
> > +
> > + return MPUMAP_REGION_FAILED;
> > +}
> > +
> > +/*
> > + * Update an entry at the index @idx.
> > + * @base: base address
> > + * @limit: limit address(exclusive)
> > + * @flags: region attributes, should be the combination of
> > +REGION_HYPERVISOR_xx */ static int
> xen_mpumap_update_entry(paddr_t
> > +base, paddr_t limit,
> > + unsigned int flags) {
> > + uint64_t idx;
> > + int rc;
> > +
> > + rc = mpumap_contain_region(xen_mpumap, max_xen_mpumap, base,
> limit - 1,
> > + &idx);
> > + if ( rc == MPUMAP_REGION_OVERLAP )
> > + return -EINVAL;
> > +
> > + /* We are inserting a mapping => Create new region. */
> > + if ( flags & _REGION_PRESENT )
> > + {
> > + if ( rc != MPUMAP_REGION_FAILED )
> > + return -EINVAL;
> > +
> > + if ( xen_boot_mpu_regions_is_full() )
> > + {
> > + region_printk("There is no room left in EL2 MPU memory region
> mapping\n");
> > + return -ENOMEM;
> > + }
> > +
> > + /* During boot time, the default index is next_fixed_region_idx. */
> > + if ( system_state <= SYS_STATE_active )
> > + idx = next_fixed_region_idx;
> > +
> > + xen_mpumap[idx] = pr_of_xenaddr(base, limit - 1,
> REGION_AI_MASK(flags));
> > + /* Set permission */
> > + xen_mpumap[idx].prbar.reg.ap = REGION_AP_MASK(flags);
> > + xen_mpumap[idx].prbar.reg.xn = REGION_XN_MASK(flags);
> > +
> > + /* Update and enable the region */
> > + access_protection_region(false, NULL, (const
> pr_t*)(&xen_mpumap[idx]),
> > + idx);
> > +
> > + if ( system_state <= SYS_STATE_active )
> > + update_boot_xen_mpumap_idx(idx);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned
> > +int flags) {
> > + int rc;
> > +
> > + /*
> > + * The hardware was configured to forbid mapping both writeable and
> > + * executable.
> > + * When modifying/creating mapping (i.e _REGION_PRESENT is set),
> > + * prevent any update if this happen.
> > + */
> > + if ( (flags & _REGION_PRESENT) && !REGION_RO_MASK(flags) &&
> > + !REGION_XN_MASK(flags) )
> > + {
> > + region_printk("Mappings should not be both Writeable and
> Executable.\n");
> > + return -EINVAL;
> > + }
> > +
> > + if ( !IS_ALIGNED(base, PAGE_SIZE) || !IS_ALIGNED(limit, PAGE_SIZE) )
> > + {
> > + region_printk("base address 0x%"PRIpaddr", or limit address
> 0x%"PRIpaddr" is not page aligned.\n",
> > + base, limit);
> > + return -EINVAL;
> > + }
> > +
> > + spin_lock(&xen_mpumap_lock);
> > +
> > + rc = xen_mpumap_update_entry(base, limit, flags);
> > +
> > + 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) {
> > + ASSERT(virt == mfn_to_maddr(mfn));
> > +
> > + return xen_mpumap_update(mfn_to_maddr(mfn),
> > + mfn_to_maddr(mfn_add(mfn, nr_mfns)),
> > +flags); }
> > +
> > /* TODO: Implementation on the first usage */
> > void dump_hyp_walk(vaddr_t addr)
> > {
> > @@ -230,14 +498,6 @@ void *ioremap(paddr_t pa, size_t len)
> > return NULL;
> > }
> >
> > -int map_pages_to_xen(unsigned long virt,
> > - mfn_t mfn,
> > - unsigned long nr_mfns,
> > - unsigned int flags)
> > -{
> > - return -ENOSYS;
> > -}
> > -
>
> Why do you implement map_pages_to_xen() at a different place?
>
>
> > int destroy_xen_mappings(unsigned long s, unsigned long e)
> > {
> > return -ENOSYS;
>
> Cheers,
>
> --
> Julien Grall
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |