summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2012-04-19 08:25:03 (GMT)
committerPaul Mundt <lethal@linux-sh.org>2012-04-19 08:25:03 (GMT)
commit45c0e0e25eae2c5e8bb9e2dfaf73afb396e0928d (patch)
treed28db9a7ec6225746689b43f11b94733fe0b89db
parent8d9a784d1e2c75e0dcae06f77a02f5e7bb547f3a (diff)
downloadlinux-fsl-qoriq-45c0e0e25eae2c5e8bb9e2dfaf73afb396e0928d.tar.xz
sh: Improve oops error reporting
In some cases the opps error reporting doesn't give enough information to diagnose the problem, only printing information if it is thought to be valid. Replace the current code with more detailed output. This code is based on the ARM reporting, with minor changes for the SH. [lethal@linux-sh.org: fixed up for 64-bit PTEs and pte_offset_kernel()] Signed-off-by: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/mm/fault_32.c97
1 files changed, 74 insertions, 23 deletions
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
index e99b104..c5cd878 100644
--- a/arch/sh/mm/fault_32.c
+++ b/arch/sh/mm/fault_32.c
@@ -35,6 +35,74 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap)
return ret;
}
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+static void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+
+ if (mm)
+ pgd = mm->pgd;
+ else
+ pgd = get_TTB();
+
+ printk(KERN_ALERT "pgd = %p\n", pgd);
+ pgd += pgd_index(addr);
+ printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr,
+ sizeof(*pgd) * 2, (u64)pgd_val(*pgd));
+
+ do {
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (pgd_none(*pgd))
+ break;
+
+ if (pgd_bad(*pgd)) {
+ printk("(bad)");
+ break;
+ }
+
+ pud = pud_offset(pgd, addr);
+ if (PTRS_PER_PUD != 1)
+ printk(", *pud=%0*Lx", sizeof(*pud) * 2,
+ (u64)pud_val(*pud));
+
+ if (pud_none(*pud))
+ break;
+
+ if (pud_bad(*pud)) {
+ printk("(bad)");
+ break;
+ }
+
+ pmd = pmd_offset(pud, addr);
+ if (PTRS_PER_PMD != 1)
+ printk(", *pmd=%0*Lx", sizeof(*pmd) * 2,
+ (u64)pmd_val(*pmd));
+
+ if (pmd_none(*pmd))
+ break;
+
+ if (pmd_bad(*pmd)) {
+ printk("(bad)");
+ break;
+ }
+
+ /* We must not map this if we have highmem enabled */
+ if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
+ break;
+
+ pte = pte_offset_kernel(pmd, addr);
+ printk(", *pte=%0*Lx", sizeof(*pte) * 2, (u64)pte_val(*pte));
+ } while (0);
+
+ printk("\n");
+}
+
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
unsigned index = pgd_index(address);
@@ -254,29 +322,12 @@ no_context:
bust_spinlocks(1);
if (oops_may_print()) {
- unsigned long page;
-
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL "
- "pointer dereference");
- else
- printk(KERN_ALERT "Unable to handle kernel paging "
- "request");
- printk(" at virtual address %08lx\n", address);
- printk(KERN_ALERT "pc = %08lx\n", regs->pc);
- page = (unsigned long)get_TTB();
- if (page) {
- page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT];
- printk(KERN_ALERT "*pde = %08lx\n", page);
- if (page & _PAGE_PRESENT) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((__typeof__(page) *)
- __va(page))[address >>
- PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
- }
- }
+ printk(KERN_ALERT
+ "Unable to handle kernel %s at virtual address %08lx\n",
+ (address < PAGE_SIZE) ? "NULL pointer dereference" :
+ "paging request", address);
+
+ show_pte(mm, address);
}
die("Oops", regs, writeaccess);