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

Commit f7b8156d authored by Catalin Marinas's avatar Catalin Marinas
Browse files

ARM: LPAE: Add fault handling support



The DFSR and IFSR register format is different when LPAE is enabled. In
addition, DFSR and IFSR have similar definitions for the fault type.
This modifies the fault code to correctly handle the new format.

Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent c9f27f10
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -80,6 +80,14 @@ struct siginfo;
void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
		unsigned long err, unsigned long trap);

#ifdef CONFIG_ARM_LPAE
#define FAULT_CODE_ALIGNMENT	33
#define FAULT_CODE_DEBUG	34
#else
#define FAULT_CODE_ALIGNMENT	1
#define FAULT_CODE_DEBUG	2
#endif

void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
				       struct pt_regs *),
		     int sig, int code, const char *name);
+4 −4
Original line number Diff line number Diff line
@@ -1016,10 +1016,10 @@ static int __init arch_hw_breakpoint_init(void)
	}

	/* Register debug fault handler. */
	hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
			"watchpoint debug exception");
	hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
			"breakpoint debug exception");
	hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,
			TRAP_HWBKPT, "watchpoint debug exception");
	hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,
			TRAP_HWBKPT, "breakpoint debug exception");

	/* Register hotplug notifier. */
	register_cpu_notifier(&dbg_reset_nb);
+1 −1
Original line number Diff line number Diff line
@@ -968,7 +968,7 @@ static int __init alignment_init(void)
		ai_usermode = safe_usermode(ai_usermode, false);
	}

	hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
	hook_fault_code(FAULT_CODE_ALIGNMENT, do_alignment, SIGBUS, BUS_ADRALN,
			"alignment exception");

	/*
+15 −0
Original line number Diff line number Diff line
@@ -110,8 +110,10 @@ void show_pte(struct mm_struct *mm, unsigned long addr)

		pte = pte_offset_map(pmd, addr);
		printk(", *pte=%08llx", (long long)pte_val(*pte));
#ifndef CONFIG_ARM_LPAE
		printk(", *ppte=%08llx",
		       (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
#endif
		pte_unmap(pte);
	} while(0);

@@ -428,6 +430,12 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
	pmd = pmd_offset(pud, addr);
	pmd_k = pmd_offset(pud_k, addr);

#ifdef CONFIG_ARM_LPAE
	/*
	 * Only one hardware entry per PMD with LPAE.
	 */
	index = 0;
#else
	/*
	 * On ARM one Linux PGD entry contains two hardware entries (see page
	 * tables layout in pgtable.h). We normally guarantee that we always
@@ -437,6 +445,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
	 * for the first of pair.
	 */
	index = (addr >> SECTION_SHIFT) & 1;
#endif
	if (pmd_none(pmd_k[index]))
		goto bad_area;

@@ -484,7 +493,11 @@ struct fsr_info {
};

/* FSR definition */
#ifdef CONFIG_ARM_LPAE
#include "fsr-3level.c"
#else
#include "fsr-2level.c"
#endif

void __init
hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
@@ -553,6 +566,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
	arm_notify_die("", regs, &info, ifsr, 0);
}

#ifndef CONFIG_ARM_LPAE
static int __init exceptions_init(void)
{
	if (cpu_architecture() >= CPU_ARCH_ARMv6) {
@@ -575,3 +589,4 @@ static int __init exceptions_init(void)
}

arch_initcall(exceptions_init);
#endif
+8 −0
Original line number Diff line number Diff line
@@ -8,11 +8,19 @@
#define FSR_WRITE		(1 << 11)
#define FSR_FS4			(1 << 10)
#define FSR_FS3_0		(15)
#define FSR_FS5_0		(0x3f)

#ifdef CONFIG_ARM_LPAE
static inline int fsr_fs(unsigned int fsr)
{
	return fsr & FSR_FS5_0;
}
#else
static inline int fsr_fs(unsigned int fsr)
{
	return (fsr & FSR_FS3_0) | (fsr & FSR_FS4) >> 6;
}
#endif

void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
unsigned long search_exception_table(unsigned long addr);
Loading