Commit 67ce16ec authored by Kristina Martsenko's avatar Kristina Martsenko Committed by Will Deacon

arm64: mm: print out correct page table entries

When we take a fault that can't be handled, we print out the page table
entries associated with the faulting address. In some cases we currently
print out the wrong entries. For a faulting TTBR1 address, we sometimes
print out TTBR0 table entries instead, and for a faulting TTBR0 address
we sometimes print out TTBR1 table entries. Fix this by choosing the
tables based on the faulting address.
Acked-by: default avatarMark Rutland <mark.rutland@arm.com>
Signed-off-by: default avatarKristina Martsenko <kristina.martsenko@arm.com>
[will: zero-extend addrs to 64-bit, don't walk swapper w/ TTBR0 addr]
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent e71a4e1b
...@@ -40,7 +40,7 @@ void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int, ...@@ -40,7 +40,7 @@ void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
int sig, int code, const char *name); int sig, int code, const char *name);
struct mm_struct; struct mm_struct;
extern void show_pte(struct mm_struct *mm, unsigned long addr); extern void show_pte(unsigned long addr);
extern void __show_regs(struct pt_regs *); extern void __show_regs(struct pt_regs *);
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
......
...@@ -80,18 +80,33 @@ static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr) ...@@ -80,18 +80,33 @@ static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
#endif #endif
/* /*
* Dump out the page tables associated with 'addr' in mm 'mm'. * Dump out the page tables associated with 'addr' in the currently active mm.
*/ */
void show_pte(struct mm_struct *mm, unsigned long addr) void show_pte(unsigned long addr)
{ {
struct mm_struct *mm;
pgd_t *pgd; pgd_t *pgd;
if (!mm) if (addr < TASK_SIZE) {
/* TTBR0 */
mm = current->active_mm;
if (mm == &init_mm) {
pr_alert("[%016lx] user address but active_mm is swapper\n",
addr);
return;
}
} else if (addr >= VA_START) {
/* TTBR1 */
mm = &init_mm; mm = &init_mm;
} else {
pr_alert("[%016lx] address between user and kernel address ranges\n",
addr);
return;
}
pr_alert("pgd = %p\n", mm->pgd); pr_alert("pgd = %p\n", mm->pgd);
pgd = pgd_offset(mm, addr); pgd = pgd_offset(mm, addr);
pr_alert("[%08lx] *pgd=%016llx", addr, pgd_val(*pgd)); pr_alert("[%016lx] *pgd=%016llx", addr, pgd_val(*pgd));
do { do {
pud_t *pud; pud_t *pud;
...@@ -196,8 +211,8 @@ static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs, ...@@ -196,8 +211,8 @@ static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs,
/* /*
* The kernel tried to access some page that wasn't present. * The kernel tried to access some page that wasn't present.
*/ */
static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, static void __do_kernel_fault(unsigned long addr, unsigned int esr,
unsigned int esr, struct pt_regs *regs) struct pt_regs *regs)
{ {
const char *msg; const char *msg;
...@@ -227,7 +242,7 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, ...@@ -227,7 +242,7 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
pr_alert("Unable to handle kernel %s at virtual address %08lx\n", msg, pr_alert("Unable to handle kernel %s at virtual address %08lx\n", msg,
addr); addr);
show_pte(mm, addr); show_pte(addr);
die("Oops", regs, esr); die("Oops", regs, esr);
bust_spinlocks(0); bust_spinlocks(0);
do_exit(SIGKILL); do_exit(SIGKILL);
...@@ -249,7 +264,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr, ...@@ -249,7 +264,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
pr_info("%s[%d]: unhandled %s (%d) at 0x%08lx, esr 0x%03x\n", pr_info("%s[%d]: unhandled %s (%d) at 0x%08lx, esr 0x%03x\n",
tsk->comm, task_pid_nr(tsk), inf->name, sig, tsk->comm, task_pid_nr(tsk), inf->name, sig,
addr, esr); addr, esr);
show_pte(tsk->mm, addr); show_pte(addr);
__show_regs(regs); __show_regs(regs);
} }
...@@ -265,7 +280,6 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr, ...@@ -265,7 +280,6 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs) static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct mm_struct *mm = tsk->active_mm;
const struct fault_info *inf; const struct fault_info *inf;
/* /*
...@@ -276,7 +290,7 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re ...@@ -276,7 +290,7 @@ static void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *re
inf = esr_to_fault_info(esr); inf = esr_to_fault_info(esr);
__do_user_fault(tsk, addr, esr, inf->sig, inf->code, regs); __do_user_fault(tsk, addr, esr, inf->sig, inf->code, regs);
} else } else
__do_kernel_fault(mm, addr, esr, regs); __do_kernel_fault(addr, esr, regs);
} }
#define VM_FAULT_BADMAP 0x010000 #define VM_FAULT_BADMAP 0x010000
...@@ -475,7 +489,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, ...@@ -475,7 +489,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
return 0; return 0;
no_context: no_context:
__do_kernel_fault(mm, addr, esr, regs); __do_kernel_fault(addr, esr, regs);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment