[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH RFC 9/9] xen: arm: support for up to 48-bit IPA addressing on arm64



Hi Ian,

On 07/30/2014 02:47 PM, Ian Campbell wrote:
> Currently we support only 40-bits. This is insufficient on systems where
> peripherals which need to be 1:1 mapped to dom0 are above the 40-bit limit.
> 
> Unfortunately the hardware requirements are such that this means that the
> number of levels in the P2M is not static and must vary with the number of
> implemented physical address bits. This is described in ARM DDI 0487A.b Table
> D4-5. In short there is no single p2m configuration which supports everything
> from 40- to 48- bits.
> 
> For example a system which supports up to 40-bit addressing will only support 
> 3
> level p2m (maximum SL0 is 1 == 3 levels), requiring a concatenated page table
> root consisting of two pages to make the full 40-bits of addressing.
> 
> A maximum of 16 pages can be concatenated meaning that a 3 level p2m can only
> support up to 43-bit addreses. Therefore support for 48-bit addressing requres

s/addreses/addresses/
s/requres/requires/

> SL0==2 (4 levels of paging).
> 
> After the previous patches our various p2m lookup and manipulation functions
> already support starting at arbitrary level and with arbitrary root
> concatenation. All that remains is to determine the correct settings from
> ID_AA64MMFR0_EL1.PARange for which we use a lookup table.
> 
> As well as supporting 44 and 48 bit addressing we can also reduce the order of
> the first level for systems which support only 32 or 36 physical address bits,
> saving a page.
> 
> Systems with 42-bits are an interesting case, since they only support 3 levels
> of paging, implying that 8 pages are required at the root level. So far I am
> not aware of any systems with peripheral located so high up (the only 42-bit
> system I've seen has nothing above 40-bits), so such systems remain configured
> for 40-bit IPA with a pair of pages at the root of the p2m.
> 
> Switching to synbolic names for the VTCR_EL2 bits as we go improves the 
> clarity

s/synbolic/symbolic/

> of the result.
> 
> Parts of this are derived from "xen/arm: Add 4-level page table for
> stage 2 translation" by Vijaya Kumar K.
> 
> arm32 remains with the static 3-level, 2 page root configuration.
> 
> Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
> ---
>  xen/arch/arm/p2m.c              |   82 
> +++++++++++++++++++++++++++++++--------
>  xen/include/asm-arm/p2m.h       |    2 +-
>  xen/include/asm-arm/processor.h |   28 +++++++++++++
>  3 files changed, 94 insertions(+), 18 deletions(-)
> 
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index e9938ae..0e8e8e0 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -11,10 +11,17 @@
>  #include <asm/hardirq.h>
>  #include <asm/page.h>
>  
> -#define P2M_ROOT_LEVEL       1
> +#ifdef CONFIG_ARM_64
> +static int __read_mostly p2m_root_order;

unsigned int? It might even be better to use uint8_t as we won't never
have an order greater than 256. Even though I'm not sure if it will
improve performance.

> +static int __read_mostly p2m_root_level;

same here.

> +#define P2M_ROOT_ORDER    p2m_root_order
> +#define P2M_ROOT_LEVEL p2m_root_level
> +#else
> +/* First level P2M is alway 2 consecutive pages */
> +#define P2M_ROOT_LEVEL 1
> +#define P2M_ROOT_ORDER    1
> +#endif
>  
> -/* First level P2M is 2 consecutive pages */
> -#define P2M_ROOT_ORDER 1
>  #define P2M_ROOT_PAGES    (1<<P2M_ROOT_ORDER)
>  
>  static bool_t p2m_valid(lpae_t pte)
> @@ -164,6 +171,8 @@ paddr_t p2m_lookup(struct domain *d, paddr_t paddr, 
> p2m_type_t *t)
>  
>      map = __map_domain_page(p2m->root + root_table);
>  
> +    BUG_ON(P2M_ROOT_LEVEL >= 4);
> +

For ARM64, P2M_ROOT_LEVEL is set up once at startup and AFAIU should not
change.

Using BUG_ON seem excessive here. If you want to keep a test, I would
use ASSERT to avoid impacting hypervisor in production mode.

>      for ( level = P2M_ROOT_LEVEL ; level < 4 ; level++ )
>      {
>          mask = masks[level];
> @@ -883,6 +892,7 @@ int p2m_alloc_table(struct domain *d)
>  {
>      struct p2m_domain *p2m = &d->arch.p2m;
>      struct page_info *page;
> +    int i;

unsigned int.

[..]

>  #ifdef CONFIG_ARM_32
> -    val = 0x80003558;
> -#else
> -    val = 0x80023558;
> +    printk("P2M: 40-bit IPA\n");
> +    val |= VTCR_T0SZ(0x18); /* 40 bit IPA */
> +#else /* CONFIG_ARM_64 */
> +    const struct {
> +        unsigned pabits; /* Physical Address Size */

missing the unsigned int by mistake? Or maybe uint8_t.

> +        unsigned t0sz;   /* Desired T0SZ, minimum in comment */
> +        unsigned root_order; /* Page order of the root of the p2m */
> +        unsigned sl0;    /* Desired SL0, maximum in comment */
> +    } pa_range_info[] = {
> +        /* T0SZ minimum and SL0 maximum from ARM DDI 0487A.b Table D4-5 */
> +        /*      PA size, t0sz(min), root-order, sl0(max) */
> +        [0] = { 32,      32/*32*/,  0,          1 },
> +        [1] = { 36,      28/*28*/,  0,          1 },
> +        [2] = { 40,      24/*24*/,  1,          1 },
> +        [3] = { 42,      24/*22*/,  1,          1 },
> +        [4] = { 44,      20/*20*/,  0,          2 },
> +        [5] = { 48,      16/*16*/,  0,          2 },
> +        [6] = { 0 }, /* Invalid */
> +        [7] = { 0 }  /* Invalid */
> +    };
> +
> +    int cpu;

unsigned int

> +    int pa_range = 0x10; /* Larger than any possible value */

same here.

> +
> +    for_each_online_cpu ( cpu )
> +    {
> +        struct cpuinfo_arm *info = &cpu_data[cpu];
> +        if ( info->mm64.pa_range < pa_range )
> +            pa_range = info->mm64.pa_range;
> +    }
> +
> +    /* pa_range is 4 bits, but the defined encodings are only 3 bits */
> +    if ( pa_range&0x8 || !pa_range_info[pa_range].pabits )

I think a space is missing around & for clarity.

> +        panic("Unknown encoding of ID_AA64MMFR0_EL1.PARange %x\n", pa_range);
> +
> +    val |= VTCR_PS(pa_range);
> +    val |= VTCR_TG0_4K;
> +    val |= VTCR_SL0(pa_range_info[pa_range].sl0);
> +    val |= VTCR_T0SZ(pa_range_info[pa_range].t0sz);
> +
> +    p2m_root_order = pa_range_info[pa_range].root_order;
> +    p2m_root_level = 2 - pa_range_info[pa_range].sl0;

Following my comment on BUG_ON earlier, I think you should check that we
correctly support the values set in p2m_root_{order,level} and bail out
if necessary.

[..]

> diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
> index 979a41d..a744a67 100644
> --- a/xen/include/asm-arm/processor.h
> +++ b/xen/include/asm-arm/processor.h
> @@ -116,6 +116,34 @@
>  #define TCR_RES1        (_AC(1,UL)<<31)
>  #endif
>  
> +/* VTCR: Stage 2 Translation Control */
> +
> +#define VTCR_T0SZ(x)    ((x)<<0)
> +
> +#define VTCR_SL0(x)     ((x)<<6)
> +
> +#define VTCR_IRGN0_NC   (_AC(0x0,UL)<<8)
> +#define VTCR_IRGN0_WBWA (_AC(0x1,UL)<<8)
> +#define VTCR_IRGN0_WT   (_AC(0x2,UL)<<8)
> +#define VTCR_IRGN0_WB   (_AC(0x3,UL)<<8)
> +
> +#define VTCR_ORGN0_NC   (_AC(0x0,UL)<<10)
> +#define VTCR_ORGN0_WBWA (_AC(0x1,UL)<<10)
> +#define VTCR_ORGN0_WT   (_AC(0x2,UL)<<10)
> +#define VTCR_ORGN0_WB   (_AC(0x3,UL)<<10)
> +
> +#define VTCR_SH0_NS     (_AC(0x0,UL)<<12)
> +#define VTCR_SH0_OS     (_AC(0x2,UL)<<12)
> +#define VTCR_SH0_IS     (_AC(0x3,UL)<<12)
> +
> +#define VTCR_TG0_4K     (_AC(0x0,UL)<<14) /* arm64 only */
> +#define VTCR_TG0_64K    (_AC(0x1,UL)<<14)
> +#define VTCR_TG0_16K    (_AC(0x2,UL)<<14)
> +
> +#define VTCR_PS(x)      ((x)<<16)

All the define from the "/* arm64 only */" up to here are arm64 only.

With the comment at the end of the line it's no clear that it's actually
the case. It might be worse to add an #ifdef CONFIG_ARM_64

Regards,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.