cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

traps_32.c (11259B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arch/sparc/kernel/traps.c
      4 *
      5 * Copyright 1995, 2008 David S. Miller (davem@davemloft.net)
      6 * Copyright 2000 Jakub Jelinek (jakub@redhat.com)
      7 */
      8
      9/*
     10 * I hate traps on the sparc, grrr...
     11 */
     12
     13#include <linux/sched/mm.h>
     14#include <linux/sched/debug.h>
     15#include <linux/mm_types.h>
     16#include <linux/kernel.h>
     17#include <linux/signal.h>
     18#include <linux/smp.h>
     19#include <linux/kdebug.h>
     20#include <linux/export.h>
     21#include <linux/pgtable.h>
     22
     23#include <asm/delay.h>
     24#include <asm/ptrace.h>
     25#include <asm/oplib.h>
     26#include <asm/page.h>
     27#include <asm/unistd.h>
     28#include <asm/traps.h>
     29
     30#include "entry.h"
     31#include "kernel.h"
     32
     33/* #define TRAP_DEBUG */
     34
     35static void instruction_dump(unsigned long *pc)
     36{
     37	int i;
     38	
     39	if((((unsigned long) pc) & 3))
     40                return;
     41
     42	for(i = -3; i < 6; i++)
     43		printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
     44	printk("\n");
     45}
     46
     47#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
     48#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
     49
     50void __noreturn die_if_kernel(char *str, struct pt_regs *regs)
     51{
     52	static int die_counter;
     53	int count = 0;
     54
     55	/* Amuse the user. */
     56	printk(
     57"              \\|/ ____ \\|/\n"
     58"              \"@'/ ,. \\`@\"\n"
     59"              /_| \\__/ |_\\\n"
     60"                 \\__U_/\n");
     61
     62	printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);
     63	show_regs(regs);
     64	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
     65
     66	__SAVE; __SAVE; __SAVE; __SAVE;
     67	__SAVE; __SAVE; __SAVE; __SAVE;
     68	__RESTORE; __RESTORE; __RESTORE; __RESTORE;
     69	__RESTORE; __RESTORE; __RESTORE; __RESTORE;
     70
     71	{
     72		struct reg_window32 *rw = (struct reg_window32 *)regs->u_regs[UREG_FP];
     73
     74		/* Stop the back trace when we hit userland or we
     75		 * find some badly aligned kernel stack. Set an upper
     76		 * bound in case our stack is trashed and we loop.
     77		 */
     78		while(rw					&&
     79		      count++ < 30				&&
     80                      (((unsigned long) rw) >= PAGE_OFFSET)	&&
     81		      !(((unsigned long) rw) & 0x7)) {
     82			printk("Caller[%08lx]: %pS\n", rw->ins[7],
     83			       (void *) rw->ins[7]);
     84			rw = (struct reg_window32 *)rw->ins[6];
     85		}
     86	}
     87	printk("Instruction DUMP:");
     88	instruction_dump ((unsigned long *) regs->pc);
     89	make_task_dead((regs->psr & PSR_PS) ? SIGKILL : SIGSEGV);
     90}
     91
     92void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
     93{
     94	if(type < 0x80) {
     95		/* Sun OS's puke from bad traps, Linux survives! */
     96		printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
     97		die_if_kernel("Whee... Hello Mr. Penguin", regs);
     98	}	
     99
    100	if(regs->psr & PSR_PS)
    101		die_if_kernel("Kernel bad trap", regs);
    102
    103	force_sig_fault_trapno(SIGILL, ILL_ILLTRP,
    104			       (void __user *)regs->pc, type - 0x80);
    105}
    106
    107void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    108			    unsigned long psr)
    109{
    110	if(psr & PSR_PS)
    111		die_if_kernel("Kernel illegal instruction", regs);
    112#ifdef TRAP_DEBUG
    113	printk("Ill instr. at pc=%08lx instruction is %08lx\n",
    114	       regs->pc, *(unsigned long *)regs->pc);
    115#endif
    116
    117	send_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)pc, current);
    118}
    119
    120void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    121			 unsigned long psr)
    122{
    123	if(psr & PSR_PS)
    124		die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
    125	send_sig_fault(SIGILL, ILL_PRVOPC, (void __user *)pc, current);
    126}
    127
    128/* XXX User may want to be allowed to do this. XXX */
    129
    130void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    131			    unsigned long psr)
    132{
    133	if(regs->psr & PSR_PS) {
    134		printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
    135		       regs->u_regs[UREG_RETPC]);
    136		die_if_kernel("BOGUS", regs);
    137		/* die_if_kernel("Kernel MNA access", regs); */
    138	}
    139#if 0
    140	show_regs (regs);
    141	instruction_dump ((unsigned long *) regs->pc);
    142	printk ("do_MNA!\n");
    143#endif
    144	send_sig_fault(SIGBUS, BUS_ADRALN,
    145		       /* FIXME: Should dig out mna address */ (void *)0,
    146		       current);
    147}
    148
    149static unsigned long init_fsr = 0x0UL;
    150static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
    151                { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
    152		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
    153		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
    154		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
    155
    156void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    157		 unsigned long psr)
    158{
    159	/* Sanity check... */
    160	if(psr & PSR_PS)
    161		die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
    162
    163	put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
    164	regs->psr |= PSR_EF;
    165#ifndef CONFIG_SMP
    166	if(last_task_used_math == current)
    167		return;
    168	if(last_task_used_math) {
    169		/* Other processes fpu state, save away */
    170		struct task_struct *fptask = last_task_used_math;
    171		fpsave(&fptask->thread.float_regs[0], &fptask->thread.fsr,
    172		       &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth);
    173	}
    174	last_task_used_math = current;
    175	if(used_math()) {
    176		fpload(&current->thread.float_regs[0], &current->thread.fsr);
    177	} else {
    178		/* Set initial sane state. */
    179		fpload(&init_fregs[0], &init_fsr);
    180		set_used_math();
    181	}
    182#else
    183	if(!used_math()) {
    184		fpload(&init_fregs[0], &init_fsr);
    185		set_used_math();
    186	} else {
    187		fpload(&current->thread.float_regs[0], &current->thread.fsr);
    188	}
    189	set_thread_flag(TIF_USEDFPU);
    190#endif
    191}
    192
    193static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
    194static unsigned long fake_fsr;
    195static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
    196static unsigned long fake_depth;
    197
    198void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    199		 unsigned long psr)
    200{
    201	static int calls;
    202	unsigned long fsr;
    203	int ret = 0;
    204	int code;
    205#ifndef CONFIG_SMP
    206	struct task_struct *fpt = last_task_used_math;
    207#else
    208	struct task_struct *fpt = current;
    209#endif
    210	put_psr(get_psr() | PSR_EF);
    211	/* If nobody owns the fpu right now, just clear the
    212	 * error into our fake static buffer and hope it don't
    213	 * happen again.  Thank you crashme...
    214	 */
    215#ifndef CONFIG_SMP
    216	if(!fpt) {
    217#else
    218	if (!test_tsk_thread_flag(fpt, TIF_USEDFPU)) {
    219#endif
    220		fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
    221		regs->psr &= ~PSR_EF;
    222		return;
    223	}
    224	fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr,
    225	       &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth);
    226#ifdef DEBUG_FPU
    227	printk("Hmm, FP exception, fsr was %016lx\n", fpt->thread.fsr);
    228#endif
    229
    230	switch ((fpt->thread.fsr & 0x1c000)) {
    231	/* switch on the contents of the ftt [floating point trap type] field */
    232#ifdef DEBUG_FPU
    233	case (1 << 14):
    234		printk("IEEE_754_exception\n");
    235		break;
    236#endif
    237	case (2 << 14):  /* unfinished_FPop (underflow & co) */
    238	case (3 << 14):  /* unimplemented_FPop (quad stuff, maybe sqrt) */
    239		ret = do_mathemu(regs, fpt);
    240		break;
    241#ifdef DEBUG_FPU
    242	case (4 << 14):
    243		printk("sequence_error (OS bug...)\n");
    244		break;
    245	case (5 << 14):
    246		printk("hardware_error (uhoh!)\n");
    247		break;
    248	case (6 << 14):
    249		printk("invalid_fp_register (user error)\n");
    250		break;
    251#endif /* DEBUG_FPU */
    252	}
    253	/* If we successfully emulated the FPop, we pretend the trap never happened :-> */
    254	if (ret) {
    255		fpload(&current->thread.float_regs[0], &current->thread.fsr);
    256		return;
    257	}
    258	/* nope, better SIGFPE the offending process... */
    259	       
    260#ifdef CONFIG_SMP
    261	clear_tsk_thread_flag(fpt, TIF_USEDFPU);
    262#endif
    263	if(psr & PSR_PS) {
    264		/* The first fsr store/load we tried trapped,
    265		 * the second one will not (we hope).
    266		 */
    267		printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
    268		       regs->pc);
    269		regs->pc = regs->npc;
    270		regs->npc += 4;
    271		calls++;
    272		if(calls > 2)
    273			die_if_kernel("Too many Penguin-FPU traps from kernel mode",
    274				      regs);
    275		return;
    276	}
    277
    278	fsr = fpt->thread.fsr;
    279	code = FPE_FLTUNK;
    280	if ((fsr & 0x1c000) == (1 << 14)) {
    281		if (fsr & 0x10)
    282			code = FPE_FLTINV;
    283		else if (fsr & 0x08)
    284			code = FPE_FLTOVF;
    285		else if (fsr & 0x04)
    286			code = FPE_FLTUND;
    287		else if (fsr & 0x02)
    288			code = FPE_FLTDIV;
    289		else if (fsr & 0x01)
    290			code = FPE_FLTRES;
    291	}
    292	send_sig_fault(SIGFPE, code, (void __user *)pc, fpt);
    293#ifndef CONFIG_SMP
    294	last_task_used_math = NULL;
    295#endif
    296	regs->psr &= ~PSR_EF;
    297	if(calls > 0)
    298		calls=0;
    299}
    300
    301void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    302			 unsigned long psr)
    303{
    304	if(psr & PSR_PS)
    305		die_if_kernel("Penguin overflow trap from kernel mode", regs);
    306	send_sig_fault(SIGEMT, EMT_TAGOVF, (void __user *)pc, current);
    307}
    308
    309void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    310		       unsigned long psr)
    311{
    312#ifdef TRAP_DEBUG
    313	printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
    314	       pc, npc, psr);
    315#endif
    316	if(psr & PSR_PS)
    317		panic("Tell me what a watchpoint trap is, and I'll then deal "
    318		      "with such a beast...");
    319}
    320
    321void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    322		       unsigned long psr)
    323{
    324#ifdef TRAP_DEBUG
    325	printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
    326	       pc, npc, psr);
    327#endif
    328	force_sig_fault(SIGBUS, BUS_OBJERR, (void __user *)pc);
    329}
    330
    331void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    332			unsigned long psr)
    333{
    334	send_sig_fault(SIGILL, ILL_COPROC, (void __user *)pc, current);
    335}
    336
    337void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    338			 unsigned long psr)
    339{
    340#ifdef TRAP_DEBUG
    341	printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
    342	       pc, npc, psr);
    343#endif
    344	send_sig_fault(SIGILL, ILL_COPROC, (void __user *)pc, current);
    345}
    346
    347void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
    348		       unsigned long psr)
    349{
    350	send_sig_fault(SIGFPE, FPE_INTDIV, (void __user *)pc, current);
    351}
    352
    353#ifdef CONFIG_DEBUG_BUGVERBOSE
    354void do_BUG(const char *file, int line)
    355{
    356        // bust_spinlocks(1);   XXX Not in our original BUG()
    357        printk("kernel BUG at %s:%d!\n", file, line);
    358}
    359EXPORT_SYMBOL(do_BUG);
    360#endif
    361
    362/* Since we have our mappings set up, on multiprocessors we can spin them
    363 * up here so that timer interrupts work during initialization.
    364 */
    365
    366void trap_init(void)
    367{
    368	extern void thread_info_offsets_are_bolixed_pete(void);
    369
    370	/* Force linker to barf if mismatched */
    371	if (TI_UWINMASK    != offsetof(struct thread_info, uwinmask) ||
    372	    TI_TASK        != offsetof(struct thread_info, task) ||
    373	    TI_FLAGS       != offsetof(struct thread_info, flags) ||
    374	    TI_CPU         != offsetof(struct thread_info, cpu) ||
    375	    TI_PREEMPT     != offsetof(struct thread_info, preempt_count) ||
    376	    TI_SOFTIRQ     != offsetof(struct thread_info, softirq_count) ||
    377	    TI_HARDIRQ     != offsetof(struct thread_info, hardirq_count) ||
    378	    TI_KSP         != offsetof(struct thread_info, ksp) ||
    379	    TI_KPC         != offsetof(struct thread_info, kpc) ||
    380	    TI_KPSR        != offsetof(struct thread_info, kpsr) ||
    381	    TI_KWIM        != offsetof(struct thread_info, kwim) ||
    382	    TI_REG_WINDOW  != offsetof(struct thread_info, reg_window) ||
    383	    TI_RWIN_SPTRS  != offsetof(struct thread_info, rwbuf_stkptrs) ||
    384	    TI_W_SAVED     != offsetof(struct thread_info, w_saved))
    385		thread_info_offsets_are_bolixed_pete();
    386
    387	/* Attach to the address space of init_task. */
    388	mmgrab(&init_mm);
    389	current->active_mm = &init_mm;
    390
    391	/* NOTE: Other cpus have this done as they are started
    392	 *       up on SMP.
    393	 */
    394}