Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);
+25 −11
Original line number Original line Diff line number Diff line
@@ -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,
/*
/*
 * 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,
	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,
		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,
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
		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,
	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;
}
}