|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@xxxxxxxxxx>
>
> In follow-up patches, we will use xen_pt_update() (or its callers)
> to handle large mappings (e.g. frametable, xenheap). They are also
> not going to be modified once created.
>
> The page-table entries have an hint to indicate that whether an
> entry is contiguous to another 16 entries (assuming 4KB). When the
> processor support the hint, one TLB entry will be created per
> contiguous region.
>
> For now this is tied to _PAGE_BLOCK. We can untie it in the future
> if there are use-cases where we may want to use _PAGE_BLOCK without
> setting the contiguous (couldn't think of any yet).
>
> Note that to avoid extra complexity, mappings with the contiguous
> bit set cannot be removed. Given the expected use, this restriction
> ought to be fine.
>
> Signed-off-by: Julien Grall <jgrall@xxxxxxxxxx>
>
> ---
> Changes in v3:
> - New patch
> ---
> xen/arch/arm/include/asm/page.h | 4 ++
> xen/arch/arm/mm.c | 80 ++++++++++++++++++++++++++++++---
> 2 files changed, 77 insertions(+), 7 deletions(-)
>
> diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
> index 07998df47bac..e7cd62190c7f 100644
> --- a/xen/arch/arm/include/asm/page.h
> +++ b/xen/arch/arm/include/asm/page.h
> @@ -70,6 +70,7 @@
> * [5] Page present
> * [6] Only populate page tables
> * [7] Superpage mappings is allowed
> + * [8] Set contiguous bit (internal flag)
> */
> #define PAGE_AI_MASK(x) ((x) & 0x7U)
>
> @@ -86,6 +87,9 @@
> #define _PAGE_BLOCK_BIT 7
> #define _PAGE_BLOCK (1U << _PAGE_BLOCK_BIT)
>
> +#define _PAGE_CONTIG_BIT 8
> +#define _PAGE_CONTIG (1U << _PAGE_CONTIG_BIT)
> +
> /*
> * _PAGE_DEVICE and _PAGE_NORMAL are convenience defines. They are not
> * meant to be used outside of this header.
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 3af69b396bd1..fd16c1541ce2 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -1237,6 +1237,8 @@ static int xen_pt_update_entry(mfn_t root, unsigned
> long virt,
> /* Set permission */
> pte.pt.ro = PAGE_RO_MASK(flags);
> pte.pt.xn = PAGE_XN_MASK(flags);
> + /* Set contiguous bit */
> + pte.pt.contig = !!(flags & _PAGE_CONTIG);
> }
>
> write_pte(entry, pte);
> @@ -1289,6 +1291,51 @@ static int xen_pt_mapping_level(unsigned long vfn,
> mfn_t mfn, unsigned long nr,
> return level;
> }
>
> +#define XEN_PT_4K_NR_CONTIG 16
> +
> +/*
> + * Check whether the contiguous bit can be set. Return the number of
> + * contiguous entry allowed. If not allowed, return 1.
> + */
> +static unsigned int xen_pt_check_contig(unsigned long vfn, mfn_t mfn,
> + unsigned int level, unsigned long
> left,
> + unsigned int flags)
> +{
> + unsigned long nr_contig;
> +
> + /*
> + * Allow the contiguous bit to set when the caller requests block
> + * mapping.
> + */
> + if ( !(flags & _PAGE_BLOCK) )
> + return 1;
> +
> + /*
> + * We don't allow to remove mapping with the contiguous bit set.
> + * So shortcut the logic and directly return 1.
> + */
> + if ( mfn_eq(mfn, INVALID_MFN) )
> + return 1;
> +
> + /*
> + * The number of contiguous entries varies depending on the page
> + * granularity used. The logic below assumes 4KB.
> + */
> + BUILD_BUG_ON(PAGE_SIZE != SZ_4K);
> +
> + /*
> + * In order to enable the contiguous bit, we should have enough entries
> + * to map left and both the virtual and physical address should be
> + * aligned to the size of 16 translation tables entries.
> + */
> + nr_contig = BIT(XEN_PT_LEVEL_ORDER(level), UL) * XEN_PT_4K_NR_CONTIG;
> +
> + if ( (left < nr_contig) || ((mfn_x(mfn) | vfn) & (nr_contig - 1)) )
> + return 1;
> +
> + return XEN_PT_4K_NR_CONTIG;
> +}
> +
> static DEFINE_SPINLOCK(xen_pt_lock);
>
> static int xen_pt_update(unsigned long virt,
> @@ -1322,6 +1369,12 @@ static int xen_pt_update(unsigned long virt,
> return -EINVAL;
> }
>
> + if ( flags & _PAGE_CONTIG )
> + {
> + mm_printk("_PAGE_CONTIG is an internal only flag.\n");
> + return -EINVAL;
> + }
> +
> if ( !IS_ALIGNED(virt, PAGE_SIZE) )
> {
> mm_printk("The virtual address is not aligned to the page-size.\n");
> @@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
> while ( left )
> {
> unsigned int order, level;
> + unsigned int nr_contig;
> + unsigned int new_flags;
>
> level = xen_pt_mapping_level(vfn, mfn, left, flags);
> order = XEN_PT_LEVEL_ORDER(level);
>
> ASSERT(left >= BIT(order, UL));
>
> - rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
> - if ( rc )
> - break;
> + /*
> + * Check if we can set the contiguous mapping and update the
> + * flags accordingly.
> + */
> + nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
> + new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);
Here is an optional idea to make the code simpler. We could move the
flags changes (adding/removing _PAGE_CONTIG) to xen_pt_check_contig.
That way, we could remove the inner loop.
xen_pt_check_contig could check if _PAGE_CONTIG is already set and based
on alignment, it should be able to figure out when it needs to be
disabled.
But also this code works as far as I can tell.
> - vfn += 1U << order;
> - if ( !mfn_eq(mfn, INVALID_MFN) )
> - mfn = mfn_add(mfn, 1U << order);
> + for ( ; nr_contig > 0; nr_contig-- )
> + {
> + rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
> + new_flags);
> + if ( rc )
> + break;
>
> - left -= (1U << order);
> + vfn += 1U << order;
> + if ( !mfn_eq(mfn, INVALID_MFN) )
> + mfn = mfn_add(mfn, 1U << order);
> +
> + left -= (1U << order);
> + }
> }
>
> /*
> --
> 2.32.0
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |