summaryrefslogtreecommitdiff
path: root/arch/parisc/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/kernel/traps.c')
-rw-r--r--arch/parisc/kernel/traps.c130
1 files changed, 59 insertions, 71 deletions
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 82fc01189488..1107ca819ac8 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -30,6 +30,7 @@
#include <linux/ratelimit.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
+#include <linux/kfence.h>
#include <asm/assembly.h>
#include <asm/io.h>
@@ -46,10 +47,14 @@
#include <linux/kgdb.h>
#include <linux/kprobes.h>
+#if defined(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK)
+#include <asm/spinlock.h>
+#endif
+
#include "../math-emu/math-emu.h" /* for handle_fpe() */
static void parisc_show_stack(struct task_struct *task,
- struct pt_regs *regs);
+ struct pt_regs *regs, const char *loglvl);
static int printbinary(char *buf, unsigned long x, int nbits)
{
@@ -75,7 +80,7 @@ static int printbinary(char *buf, unsigned long x, int nbits)
lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1], \
(r)[(x)+2], (r)[(x)+3])
-static void print_gr(char *level, struct pt_regs *regs)
+static void print_gr(const char *level, struct pt_regs *regs)
{
int i;
char buf[64];
@@ -89,7 +94,7 @@ static void print_gr(char *level, struct pt_regs *regs)
PRINTREGS(level, regs->gr, "r", RFMT, i);
}
-static void print_fr(char *level, struct pt_regs *regs)
+static void print_fr(const char *level, struct pt_regs *regs)
{
int i;
char buf[64];
@@ -119,7 +124,7 @@ static void print_fr(char *level, struct pt_regs *regs)
void show_regs(struct pt_regs *regs)
{
int i, user;
- char *level;
+ const char *level;
unsigned long cr30, cr31;
user = user_mode(regs);
@@ -143,7 +148,7 @@ void show_regs(struct pt_regs *regs)
printk("%s IIR: %08lx ISR: " RFMT " IOR: " RFMT "\n",
level, regs->iir, regs->isr, regs->ior);
printk("%s CPU: %8d CR30: " RFMT " CR31: " RFMT "\n",
- level, current_thread_info()->cpu, cr30, cr31);
+ level, task_cpu(current), cr30, cr31);
printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
if (user) {
@@ -155,7 +160,7 @@ void show_regs(struct pt_regs *regs)
printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
- parisc_show_stack(current, regs);
+ parisc_show_stack(current, regs, KERN_DEFAULT);
}
}
@@ -170,37 +175,37 @@ static DEFINE_RATELIMIT_STATE(_hppa_rs,
}
-static void do_show_stack(struct unwind_frame_info *info)
+static void do_show_stack(struct unwind_frame_info *info, const char *loglvl)
{
int i = 1;
- printk(KERN_CRIT "Backtrace:\n");
+ printk("%sBacktrace:\n", loglvl);
while (i <= MAX_UNWIND_ENTRIES) {
if (unwind_once(info) < 0 || info->ip == 0)
break;
if (__kernel_text_address(info->ip)) {
- printk(KERN_CRIT " [<" RFMT ">] %pS\n",
- info->ip, (void *) info->ip);
+ printk("%s [<" RFMT ">] %pS\n",
+ loglvl, info->ip, (void *) info->ip);
i++;
}
}
- printk(KERN_CRIT "\n");
+ printk("%s\n", loglvl);
}
static void parisc_show_stack(struct task_struct *task,
- struct pt_regs *regs)
+ struct pt_regs *regs, const char *loglvl)
{
struct unwind_frame_info info;
unwind_frame_init_task(&info, task, regs);
- do_show_stack(&info);
+ do_show_stack(&info, loglvl);
}
-void show_stack(struct task_struct *t, unsigned long *sp)
+void show_stack(struct task_struct *t, unsigned long *sp, const char *loglvl)
{
- parisc_show_stack(t, NULL);
+ parisc_show_stack(t, NULL, loglvl);
}
int is_valid_bugaddr(unsigned long iaoq)
@@ -238,13 +243,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
/* unlock the pdc lock if necessary */
pdc_emergency_unlock();
- /* maybe the kernel hasn't booted very far yet and hasn't been able
- * to initialize the serial or STI console. In that case we should
- * re-enable the pdc console, so that the user will be able to
- * identify the problem. */
- if (!console_drivers)
- pdc_console_restart();
-
if (err)
printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
current->comm, task_pid_nr(current), str, err);
@@ -268,7 +266,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
panic("Fatal exception");
oops_exit();
- do_exit(SIGSEGV);
+ make_task_dead(SIGSEGV);
}
/* gdb uses break 4,8 */
@@ -297,21 +295,30 @@ static void handle_break(struct pt_regs *regs)
}
#ifdef CONFIG_KPROBES
- if (unlikely(iir == PARISC_KPROBES_BREAK_INSN)) {
+ if (unlikely(iir == PARISC_KPROBES_BREAK_INSN && !user_mode(regs))) {
parisc_kprobe_break_handler(regs);
return;
}
-
+ if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2 && !user_mode(regs))) {
+ parisc_kprobe_ss_handler(regs);
+ return;
+ }
#endif
#ifdef CONFIG_KGDB
- if (unlikely(iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
- iir == PARISC_KGDB_BREAK_INSN)) {
+ if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
+ iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) {
kgdb_handle_exception(9, SIGTRAP, 0, regs);
return;
}
#endif
+#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
+ if ((iir == SPINLOCK_BREAK_INSN) && !user_mode(regs)) {
+ die_if_kernel("Spinlock was trashed", regs, 1);
+ }
+#endif
+
if (unlikely(iir != GDB_BREAK_INSN))
parisc_printk_ratelimited(0, regs,
KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
@@ -328,10 +335,7 @@ static void default_trap(int code, struct pt_regs *regs)
show_regs(regs);
}
-void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap;
-
-
-void transfer_pim_to_trap_frame(struct pt_regs *regs)
+static void transfer_pim_to_trap_frame(struct pt_regs *regs)
{
register int i;
extern unsigned int hpmc_pim_data[];
@@ -425,10 +429,6 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
/* unlock the pdc lock if necessary */
pdc_emergency_unlock();
- /* restart pdc console if necessary */
- if (!console_drivers)
- pdc_console_restart();
-
/* Not all paths will gutter the processor... */
switch(code){
@@ -437,7 +437,6 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
break;
default:
- /* Fall through */
break;
}
@@ -446,7 +445,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
/* show_stack(NULL, (unsigned long *)regs->gr[30]); */
struct unwind_frame_info info;
unwind_frame_init(&info, current, regs);
- do_show_stack(&info);
+ do_show_stack(&info, KERN_CRIT);
}
printk("\n");
@@ -466,7 +465,7 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
* panic notifiers, and we should call panic
* directly from the location that we wish.
* e.g. We should not call panic from
- * parisc_terminate, but rather the oter way around.
+ * parisc_terminate, but rather the other way around.
* This hack works, prints the panic message twice,
* and it enables reboot timers!
*/
@@ -479,9 +478,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
unsigned long fault_space = 0;
int si_code;
- if (code == 1)
- pdc_console_restart(); /* switch back to pdc if HPMC */
- else
+ if (!irqs_disabled_flags(regs->gr[0]))
local_irq_enable();
/* Security check:
@@ -539,11 +536,6 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
/* Recovery counter trap */
regs->gr[0] &= ~PSW_R;
-#ifdef CONFIG_KPROBES
- if (parisc_kprobe_ss_handler(regs))
- return;
-#endif
-
#ifdef CONFIG_KGDB
if (kgdb_single_step) {
kgdb_handle_exception(0, SIGTRAP, 0, regs);
@@ -562,7 +554,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
flush_cache_all();
flush_tlb_all();
- cpu_lpmc(5, regs);
+ default_trap(code, regs);
return;
case PARISC_ITLB_TRAP:
@@ -644,12 +636,12 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
case 15:
/* Data TLB miss fault/Data page fault */
- /* Fall through */
+ fallthrough;
case 16:
/* Non-access instruction TLB miss fault */
/* The instruction TLB entry needed for the target address of the FIC
is absent, and hardware can't find it, so we get to cleanup */
- /* Fall through */
+ fallthrough;
case 17:
/* Non-access data TLB miss fault/Non-access data page fault */
/* FIXME:
@@ -662,6 +654,8 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
by hand. Technically we need to emulate:
fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw
*/
+ if (code == 17 && handle_nadtlb_fault(regs))
+ return;
fault_address = regs->ior;
fault_space = regs->isr;
break;
@@ -673,7 +667,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
handle_unaligned(regs);
return;
}
- /* Fall Through */
+ fallthrough;
case 26:
/* PCXL: Data memory access rights trap */
fault_address = regs->ior;
@@ -683,7 +677,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
case 19:
/* Data memory break trap */
regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
- /* fall thru */
+ fallthrough;
case 21:
/* Page reference trap */
handle_gdb_break(regs, TRAP_HWBKPT);
@@ -717,7 +711,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
if (user_mode(regs)) {
struct vm_area_struct *vma;
- down_read(&current->mm->mmap_sem);
+ mmap_read_lock(current->mm);
vma = find_vma(current->mm,regs->iaoq[0]);
if (vma && (regs->iaoq[0] >= vma->vm_start)
&& (vma->vm_flags & VM_EXEC)) {
@@ -725,12 +719,14 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
fault_address = regs->iaoq[0];
fault_space = regs->iasq[0];
- up_read(&current->mm->mmap_sem);
+ mmap_read_unlock(current->mm);
break; /* call do_page_fault() */
}
- up_read(&current->mm->mmap_sem);
+ mmap_read_unlock(current->mm);
}
- /* Fall Through */
+ /* CPU could not fetch instruction, so clear stale IIR value. */
+ regs->iir = 0xbaadf00d;
+ fallthrough;
case 27:
/* Data memory protection ID trap */
if (code == 27 && !user_mode(regs) &&
@@ -783,11 +779,15 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
* unless pagefault_disable() was called before.
*/
- if (fault_space == 0 && !faulthandler_disabled())
+ if (faulthandler_disabled() || fault_space == 0)
{
/* Clean up and return if in exception table. */
if (fixup_exception(regs))
return;
+ /* Clean up and return if handled by kfence. */
+ if (kfence_handle_page_fault(fault_address,
+ parisc_acctyp(code, regs->iir) == VM_WRITE, regs))
+ return;
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
parisc_terminate("Kernel Fault", regs, code, fault_address);
}
@@ -797,16 +797,14 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
}
-void __init initialize_ivt(const void *iva)
+static void __init initialize_ivt(const void *iva)
{
- extern u32 os_hpmc_size;
extern const u32 os_hpmc[];
int i;
u32 check = 0;
u32 *ivap;
- u32 *hpmcp;
- u32 length, instr;
+ u32 instr;
if (strcmp((const char *)iva, "cows can fly"))
panic("IVT invalid");
@@ -837,18 +835,12 @@ void __init initialize_ivt(const void *iva)
/* Setup IVA and compute checksum for HPMC handler */
ivap[6] = (u32)__pa(os_hpmc);
- length = os_hpmc_size;
- ivap[7] = length;
-
- hpmcp = (u32 *)os_hpmc;
-
- for (i=0; i<length/4; i++)
- check += *hpmcp++;
for (i=0; i<8; i++)
check += ivap[i];
ivap[5] = -check;
+ pr_debug("initialize_ivt: IVA[6] = 0x%08x\n", ivap[6]);
}
@@ -865,7 +857,3 @@ void __init early_trap_init(void)
initialize_ivt(&fault_vector_20);
}
-
-void __init trap_init(void)
-{
-}