|
@@ -0,0 +1,115 @@
|
|
|
+/*
|
|
|
+ * linux/arch/arm/mm/fault.c
|
|
|
+ *
|
|
|
+ * Copyright (C) 1995 Linus Torvalds
|
|
|
+ * Modifications for ARM processor (c) 1995-2004 Russell King
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ */
|
|
|
+#include <linux/module.h>
|
|
|
+#include <linux/signal.h>
|
|
|
+#include <linux/mm.h>
|
|
|
+#include <linux/hardirq.h>
|
|
|
+#include <linux/init.h>
|
|
|
+#include <linux/kprobes.h>
|
|
|
+#include <linux/uaccess.h>
|
|
|
+#include <linux/page-flags.h>
|
|
|
+#include <linux/sched.h>
|
|
|
+#include <linux/highmem.h>
|
|
|
+#include <linux/perf_event.h>
|
|
|
+
|
|
|
+#include <asm/exception.h>
|
|
|
+#include <asm/pgtable.h>
|
|
|
+#include <asm/system_misc.h>
|
|
|
+#include <asm/system_info.h>
|
|
|
+#include <asm/tlbflush.h>
|
|
|
+
|
|
|
+#include "fault.h"
|
|
|
+
|
|
|
+#ifdef CONFIG_MMU
|
|
|
+
|
|
|
+#ifdef CONFIG_KPROBES
|
|
|
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (!user_mode(regs)) {
|
|
|
+ /* kprobe_running() needs smp_processor_id() */
|
|
|
+ preempt_disable();
|
|
|
+ if (kprobe_running() && kprobe_fault_handler(regs, fsr))
|
|
|
+ ret = 1;
|
|
|
+ preempt_enable();
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline int notify_page_fault(struct pt_regs *regs, unsigned int fsr)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/*
|
|
|
+ * This is useful to dump out the page tables associated with
|
|
|
+ * 'addr' in mm 'mm'.
|
|
|
+ */
|
|
|
+void show_pte(struct mm_struct *mm, unsigned long addr)
|
|
|
+{
|
|
|
+ pgd_t *pgd;
|
|
|
+
|
|
|
+ if (!mm)
|
|
|
+ mm = &init_mm;
|
|
|
+
|
|
|
+ printk(KERN_ALERT "pgd = %p\n", mm->pgd);
|
|
|
+ pgd = pgd_offset(mm, addr);
|
|
|
+ printk(KERN_ALERT "[%08lx] *pgd=%08llx",
|
|
|
+ addr, (long long)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=%08llx", (long long)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=%08llx", (long long)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_map(pmd, addr);
|
|
|
+ printk(", *pte=%08llx", (long long)pte_val(*pte));
|
|
|
+#ifndef CONFIG_ARM_LPAE
|
|
|
+ printk(", *ppte=%08llx",
|