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

Re: [Xen-devel] [RFC PATCH] xen/arm: Add 4-level page table for stage 2 translation



Hello Vijaya,

On 04/30/2014 01:15 PM, vijay.kilari@xxxxxxxxx wrote:
> diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> index d151724..c0e0362 100644
> --- a/xen/arch/arm/arm64/head.S
> +++ b/xen/arch/arm/arm64/head.S
> @@ -224,13 +224,16 @@ skip_bss:
>          ldr   x0, =MAIRVAL
>          msr   mair_el2, x0
>  
> +        mrs x1, ID_AA64MMFR0_EL1
> +
>          /* Set up the HTCR:
> -         * PASize -- 40 bits / 1TB
> +         * PASize -- based on ID_AA64MMFR0_EL1.PARange value
>           * Top byte is used
>           * PT walks use Outer-Shareable accesses,
>           * PT walks are write-back, write-allocate in both cache levels,
>           * Full 64-bit address space goes through this table. */
> -        ldr   x0, =0x80822500
> +        ldr x0, =TCR_VAL_40PA

If you define TCR_VAL_40PA in another header, I would also move the
comments explaining the different bits in this header.

> +        bfi x0, x1, #16, #3
>          msr   tcr_el2, x0
>  
>          /* Set up the SCTLR_EL2:
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 305879f..d577b23 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -382,13 +382,18 @@ void __cpuinit setup_virt_paging(void)
>      /* SH0=00, ORGN0=IRGN0=01
>       * SL0=01 (Level-1)
>       * ARVv7: T0SZ=(1)1000 = -8 (32-(-8) = 40 bit physical addresses)
>       * ARMv8: T0SZ=01 1000 = 24 (64-24   = 40 bit physical addresses)
>       *        PS=010 == 40 bits
>       */
>  #ifdef CONFIG_ARM_32
> -    WRITE_SYSREG32(0x80002558, VTCR_EL2);
> +    WRITE_SYSREG32(VTCR_VAL, VTCR_EL2);
>  #else
> -    WRITE_SYSREG32(0x80022558, VTCR_EL2);
> +    /* Change PS to 48 and T0SZ = 16  SL0 - 2 to take VA 48 bit */
> +    if ( current_cpu_data.mm64.pa_range == VTCR_PS_48BIT )
> +        WRITE_SYSREG32(VTCR_VAL_48PA, VTCR_EL2);
> +    else
> +        /* Consider by default 40 PA support for ARM64 */
> +        WRITE_SYSREG32(VTCR_VAL_40PA, VTCR_EL2);
>  #endif

Same remark here. Also, please update ARMv8 stuff for 48 bits PA in the
comment.

>      isb();
>  }
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index d00c882..bdaab46 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -10,29 +10,38 @@
>  #include <asm/hardirq.h>
>  #include <asm/page.h>
>  
> +#ifdef CONFIG_ARM_64
> +/* Zeroeth level is of 1 page size */
> +#define P2M_FIRST_ORDER 0

From your comment, should not it be P2M_ZEROETH_ORDER?

> +#else
>  /* First level P2M is 2 consecutive pages */
>  #define P2M_FIRST_ORDER 1
> +#endif
>  #define P2M_FIRST_ENTRIES (LPAE_ENTRIES<<P2M_FIRST_ORDER)
>  
>  void dump_p2m_lookup(struct domain *d, paddr_t addr)
>  {
>      struct p2m_domain *p2m = &d->arch.p2m;
> -    lpae_t *first;
> +    lpae_t *lookup;
>  
>      printk("dom%d IPA 0x%"PRIpaddr"\n", d->domain_id, addr);
>  
> +#ifdef CONFIG_ARM_64
> +    if ( zeroeth_linear_offset(addr) > LPAE_ENTRIES )
> +#else
>      if ( first_linear_offset(addr) > LPAE_ENTRIES )
> +#endif
>      {
> -        printk("Cannot dump addresses in second of first level pages...\n");
> +        printk("Cannot dump addresses in second of 
> first(ARM32)/zeroeth(ARM64) level pages...\n");
>          return;
>      }
>  
>      printk("P2M @ %p mfn:0x%lx\n",
> -           p2m->first_level, page_to_mfn(p2m->first_level));
> +           p2m->lookup_level, page_to_mfn(p2m->lookup_level));
>  
> -    first = __map_domain_page(p2m->first_level);
> -    dump_pt_walk(first, addr);
> -    unmap_domain_page(first);
> +    lookup = __map_domain_page(p2m->lookup_level);
> +    dump_pt_walk(lookup, addr);

dump_pt_walk assume the table is the first level. I think you should
update dump_pt_walk to handle the zeroeth level.

> +    unmap_domain_page(lookup);
>  }
>  
>  void p2m_load_VTTBR(struct domain *d)
> @@ -44,6 +53,20 @@ void p2m_load_VTTBR(struct domain *d)
>      isb(); /* Ensure update is visible */
>  }
>  
> +#ifdef CONFIG_ARM_64
> +/*
> + * Map zeroeth level page that addr contains.
> + */
> +static lpae_t *p2m_map_zeroeth(struct p2m_domain *p2m, paddr_t addr)
> +{
> +    if ( zeroeth_linear_offset(addr) >= LPAE_ENTRIES )
> +        return NULL;
> +
> +    return __map_domain_page(p2m->lookup_level);
> +}
> +
> +#else
> +
>  static int p2m_first_level_index(paddr_t addr)
>  {
>      /*
> @@ -64,10 +87,11 @@ static lpae_t *p2m_map_first(struct p2m_domain *p2m, 
> paddr_t addr)
>      if ( first_linear_offset(addr) >= P2M_FIRST_ENTRIES )
>          return NULL;
>  
> -    page = p2m->first_level + p2m_first_level_index(addr);
> +    page = p2m->lookup_level + p2m_first_level_index(addr);
>  
>      return __map_domain_page(page);
>  }
> +#endif
>  
>  /*
>   * Lookup the MFN corresponding to a domain's PFN.
> @@ -79,6 +103,9 @@ paddr_t p2m_lookup(struct domain *d, paddr_t paddr, 
> p2m_type_t *t)
>  {
>      struct p2m_domain *p2m = &d->arch.p2m;
>      lpae_t pte, *first = NULL, *second = NULL, *third = NULL;
> +#ifdef CONFIG_ARM_64
> +    lpae_t *zeroeth = NULL;
> +#endif
>      paddr_t maddr = INVALID_PADDR;
>      p2m_type_t _t;
>  
> @@ -89,9 +116,29 @@ paddr_t p2m_lookup(struct domain *d, paddr_t paddr, 
> p2m_type_t *t)
>  
>      spin_lock(&p2m->lock);
>  
> +#ifdef CONFIG_ARM_64
> +    zeroeth = p2m_map_zeroeth(p2m, paddr);
> +    if ( !zeroeth )
> +        goto err;
> +
> +    pte = zeroeth[zeroeth_table_offset(paddr)];
> +    /* Zeroeth level does not support block translation
> +     * so pte.p2m.table should be always set.
> +     * Just check for valid bit
> +     */
> +    if ( !pte.p2m.valid )
> +        goto done;
> +
> +#else
>      first = p2m_map_first(p2m, paddr);
>      if ( !first )
>          goto err;
> +#endif
> +
> +#ifdef CONFIG_ARM_64
> +    /* Map first level table */
> +    first = map_domain_page(pte.p2m.base);
> +#endif

Can you move the code in this ifdef into the first one?

[..]

> @@ -244,8 +294,14 @@ static int apply_p2m_changes(struct domain *d,
>      struct p2m_domain *p2m = &d->arch.p2m;
>      lpae_t *first = NULL, *second = NULL, *third = NULL;
>      paddr_t addr;
> -    unsigned long cur_first_page = ~0,
> -                  cur_first_offset = ~0,
> +#ifdef CONFIG_ARM_64
> +    lpae_t *zeroeth = NULL;
> +    unsigned long cur_zeroeth_page = ~0,
> +                  cur_zeroeth_offset = ~0;
> +#else
> +    unsigned long cur_first_page = ~0;
> +#endif
> +    unsigned long cur_first_offset = ~0,
>                    cur_second_offset = ~0;
>      unsigned long count = 0;
>      unsigned int flush = 0;
> @@ -260,6 +316,37 @@ static int apply_p2m_changes(struct domain *d,
>      addr = start_gpaddr;
>      while ( addr < end_gpaddr )
>      {
> +#ifdef CONFIG_ARM_64
> +        /* Find zeoeth offset and Map zeroeth page */
> +        if ( cur_zeroeth_page != zeroeth_table_offset(addr) )
> +        {
> +            if ( zeroeth ) unmap_domain_page(zeroeth);
> +            zeroeth = p2m_map_zeroeth(p2m, addr);
> +            if ( !zeroeth )
> +            {
> +                rc = -EINVAL;
> +                goto out;
> +            }
> +            cur_zeroeth_page = zeroeth_table_offset(addr);
> +        }
> +
> +        if ( !zeroeth[zeroeth_table_offset(addr)].p2m.valid )
> +        {
> +            if ( !populate )
> +            {
> +                addr = (addr + ZEROETH_SIZE) & ZEROETH_MASK;
> +                continue;
> +            }
> +            rc = p2m_create_table(d, &zeroeth[zeroeth_table_offset(addr)]);
> +            if ( rc < 0 )
> +            {
> +                printk("p2m_populate_ram: L0 failed\n");
> +                goto out;
> +            }
> +        } 
> +
> +        BUG_ON(!zeroeth[zeroeth_table_offset(addr)].p2m.valid);
> +#else
>          if ( cur_first_page != p2m_first_level_index(addr) )
>          {
>              if ( first ) unmap_domain_page(first);
> @@ -271,7 +358,16 @@ static int apply_p2m_changes(struct domain *d,
>              }
>              cur_first_page = p2m_first_level_index(addr);
>          }
> +#endif
>  
> +#ifdef CONFIG_ARM_64
> +        if ( cur_zeroeth_offset != zeroeth_table_offset(addr) )
> +        {
> +            if ( first ) unmap_domain_page(first);
> +            first = 
> map_domain_page(zeroeth[zeroeth_table_offset(addr)].p2m.base);
> +            cur_zeroeth_offset = zeroeth_table_offset(addr);
> +        }
> +#endif

Same remark here.

>          if ( !first[first_table_offset(addr)].p2m.valid )
>          {
>              if ( !populate )
> @@ -279,7 +375,6 @@ static int apply_p2m_changes(struct domain *d,
>                  addr = (addr + FIRST_SIZE) & FIRST_MASK;
>                  continue;
>              }
> -

Why did you remove this empty line?

>              rc = p2m_create_table(d, &first[first_table_offset(addr)]);
>              if ( rc < 0 )
>              {
> @@ -287,7 +382,6 @@ static int apply_p2m_changes(struct domain *d,
>                  goto out;
>              }
>          }
> -

Same here.

>          BUG_ON(!first[first_table_offset(addr)].p2m.valid);
>  
>          if ( cur_first_offset != first_table_offset(addr) )
> @@ -305,7 +399,6 @@ static int apply_p2m_changes(struct domain *d,
>                  addr = (addr + SECOND_SIZE) & SECOND_MASK;
>                  continue;
>              }
> -

Same here.

[..]

>      /* Current VMID in use */
>      uint8_t vmid;
> diff --git a/xen/include/asm-arm/page.h b/xen/include/asm-arm/page.h
> index 905beb8..8477206 100644
> --- a/xen/include/asm-arm/page.h
> +++ b/xen/include/asm-arm/page.h
> @@ -6,12 +6,13 @@
>  #include <public/xen.h>
>  #include <asm/processor.h>
>  
> +#ifdef CONFIG_ARM_64
> +#define PADDR_BITS              48
> +#else
>  #define PADDR_BITS              40
> +#endif
>  #define PADDR_MASK              ((1ULL << PADDR_BITS)-1)
>  
> -#define VADDR_BITS              32
> -#define VADDR_MASK              (~0UL)
> -

Why did you remove VADDR_{BITS,MASK}?

> +#ifdef CONFIG_ARM_64
> +/* 48 bit VA to 48 bit PA */

[..]

> +/* 40 bit VA to 40 bit PA */

[..]

> +/* 40 bit VA to 32 bit PA */

Did you mean IPA instead of VA?

Also, on ARM, the PA is encoded with 40 bits.

[..]

>  
> -    unsigned long pad1:24;
> +    //unsigned long pad1:24;

This line should be removed rather than comment.

> +    unsigned long pad1:16;
>  } lpae_walk_t;
>  
>  typedef union {
> diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h
> index 06e638f..1355d81 100644
> --- a/xen/include/asm-arm/processor.h
> +++ b/xen/include/asm-arm/processor.h
> @@ -173,9 +173,21 @@ struct cpuinfo_arm {
>          uint64_t bits[2];
>      } aux64;
>  
> -    struct {
> +    union {
>          uint64_t bits[2];
> +        struct {
> +            unsigned long pa_range:4;
> +            unsigned long asid_bits:4;
> +            unsigned long bigend:4;
> +            unsigned long secure_ns:4;
> +            unsigned long bigend_el0:4;
> +            unsigned long tgranule_16K:4;
> +            unsigned long tgranule_64K:4;
> +            unsigned long tgranule_4K:4;
> +            unsigned long __res0:32;
> +       };
>      } mm64;
> +    

Spurious line.

>  
>      struct {
>          uint64_t bits[2];
> 

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®.