----- Original Message -----
> Hi Dave,
> 
> This patch introduces LPAE support for ARM32 platform.

Nicely done -- I appreciate your efforts!

I can only test that this doesn't affect non-PAE dumpfiles.
Would it be possible for you to create a sample vmcore and
make it available to me to download for future testing?

Thanks again,
  Dave


> 
> main description:
> 
> (1) identify LPAE enabled vmcores:
>       PG_DIR_SIZE(LPAE:20K,other:16K)
> 
> (2) section mapping size changed to 2MiB
> (3) virtual to physical address converting:
>    (a)
>       #define PTRS_PER_PTE            512
>       #define PTRS_PER_PMD            512
>       #define PTRS_PER_PGD            4
> 
>    (b) Each ptr are 8-bit long, so we need sevel new
>        macros to deal with them: FILL_PGD_LPAE ...
>    (c) arm_translate_pte changed as x86_translate_pte
>    (d) arm_lpae_vtop doing this converting
> 
> Signed-off-by: Wei Jitao <weiji...@huawei.com>
> Signed-off-by: Liu Hua <sdu....@huawei.com>
> ---
>  arm.c  | 134
>  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
>  defs.h |  77 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 200 insertions(+), 11 deletions(-)
> 
> diff --git a/arm.c b/arm.c
> index 84dd3ec..001fe6b 100644
> --- a/arm.c
> +++ b/arm.c
> @@ -83,6 +83,7 @@ static struct arm_pt_regs *panic_task_regs;
>  #define PMD_TYPE_MASK   3
>  #define PMD_TYPE_SECT   2
>  #define PMD_TYPE_TABLE  1
> +#define PMD_TYPE_SECT_LPAE 1
>  
>  static inline ulong *
>  pmd_page_addr(ulong pmd)
> @@ -219,12 +220,19 @@ arm_init(int when)
>       case PRE_GDB:
>               if ((machdep->pgd = (char *)malloc(PGDIR_SIZE())) == NULL)
>                       error(FATAL, "cannot malloc pgd space.");
> +             if ((machdep->pmd = (char *)malloc(PMDSIZE())) == NULL)
> +                     error(FATAL, "cannot malloc pmd space.");
>               if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
>                       error(FATAL, "cannot malloc ptbl space.");
>  
>               /*
> -              * Kernel text starts 16k after PAGE_OFFSET.
> +              *LPAE requires an additional page for the PGD;
> +              *So PG_DIR_SIZE =  0x5000 for LPAE
>                */
> +
> +             if (symbol_value("_text") - symbol_value("swapper_pg_dir")
> +                             == 0x5000)
> +                     machdep->flags |= PAE;
>               machdep->kvbase = symbol_value("_stext") & ~KVBASE_MASK;
>               machdep->identity_map_base = machdep->kvbase;
>               machdep->is_kvaddr = arm_is_kvaddr;
> @@ -269,9 +277,13 @@ arm_init(int when)
>               if (THIS_KERNEL_VERSION >= LINUX(3,3,0) ||
>                   symbol_exists("idmap_pgd"))
>                       machdep->flags |= IDMAP_PGD;
> -
> -             machdep->section_size_bits = _SECTION_SIZE_BITS;
> -             machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
> +             if (machdep->flags & PAE) {
> +                     machdep->section_size_bits = _SECTION_SIZE_BITS_LPAE;
> +                     machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_LPAE;
> +             } else {
> +                     machdep->section_size_bits = _SECTION_SIZE_BITS;
> +                     machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
> +             }
>  
>               if (symbol_exists("irq_desc"))
>                       ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
> @@ -834,24 +846,32 @@ arm_processor_speed(void)
>   * is passed in, don't print anything.
>   */
>  static int
> -arm_translate_pte(ulong pte, void *physaddr, ulonglong pae_pte)
> +arm_translate_pte(ulong pte, void *physaddr, ulonglong lpae_pte)
>  {
>       char ptebuf[BUFSIZE];
>       char physbuf[BUFSIZE];
>       char buf[BUFSIZE];
>       int page_present;
> -     ulong paddr;
> +     ulonglong paddr;
>       int len1, len2, others;
>  
> +     if (machdep->flags & PAE) {
> +             paddr = LPAE_PAGEBASE(lpae_pte);
> +             sprintf(ptebuf, "%llx", lpae_pte);
> +             pte = (ulong)lpae_pte;
> +     } else {
> +             paddr = PAGEBASE(pte);
> +             sprintf(ptebuf, "%lx", pte);
> +     }
>       page_present = pte_present(pte);
> -     paddr = PAGEBASE(pte);
> -
>       if (physaddr) {
> -             *((ulong *)physaddr) = paddr;
> +             if (machdep->flags & PAE)
> +                     *((ulonglong *)physaddr) = paddr;
> +             else
> +                     *((ulong *)physaddr) = (ulong)paddr;
>               return page_present;
>       }
>  
> -     sprintf(ptebuf, "%lx", pte);
>       len1 = MAX(strlen(ptebuf), strlen("PTE"));
>       fprintf(fp, "%s  ", mkstring(buf, len1, CENTER | LJUST, "PTE"));
>  
> @@ -860,7 +880,7 @@ arm_translate_pte(ulong pte, void *physaddr, ulonglong
> pae_pte)
>               return page_present;
>       }
>  
> -     sprintf(physbuf, "%lx", paddr);
> +     sprintf(physbuf, "%llx", paddr);
>       len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
>       fprintf(fp, "%s  ", mkstring(buf, len2, CENTER | LJUST, "PHYSICAL"));
>  
> @@ -1049,6 +1069,91 @@ arm_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr,
> int verbose)
>  }
>  
>  /*
> + *Virtual to physical memory translation when "CONFIG_ARM_LPAE=y".
> + *This function will be called by both arm_kvtop() and arm_uvtop().
> + */
> +static int
> +arm_lpae_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr, int verbose)
> +{
> +     char buf[BUFSIZE];
> +     physaddr_t page_dir;
> +     physaddr_t page_middle;
> +     physaddr_t page_table;
> +     pgd_t pgd_pmd;
> +     pmd_t pmd_pte;
> +     pte_t pte;
> +
> +     if (verbose)
> +             fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
> +
> +     /*
> +      * pgd_offset(pgd, vaddr)
> +      */
> +     page_dir = LPAE_VTOP((ulong)pgd + LPAE_PGD_OFFSET(vaddr) * 8);
> +     FILL_PGD_LPAE(LPAE_VTOP(pgd), PHYSADDR, LPAE_PGDIR_SIZE());
> +     pgd_pmd = ULONGLONG(machdep->pgd + LPAE_PGDIR_OFFSET(page_dir));
> +
> +     if (verbose)
> +             fprintf(fp, "  PGD: %8llx => %llx\n",
> +                             (ulonglong)page_dir, pgd_pmd);
> +
> +     if (!pgd_pmd)
> +             return FALSE;
> +
> +     /*
> +      * pmd_offset(pgd, vaddr)
> +      */
> +     page_middle = LPAE_PAGEBASE(pgd_pmd) + LPAE_PMD_OFFSET(vaddr) * 8;
> +     FILL_PMD_LPAE(LPAE_PAGEBASE(pgd_pmd), PHYSADDR, LPAE_PMDIR_SIZE());
> +     pmd_pte = ULONGLONG(machdep->pmd + LPAE_PMDIR_OFFSET(page_middle));
> +
> +     if (!pmd_pte)
> +             return FALSE;
> +
> +     if ((pmd_pte & PMD_TYPE_MASK) == PMD_TYPE_SECT_LPAE) {
> +             ulonglong sectionbase = LPAE_PAGEBASE(pmd_pte)
> +                                     & LPAE_SECTION_PAGE_MASK;
> +
> +             if (verbose) {
> +                             fprintf(fp, " PAGE: %8llx  (2MB)\n\n",
> +                                     (ulonglong)sectionbase);
> +             }
> +
> +             *paddr = sectionbase + (vaddr & ~LPAE_SECTION_PAGE_MASK);
> +             return TRUE;
> +     }
> +     /*
> +      * pte_offset_map(pmd, vaddr)
> +      */
> +     page_table = LPAE_PAGEBASE(pmd_pte) + PTE_OFFSET(vaddr) * 8;
> +     FILL_PTBL_LPAE(LPAE_PAGEBASE(pmd_pte), PHYSADDR, LPAE_PTEDIR_SIZE());
> +     pte = ULONGLONG(machdep->ptbl + LPAE_PTEDIR_OFFSET(page_table));
> +
> +     if (verbose) {
> +             fprintf(fp, "  PTE: %8llx => %llx\n\n",
> +                     (ulonglong)page_table, pte);
> +     }
> +
> +     if (!pte_present(pte)) {
> +             if (pte && verbose) {
> +                     fprintf(fp, "\n");
> +                     arm_translate_pte(0, 0, pte);
> +             }
> +             return FALSE;
> +     }
> +
> +     *paddr = LPAE_PAGEBASE(pte) + PAGEOFFSET(vaddr);
> +
> +     if (verbose) {
> +             fprintf(fp, " PAGE: %s\n\n",
> +             mkstring(buf, VADDR_PRLEN, RJUST | LONG_HEX,
> +                                     MKSTR(PAGEBASE(pte))));
> +             arm_translate_pte(0, 0, pte);
> +     }
> +     return TRUE;
> +}
> +
> +/*
>   * Translates a user virtual address to its physical address. cmd_vtop()
>   sets
>   * the verbose flag so that the pte translation gets displayed; all other
>   * callers quietly accept the translation.
> @@ -1098,6 +1203,9 @@ arm_uvtop(struct task_context *tc, ulong uvaddr,
> physaddr_t *paddr, int verbose)
>                               FAULT_ON_ERROR);
>       }
>  
> +     if (machdep->flags & PAE)
> +             return arm_lpae_vtop(uvaddr, pgd, paddr, verbose);
> +
>       return arm_vtop(uvaddr, pgd, paddr, verbose);
>  }
>  
> @@ -1123,6 +1231,10 @@ arm_kvtop(struct task_context *tc, ulong kvaddr,
> physaddr_t *paddr, int verbose)
>                       return TRUE;
>       }
>  
> +     if (machdep->flags & PAE)
> +             return arm_lpae_vtop(kvaddr,
> +                             (ulong *)vt->kernel_pgd[0], paddr, verbose);
> +
>       return arm_vtop(kvaddr, (ulong *)vt->kernel_pgd[0], paddr, verbose);
>  }
>  
> diff --git a/defs.h b/defs.h
> index 0ae4e48..44df6ae 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2647,6 +2647,80 @@ struct load_module {
>  #define _SECTION_SIZE_BITS   28
>  #define _MAX_PHYSMEM_BITS    32
>  
> +/*add for LPAE*/
> +typedef unsigned long long u64;
> +typedef signed int         s32;
> +typedef u64 pgd_t;
> +typedef u64 pmd_t;
> +typedef u64 pte_t;
> +
> +#define PMDSIZE()            (PAGESIZE())
> +#define LPAE_PGDIR_SHIFT     (30)
> +#define LPAE_PMDIR_SHIFT     (21)
> +
> +#define LPAE_PGD_OFFSET(vaddr)  ((vaddr) >> LPAE_PGDIR_SHIFT)
> +#define LPAE_PMD_OFFSET(vaddr)  (((vaddr) >> LPAE_PMDIR_SHIFT) & \
> +                             ((1<<(LPAE_PGDIR_SHIFT-LPAE_PMDIR_SHIFT))-1))
> +
> +#define _SECTION_SIZE_BITS_LPAE      28
> +#define _MAX_PHYSMEM_BITS_LPAE       36
> +
> +/*
> + * #define PTRS_PER_PTE            512
> + * #define PTRS_PER_PMD            512
> + * #define PTRS_PER_PGD            4
> + *
> + */
> +
> +#define LPAE_PGDIR_SIZE()    32
> +#define LPAE_PGDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PGDIR_SIZE() - 1))
> +
> +#define LPAE_PMDIR_SIZE()    4096
> +#define LPAE_PMDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PMDIR_SIZE() - 1))
> +
> +#define LPAE_PTEDIR_SIZE()   4096
> +#define LPAE_PTEDIR_OFFSET(X)        (((ulong)(X)) & (LPAE_PTEDIR_SIZE() - 
> 1))
> +
> +/*section size for LPAE is 2MiB*/
> +#define LPAE_SECTION_PAGE_MASK       (~((MEGABYTES(2))-1))
> +
> +#define _PHYSICAL_MASK_LPAE         ((1ULL << _MAX_PHYSMEM_BITS_LPAE) - 1)
> +#define PAGE_BASE_MASK    ((u64)((s32)machdep->pagemask &
> _PHYSICAL_MASK_LPAE))
> +#define LPAE_PAGEBASE(X)                (((ulonglong)(X)) & PAGE_BASE_MASK)
> +
> +#define LPAE_VTOP(X) \
> +     ((unsigned long long)(unsigned long)(X) - \
> +                     (machdep->kvbase) + (machdep->machspec->phys_base))
> +
> +#define IS_LAST_PGD_READ_LPAE(pgd)     ((pgd) == \
> +                                     machdep->machspec->last_pgd_read_lpae)
> +#define IS_LAST_PMD_READ_LPAE(pmd)     ((pmd) == \
> +                                     machdep->machspec->last_pmd_read_lpae)
> +#define IS_LAST_PTBL_READ_LPAE(ptbl)   ((ptbl) == \
> +                                     machdep->machspec->last_ptbl_read_lpae)
> +
> +#define FILL_PGD_LPAE(PGD, TYPE, SIZE)                                       
>     \
> +     if (!IS_LAST_PGD_READ_LPAE(PGD)) {                                  \
> +             readmem((ulonglong)(PGD), TYPE, machdep->pgd,               \
> +                     SIZE, "pmd page", FAULT_ON_ERROR);                   \
> +             machdep->machspec->last_pgd_read_lpae \
> +                                             = (ulonglong)(PGD);        \
> +     }
> +#define FILL_PMD_LPAE(PMD, TYPE, SIZE)                                       
>     \
> +     if (!IS_LAST_PMD_READ_LPAE(PMD)) {                                  \
> +             readmem((ulonglong)(PMD), TYPE, machdep->pmd,               \
> +                     SIZE, "pmd page", FAULT_ON_ERROR);                  \
> +             machdep->machspec->last_pmd_read_lpae \
> +                                             = (ulonglong)(PMD);        \
> +     }
> +
> +#define FILL_PTBL_LPAE(PTBL, TYPE, SIZE)                                 \
> +     if (!IS_LAST_PTBL_READ_LPAE(PTBL)) {                                \
> +             readmem((ulonglong)(PTBL), TYPE, machdep->ptbl,              \
> +                     SIZE, "page table", FAULT_ON_ERROR);                 \
> +             machdep->machspec->last_ptbl_read_lpae \
> +                                             = (ulonglong)(PTBL);        \
> +     }
>  #endif  /* ARM */
>  
>  #ifndef EM_AARCH64
> @@ -4979,6 +5053,9 @@ struct machine_specific {
>       ulong kernel_text_end;
>       ulong exception_text_start;
>       ulong exception_text_end;
> +     ulonglong last_pgd_read_lpae;
> +     ulonglong last_pmd_read_lpae;
> +     ulonglong last_ptbl_read_lpae;
>       struct arm_pt_regs *crash_task_regs;
>       int unwind_index_prel31;
>  };
> --
> 1.9.0
> 
> 

--
Crash-utility mailing list
Crash-utility@redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to