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: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Kristina Martsenko <kristina.martsenko@arm.com>
[will: zero-extend addrs to 64-bit, don't walk swapper w/ TTBR0 addr]
Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
Kristina Martsenko 2017-06-09 16:35:52 +01:00 committed by Will Deacon
parent e71a4e1beb
commit 67ce16ec15
2 changed files with 26 additions and 12 deletions

View File

@ -40,7 +40,7 @@ void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
int sig, int code, const char *name);
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 (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);

View File

@ -80,18 +80,33 @@ static inline int notify_page_fault(struct pt_regs *regs, unsigned int esr)
#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;
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;
} else {
pr_alert("[%016lx] address between user and kernel address ranges\n",
addr);
return;
}
pr_alert("pgd = %p\n", mm->pgd);
pgd = pgd_offset(mm, addr);
pr_alert("[%08lx] *pgd=%016llx", addr, pgd_val(*pgd));
pr_alert("[%016lx] *pgd=%016llx", addr, pgd_val(*pgd));
do {
pud_t *pud;
@ -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.
*/
static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
unsigned int esr, struct pt_regs *regs)
static void __do_kernel_fault(unsigned long addr, unsigned int esr,
struct pt_regs *regs)
{
const char *msg;
@ -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,
addr);
show_pte(mm, addr);
show_pte(addr);
die("Oops", regs, esr);
bust_spinlocks(0);
do_exit(SIGKILL);
@ -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",
tsk->comm, task_pid_nr(tsk), inf->name, sig,
addr, esr);
show_pte(tsk->mm, addr);
show_pte(addr);
__show_regs(regs);
}
@ -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)
{
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->active_mm;
const struct fault_info *inf;
/*
@ -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);
__do_user_fault(tsk, addr, esr, inf->sig, inf->code, regs);
} else
__do_kernel_fault(mm, addr, esr, regs);
__do_kernel_fault(addr, esr, regs);
}
#define VM_FAULT_BADMAP 0x010000
@ -475,7 +489,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
return 0;
no_context:
__do_kernel_fault(mm, addr, esr, regs);
__do_kernel_fault(addr, esr, regs);
return 0;
}