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.c (11871B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * OpenRISC traps.c
      4 *
      5 * Linux architectural port borrowing liberally from similar works of
      6 * others.  All original copyrights apply as per the original source
      7 * declaration.
      8 *
      9 * Modifications for the OpenRISC architecture:
     10 * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
     11 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
     12 *
     13 *  Here we handle the break vectors not used by the system call
     14 *  mechanism, as well as some general stack/register dumping
     15 *  things.
     16 */
     17
     18#include <linux/init.h>
     19#include <linux/sched.h>
     20#include <linux/sched/debug.h>
     21#include <linux/sched/task_stack.h>
     22#include <linux/kernel.h>
     23#include <linux/extable.h>
     24#include <linux/kmod.h>
     25#include <linux/string.h>
     26#include <linux/errno.h>
     27#include <linux/ptrace.h>
     28#include <linux/timer.h>
     29#include <linux/mm.h>
     30#include <linux/kallsyms.h>
     31#include <linux/uaccess.h>
     32
     33#include <asm/io.h>
     34#include <asm/unwinder.h>
     35#include <asm/sections.h>
     36
     37static int kstack_depth_to_print = 0x180;
     38int lwa_flag;
     39static unsigned long __user *lwa_addr;
     40
     41static void print_trace(void *data, unsigned long addr, int reliable)
     42{
     43	const char *loglvl = data;
     44
     45	printk("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ",
     46	       (void *) addr);
     47}
     48
     49static void print_data(unsigned long base_addr, unsigned long word, int i)
     50{
     51	if (i == 0)
     52		printk("(%08lx:)\t%08lx", base_addr + (i * 4), word);
     53	else
     54		printk(" %08lx:\t%08lx", base_addr + (i * 4), word);
     55}
     56
     57/* displays a short stack trace */
     58void show_stack(struct task_struct *task, unsigned long *esp, const char *loglvl)
     59{
     60	if (esp == NULL)
     61		esp = (unsigned long *)&esp;
     62
     63	printk("%sCall trace:\n", loglvl);
     64	unwind_stack((void *)loglvl, esp, print_trace);
     65}
     66
     67void show_registers(struct pt_regs *regs)
     68{
     69	int i;
     70	int in_kernel = 1;
     71	unsigned long esp;
     72
     73	esp = (unsigned long)(regs->sp);
     74	if (user_mode(regs))
     75		in_kernel = 0;
     76
     77	printk("CPU #: %d\n"
     78	       "   PC: %08lx    SR: %08lx    SP: %08lx\n",
     79	       smp_processor_id(), regs->pc, regs->sr, regs->sp);
     80	printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
     81	       0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
     82	printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
     83	       regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
     84	printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
     85	       regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
     86	printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
     87	       regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
     88	printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
     89	       regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
     90	printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
     91	       regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
     92	printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
     93	       regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
     94	printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
     95	       regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
     96	printk("  RES: %08lx oGPR11: %08lx\n",
     97	       regs->gpr[11], regs->orig_gpr11);
     98
     99	printk("Process %s (pid: %d, stackpage=%08lx)\n",
    100	       current->comm, current->pid, (unsigned long)current);
    101	/*
    102	 * When in-kernel, we also print out the stack and code at the
    103	 * time of the fault..
    104	 */
    105	if (in_kernel) {
    106
    107		printk("\nStack: ");
    108		show_stack(NULL, (unsigned long *)esp, KERN_EMERG);
    109
    110		if (esp < PAGE_OFFSET)
    111			goto bad_stack;
    112
    113		printk("\n");
    114		for (i = -8; i < 24; i += 1) {
    115			unsigned long word;
    116
    117			if (__get_user(word, &((unsigned long *)esp)[i])) {
    118bad_stack:
    119				printk(" Bad Stack value.");
    120				break;
    121			}
    122
    123			print_data(esp, word, i);
    124		}
    125
    126		printk("\nCode: ");
    127		if (regs->pc < PAGE_OFFSET)
    128			goto bad;
    129
    130		for (i = -6; i < 6; i += 1) {
    131			unsigned long word;
    132
    133			if (__get_user(word, &((unsigned long *)regs->pc)[i])) {
    134bad:
    135				printk(" Bad PC value.");
    136				break;
    137			}
    138
    139			print_data(regs->pc, word, i);
    140		}
    141	}
    142	printk("\n");
    143}
    144
    145void nommu_dump_state(struct pt_regs *regs,
    146		      unsigned long ea, unsigned long vector)
    147{
    148	int i;
    149	unsigned long addr, stack = regs->sp;
    150
    151	printk("\n\r[nommu_dump_state] :: ea %lx, vector %lx\n\r", ea, vector);
    152
    153	printk("CPU #: %d\n"
    154	       "   PC: %08lx    SR: %08lx    SP: %08lx\n",
    155	       0, regs->pc, regs->sr, regs->sp);
    156	printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
    157	       0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
    158	printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
    159	       regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
    160	printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
    161	       regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
    162	printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
    163	       regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
    164	printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
    165	       regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
    166	printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
    167	       regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
    168	printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
    169	       regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
    170	printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
    171	       regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
    172	printk("  RES: %08lx oGPR11: %08lx\n",
    173	       regs->gpr[11], regs->orig_gpr11);
    174
    175	printk("Process %s (pid: %d, stackpage=%08lx)\n",
    176	       ((struct task_struct *)(__pa(current)))->comm,
    177	       ((struct task_struct *)(__pa(current)))->pid,
    178	       (unsigned long)current);
    179
    180	printk("\nStack: ");
    181	printk("Stack dump [0x%08lx]:\n", (unsigned long)stack);
    182	for (i = 0; i < kstack_depth_to_print; i++) {
    183		if (((long)stack & (THREAD_SIZE - 1)) == 0)
    184			break;
    185		stack++;
    186
    187		printk("%lx :: sp + %02d: 0x%08lx\n", stack, i * 4,
    188		       *((unsigned long *)(__pa(stack))));
    189	}
    190	printk("\n");
    191
    192	printk("Call Trace:   ");
    193	i = 1;
    194	while (((long)stack & (THREAD_SIZE - 1)) != 0) {
    195		addr = *((unsigned long *)__pa(stack));
    196		stack++;
    197
    198		if (kernel_text_address(addr)) {
    199			if (i && ((i % 6) == 0))
    200				printk("\n ");
    201			printk(" [<%08lx>]", addr);
    202			i++;
    203		}
    204	}
    205	printk("\n");
    206
    207	printk("\nCode: ");
    208
    209	for (i = -24; i < 24; i++) {
    210		unsigned long word;
    211
    212		word = ((unsigned long *)(__pa(regs->pc)))[i];
    213
    214		print_data(regs->pc, word, i);
    215	}
    216	printk("\n");
    217}
    218
    219/* This is normally the 'Oops' routine */
    220void __noreturn die(const char *str, struct pt_regs *regs, long err)
    221{
    222
    223	console_verbose();
    224	printk("\n%s#: %04lx\n", str, err & 0xffff);
    225	show_registers(regs);
    226#ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION
    227	printk("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n");
    228
    229	/* shut down interrupts */
    230	local_irq_disable();
    231
    232	__asm__ __volatile__("l.nop   1");
    233	do {} while (1);
    234#endif
    235	make_task_dead(SIGSEGV);
    236}
    237
    238asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector)
    239{
    240	printk("Unable to handle exception at EA =0x%x, vector 0x%x",
    241	       ea, vector);
    242	die("Oops", regs, 9);
    243}
    244
    245asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
    246{
    247	force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);
    248}
    249
    250asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
    251{
    252	if (user_mode(regs)) {
    253		/* Send a SIGBUS */
    254		force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)address);
    255	} else {
    256		printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
    257		show_registers(regs);
    258		die("Die:", regs, address);
    259	}
    260
    261}
    262
    263asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address)
    264{
    265	if (user_mode(regs)) {
    266		/* Send a SIGBUS */
    267		force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
    268	} else {		/* Kernel mode */
    269		printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address);
    270		show_registers(regs);
    271		die("Die:", regs, address);
    272	}
    273}
    274
    275static inline int in_delay_slot(struct pt_regs *regs)
    276{
    277#ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX
    278	/* No delay slot flag, do the old way */
    279	unsigned int op, insn;
    280
    281	insn = *((unsigned int *)regs->pc);
    282	op = insn >> 26;
    283	switch (op) {
    284	case 0x00: /* l.j */
    285	case 0x01: /* l.jal */
    286	case 0x03: /* l.bnf */
    287	case 0x04: /* l.bf */
    288	case 0x11: /* l.jr */
    289	case 0x12: /* l.jalr */
    290		return 1;
    291	default:
    292		return 0;
    293	}
    294#else
    295	return mfspr(SPR_SR) & SPR_SR_DSX;
    296#endif
    297}
    298
    299static inline void adjust_pc(struct pt_regs *regs, unsigned long address)
    300{
    301	int displacement;
    302	unsigned int rb, op, jmp;
    303
    304	if (unlikely(in_delay_slot(regs))) {
    305		/* In delay slot, instruction at pc is a branch, simulate it */
    306		jmp = *((unsigned int *)regs->pc);
    307
    308		displacement = sign_extend32(((jmp) & 0x3ffffff) << 2, 27);
    309		rb = (jmp & 0x0000ffff) >> 11;
    310		op = jmp >> 26;
    311
    312		switch (op) {
    313		case 0x00: /* l.j */
    314			regs->pc += displacement;
    315			return;
    316		case 0x01: /* l.jal */
    317			regs->pc += displacement;
    318			regs->gpr[9] = regs->pc + 8;
    319			return;
    320		case 0x03: /* l.bnf */
    321			if (regs->sr & SPR_SR_F)
    322				regs->pc += 8;
    323			else
    324				regs->pc += displacement;
    325			return;
    326		case 0x04: /* l.bf */
    327			if (regs->sr & SPR_SR_F)
    328				regs->pc += displacement;
    329			else
    330				regs->pc += 8;
    331			return;
    332		case 0x11: /* l.jr */
    333			regs->pc = regs->gpr[rb];
    334			return;
    335		case 0x12: /* l.jalr */
    336			regs->pc = regs->gpr[rb];
    337			regs->gpr[9] = regs->pc + 8;
    338			return;
    339		default:
    340			break;
    341		}
    342	} else {
    343		regs->pc += 4;
    344	}
    345}
    346
    347static inline void simulate_lwa(struct pt_regs *regs, unsigned long address,
    348				unsigned int insn)
    349{
    350	unsigned int ra, rd;
    351	unsigned long value;
    352	unsigned long orig_pc;
    353	long imm;
    354
    355	const struct exception_table_entry *entry;
    356
    357	orig_pc = regs->pc;
    358	adjust_pc(regs, address);
    359
    360	ra = (insn >> 16) & 0x1f;
    361	rd = (insn >> 21) & 0x1f;
    362	imm = (short)insn;
    363	lwa_addr = (unsigned long __user *)(regs->gpr[ra] + imm);
    364
    365	if ((unsigned long)lwa_addr & 0x3) {
    366		do_unaligned_access(regs, address);
    367		return;
    368	}
    369
    370	if (get_user(value, lwa_addr)) {
    371		if (user_mode(regs)) {
    372			force_sig(SIGSEGV);
    373			return;
    374		}
    375
    376		if ((entry = search_exception_tables(orig_pc))) {
    377			regs->pc = entry->fixup;
    378			return;
    379		}
    380
    381		/* kernel access in kernel space, load it directly */
    382		value = *((unsigned long *)lwa_addr);
    383	}
    384
    385	lwa_flag = 1;
    386	regs->gpr[rd] = value;
    387}
    388
    389static inline void simulate_swa(struct pt_regs *regs, unsigned long address,
    390				unsigned int insn)
    391{
    392	unsigned long __user *vaddr;
    393	unsigned long orig_pc;
    394	unsigned int ra, rb;
    395	long imm;
    396
    397	const struct exception_table_entry *entry;
    398
    399	orig_pc = regs->pc;
    400	adjust_pc(regs, address);
    401
    402	ra = (insn >> 16) & 0x1f;
    403	rb = (insn >> 11) & 0x1f;
    404	imm = (short)(((insn & 0x2200000) >> 10) | (insn & 0x7ff));
    405	vaddr = (unsigned long __user *)(regs->gpr[ra] + imm);
    406
    407	if (!lwa_flag || vaddr != lwa_addr) {
    408		regs->sr &= ~SPR_SR_F;
    409		return;
    410	}
    411
    412	if ((unsigned long)vaddr & 0x3) {
    413		do_unaligned_access(regs, address);
    414		return;
    415	}
    416
    417	if (put_user(regs->gpr[rb], vaddr)) {
    418		if (user_mode(regs)) {
    419			force_sig(SIGSEGV);
    420			return;
    421		}
    422
    423		if ((entry = search_exception_tables(orig_pc))) {
    424			regs->pc = entry->fixup;
    425			return;
    426		}
    427
    428		/* kernel access in kernel space, store it directly */
    429		*((unsigned long *)vaddr) = regs->gpr[rb];
    430	}
    431
    432	lwa_flag = 0;
    433	regs->sr |= SPR_SR_F;
    434}
    435
    436#define INSN_LWA	0x1b
    437#define INSN_SWA	0x33
    438
    439asmlinkage void do_illegal_instruction(struct pt_regs *regs,
    440				       unsigned long address)
    441{
    442	unsigned int op;
    443	unsigned int insn = *((unsigned int *)address);
    444
    445	op = insn >> 26;
    446
    447	switch (op) {
    448	case INSN_LWA:
    449		simulate_lwa(regs, address, insn);
    450		return;
    451
    452	case INSN_SWA:
    453		simulate_swa(regs, address, insn);
    454		return;
    455
    456	default:
    457		break;
    458	}
    459
    460	if (user_mode(regs)) {
    461		/* Send a SIGILL */
    462		force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)address);
    463	} else {		/* Kernel mode */
    464		printk("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n",
    465		       address);
    466		show_registers(regs);
    467		die("Die:", regs, address);
    468	}
    469}