This patch adds support for processing ARM kernel crashdumps as well.

Signed-off-by: Mika Westerberg <[email protected]>
---
 Makefile       |    4 +-
 arm.c          |  200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 makedumpfile.h |   33 +++++++++
 3 files changed, 235 insertions(+), 2 deletions(-)
 create mode 100644 arm.c

diff --git a/Makefile b/Makefile
index 4a8a060..3d2ee34 100644
--- a/Makefile
+++ b/Makefile
@@ -23,8 +23,8 @@ CFLAGS_ARCH += -m64
 endif
 
 SRC    = makedumpfile.c makedumpfile.h diskdump_mod.h
-SRC_ARCH = x86.c x86_64.c ia64.c ppc64.c
-OBJ_ARCH = x86.o x86_64.o ia64.o ppc64.o
+SRC_ARCH = arm.c x86.c x86_64.c ia64.c ppc64.c
+OBJ_ARCH = arm.o x86.o x86_64.o ia64.o ppc64.o
 
 all: makedumpfile
 
diff --git a/arm.c b/arm.c
new file mode 100644
index 0000000..5acad78
--- /dev/null
+++ b/arm.c
@@ -0,0 +1,200 @@
+/*
+ * arm.c
+ *
+ * Created by: Mika Westerberg <[email protected]>
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifdef __arm__
+
+#include "makedumpfile.h"
+
+#define PMD_TYPE_MASK  3
+#define PMD_TYPE_SECT  2
+#define PMD_TYPE_TABLE 1
+
+#define pgd_index(vaddr) ((vaddr) >> PGDIR_SHIFT)
+#define pte_index(vaddr) ((vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
+
+#define pgd_offset(pgdir, vaddr) \
+       ((pgdir) + pgd_index(vaddr) * 2 * sizeof(unsigned long))
+#define pmd_offset(dir, vaddr) (dir)
+#define pte_offset(pmd, vaddr) \
+       (pmd_page_vaddr(pmd) + pte_index(vaddr) * sizeof(unsigned long))
+
+/*
+ * These only work for kernel directly mapped addresses.
+ */
+#define __va(paddr) ((paddr) - info->phys_base + info->page_offset)
+#define __pa(vaddr) ((vaddr) - info->page_offset + info->phys_base)
+
+static inline unsigned long
+pmd_page_vaddr(unsigned long pmd)
+{
+       unsigned long ptr;
+
+       ptr = pmd & ~(PTRS_PER_PTE * sizeof(void *) - 1);
+       ptr += PTRS_PER_PTE * sizeof(void *);
+
+       return __va(ptr);
+}
+
+int
+get_phys_base_arm(void)
+{
+       unsigned long phys_base = ULONG_MAX;
+       int i;
+
+       /*
+        * We resolve phys_base from PT_LOAD segments. LMA contains physical
+        * address of the segment, and we use the first one.
+        */
+       for (i = 0; i < info->num_load_memory; i++) {
+               const struct pt_load_segment *pls = &info->pt_load_segments[i];
+
+               if (pls->phys_start < phys_base)
+                       phys_base = pls->phys_start;
+       }
+
+       if (phys_base == ULONG_MAX) {
+               ERRMSG("Can't determine phys_base.\n");
+               return FALSE;
+       }
+
+       info->phys_base = phys_base;
+       DEBUG_MSG("phys_base    : %lx\n", phys_base);
+
+       return TRUE;
+}
+
+int
+get_machdep_info_arm(void)
+{
+       unsigned long vmlist, vmalloc_start;
+
+       info->page_offset = __PAGE_OFFSET;
+       info->max_physmem_bits = _MAX_PHYSMEM_BITS;
+       info->kernel_start = SYMBOL(_stext);
+       info->section_size_bits = _SECTION_SIZE_BITS;
+
+       /*
+        * For the compatibility, makedumpfile should run without the symbol
+        * vmlist and the offset of vm_struct.addr if they are not necessary.
+        */
+       if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL) ||
+               OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE) {
+               return TRUE;
+       }
+
+       if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) {
+               ERRMSG("Can't get vmlist.\n");
+               return FALSE;
+       }
+       if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start,
+                    sizeof(vmalloc_start))) {
+               ERRMSG("Can't get vmalloc_start.\n");
+               return FALSE;
+       }
+
+       info->vmalloc_start = vmalloc_start;
+
+       DEBUG_MSG("page_offset  : %lx\n", info->page_offset);
+       DEBUG_MSG("kernel_start : %lx\n", info->kernel_start);
+       DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start);
+
+       return TRUE;
+}
+
+static int
+is_vmalloc_addr_arm(unsigned long vaddr)
+{
+       return (info->vmalloc_start && vaddr >= info->vmalloc_start);
+}
+
+/*
+ * vtop_arm() - translate arbitrary virtual address to physical
+ * @vaddr: virtual address to translate
+ *
+ * Function translates @vaddr into physical address using page tables. This
+ * address can be any virtual address. Returns physical address of the
+ * corresponding virtual address or %NOT_PADDR when there is no translation.
+ */
+static unsigned long long
+vtop_arm(unsigned long vaddr)
+{
+       unsigned long long paddr = NOT_PADDR;
+       unsigned long ptr, pgd, pte, pmd;
+
+       if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
+               ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
+               return NOT_PADDR;
+       }
+
+       ptr = pgd_offset(SYMBOL(swapper_pg_dir), vaddr);
+       if (!readmem(VADDR, ptr, &pgd, sizeof(pmd))) {
+               ERRMSG("Can't read pgd\n");
+               return NOT_PADDR;
+       }
+
+       if (info->vaddr_for_vtop == vaddr)
+               MSG("  PGD : %08lx => %08lx\n", ptr, pgd);
+
+       pmd = pmd_offset(pgd, vaddr);
+
+       switch (pmd & PMD_TYPE_MASK) {
+       case PMD_TYPE_TABLE: {
+               /* 4k small page */
+               ptr = pte_offset(pmd, vaddr);
+               if (!readmem(VADDR, ptr, &pte, sizeof(pte))) {
+                       ERRMSG("Can't read pte\n");
+                       return NOT_PADDR;
+               }
+
+               if (info->vaddr_for_vtop == vaddr)
+                       MSG("  PTE : %08lx => %08lx\n", ptr, pte);
+
+               if (!(pte & _PAGE_PRESENT)) {
+                       ERRMSG("Can't get a valid pte.\n");
+                       return NOT_PADDR;
+               }
+
+               paddr = PAGEBASE(pte) + (vaddr & (PAGESIZE() - 1));
+               break;
+       }
+
+       case PMD_TYPE_SECT:
+               /* 1MB section */
+               pte = pmd & PMD_MASK;
+               paddr = pte + (vaddr & (PMD_SIZE - 1));
+               break;
+       }
+
+       return paddr;
+}
+
+unsigned long long
+vaddr_to_paddr_arm(unsigned long vaddr)
+{
+       unsigned long long paddr;
+
+       if ((paddr = vaddr_to_paddr_general(vaddr)) != NOT_PADDR)
+               return paddr;
+
+       if (is_vmalloc_addr_arm(vaddr))
+               paddr = vtop_arm(vaddr);
+       else
+               paddr = __pa(vaddr);
+
+       return paddr;
+}
+
+#endif /* __arm__ */
diff --git a/makedumpfile.h b/makedumpfile.h
index 2717d81..8a74b34 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -506,6 +506,24 @@ do { \
 #define VMEMMAP_START          (info->vmemmap_start)
 #define VMEMMAP_END            (info->vmemmap_end)
 
+#ifdef __arm__
+#define __PAGE_OFFSET          (0xc0000000)
+#define KVBASE_MASK            (0xffff)
+#define KVBASE                 (SYMBOL(_stext) & ~KVBASE_MASK)
+#define _SECTION_SIZE_BITS     (28)
+#define _MAX_PHYSMEM_BITS      (32)
+#define ARCH_PFN_OFFSET                (info->phys_base >> PAGESHIFT())
+
+#define PTRS_PER_PTE           (512)
+#define PGDIR_SHIFT            (21)
+#define PMD_SHIFT              (21)
+#define PMD_SIZE               (1UL << PMD_SHIFT)
+#define PMD_MASK               (~(PMD_SIZE - 1))
+
+#define _PAGE_PRESENT          (1 << 0)
+
+#endif /* arm */
+
 #ifdef __x86__
 #define __PAGE_OFFSET          (0xc0000000)
 #define __VMALLOC_RESERVE       (128 << 20)
@@ -653,6 +671,16 @@ do { \
 /*
  * The function of dependence on machine
  */
+#ifdef __arm__
+int get_phys_base_arm(void);
+int get_machdep_info_arm(void);
+unsigned long long vaddr_to_paddr_arm(unsigned long vaddr);
+#define get_phys_base()                get_phys_base_arm()
+#define get_machdep_info()     get_machdep_info_arm()
+#define get_versiondep_info()  TRUE
+#define vaddr_to_paddr(X)      vaddr_to_paddr_arm(X)
+#endif /* arm */
+
 #ifdef __x86__
 int get_machdep_info_x86(void);
 int get_versiondep_info_x86(void);
@@ -1148,6 +1176,11 @@ struct domain_list {
 #define PAGES_PER_MAPWORD      (sizeof(unsigned long) * 8)
 #define MFNS_PER_FRAME         (info->page_size / sizeof(unsigned long))
 
+#ifdef __arm__
+#define kvtop_xen(X)   FALSE
+#define get_xen_info_arch(X) FALSE
+#endif /* arm */
+
 #ifdef __x86__
 #define HYPERVISOR_VIRT_START_PAE      (0xF5800000UL)
 #define HYPERVISOR_VIRT_START          (0xFC000000UL)
-- 
1.5.6.5


_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to