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

kn01-berr.c (4984B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	Bus error event handling code for DECstation/DECsystem 3100
      4 *	and 2100 (KN01) systems equipped with parity error detection
      5 *	logic.
      6 *
      7 *	Copyright (c) 2005  Maciej W. Rozycki
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/interrupt.h>
     12#include <linux/kernel.h>
     13#include <linux/spinlock.h>
     14#include <linux/types.h>
     15
     16#include <asm/inst.h>
     17#include <asm/irq_regs.h>
     18#include <asm/mipsregs.h>
     19#include <asm/page.h>
     20#include <asm/ptrace.h>
     21#include <asm/traps.h>
     22#include <linux/uaccess.h>
     23
     24#include <asm/dec/kn01.h>
     25
     26
     27/* CP0 hazard avoidance. */
     28#define BARRIER				\
     29	__asm__ __volatile__(		\
     30		".set	push\n\t"	\
     31		".set	noreorder\n\t"	\
     32		"nop\n\t"		\
     33		".set	pop\n\t")
     34
     35/*
     36 * Bits 7:0 of the Control Register are write-only -- the
     37 * corresponding bits of the Status Register have a different
     38 * meaning.  Hence we use a cache.  It speeds up things a bit
     39 * as well.
     40 *
     41 * There is no default value -- it has to be initialized.
     42 */
     43u16 cached_kn01_csr;
     44static DEFINE_RAW_SPINLOCK(kn01_lock);
     45
     46
     47static inline void dec_kn01_be_ack(void)
     48{
     49	volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
     50	unsigned long flags;
     51
     52	raw_spin_lock_irqsave(&kn01_lock, flags);
     53
     54	*csr = cached_kn01_csr | KN01_CSR_MEMERR;	/* Clear bus IRQ. */
     55	iob();
     56
     57	raw_spin_unlock_irqrestore(&kn01_lock, flags);
     58}
     59
     60static int dec_kn01_be_backend(struct pt_regs *regs, int is_fixup, int invoker)
     61{
     62	volatile u32 *kn01_erraddr = (void *)CKSEG1ADDR(KN01_SLOT_BASE +
     63							KN01_ERRADDR);
     64
     65	static const char excstr[] = "exception";
     66	static const char intstr[] = "interrupt";
     67	static const char cpustr[] = "CPU";
     68	static const char mreadstr[] = "memory read";
     69	static const char readstr[] = "read";
     70	static const char writestr[] = "write";
     71	static const char timestr[] = "timeout";
     72	static const char paritystr[] = "parity error";
     73
     74	int data = regs->cp0_cause & 4;
     75	unsigned int __user *pc = (unsigned int __user *)regs->cp0_epc +
     76				  ((regs->cp0_cause & CAUSEF_BD) != 0);
     77	union mips_instruction insn;
     78	unsigned long entrylo, offset;
     79	long asid, entryhi, vaddr;
     80
     81	const char *kind, *agent, *cycle, *event;
     82	unsigned long address;
     83
     84	u32 erraddr = *kn01_erraddr;
     85	int action = MIPS_BE_FATAL;
     86
     87	/* Ack ASAP, so that any subsequent errors get caught. */
     88	dec_kn01_be_ack();
     89
     90	kind = invoker ? intstr : excstr;
     91
     92	agent = cpustr;
     93
     94	if (invoker)
     95		address = erraddr;
     96	else {
     97		/* Bloody hardware doesn't record the address for reads... */
     98		if (data) {
     99			/* This never faults. */
    100			__get_user(insn.word, pc);
    101			vaddr = regs->regs[insn.i_format.rs] +
    102				insn.i_format.simmediate;
    103		} else
    104			vaddr = (long)pc;
    105		if (KSEGX(vaddr) == CKSEG0 || KSEGX(vaddr) == CKSEG1)
    106			address = CPHYSADDR(vaddr);
    107		else {
    108			/* Peek at what physical address the CPU used. */
    109			asid = read_c0_entryhi();
    110			entryhi = asid & (PAGE_SIZE - 1);
    111			entryhi |= vaddr & ~(PAGE_SIZE - 1);
    112			write_c0_entryhi(entryhi);
    113			BARRIER;
    114			tlb_probe();
    115			/* No need to check for presence. */
    116			tlb_read();
    117			entrylo = read_c0_entrylo0();
    118			write_c0_entryhi(asid);
    119			offset = vaddr & (PAGE_SIZE - 1);
    120			address = (entrylo & ~(PAGE_SIZE - 1)) | offset;
    121		}
    122	}
    123
    124	/* Treat low 256MB as memory, high -- as I/O. */
    125	if (address < 0x10000000) {
    126		cycle = mreadstr;
    127		event = paritystr;
    128	} else {
    129		cycle = invoker ? writestr : readstr;
    130		event = timestr;
    131	}
    132
    133	if (is_fixup)
    134		action = MIPS_BE_FIXUP;
    135
    136	if (action != MIPS_BE_FIXUP)
    137		printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n",
    138			kind, agent, cycle, event, address);
    139
    140	return action;
    141}
    142
    143int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup)
    144{
    145	return dec_kn01_be_backend(regs, is_fixup, 0);
    146}
    147
    148irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id)
    149{
    150	volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
    151	struct pt_regs *regs = get_irq_regs();
    152	int action;
    153
    154	if (!(*csr & KN01_CSR_MEMERR))
    155		return IRQ_NONE;		/* Must have been video. */
    156
    157	action = dec_kn01_be_backend(regs, 0, 1);
    158
    159	if (action == MIPS_BE_DISCARD)
    160		return IRQ_HANDLED;
    161
    162	/*
    163	 * FIXME: Find the affected processes and kill them, otherwise
    164	 * we must die.
    165	 *
    166	 * The interrupt is asynchronously delivered thus EPC and RA
    167	 * may be irrelevant, but are printed for a reference.
    168	 */
    169	printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",
    170	       regs->cp0_epc, regs->regs[31]);
    171	die("Unrecoverable bus error", regs);
    172}
    173
    174
    175void __init dec_kn01_be_init(void)
    176{
    177	volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
    178	unsigned long flags;
    179
    180	raw_spin_lock_irqsave(&kn01_lock, flags);
    181
    182	/* Preset write-only bits of the Control Register cache. */
    183	cached_kn01_csr = *csr;
    184	cached_kn01_csr &= KN01_CSR_STATUS | KN01_CSR_PARDIS | KN01_CSR_TXDIS;
    185	cached_kn01_csr |= KN01_CSR_LEDS;
    186
    187	/* Enable parity error detection. */
    188	cached_kn01_csr &= ~KN01_CSR_PARDIS;
    189	*csr = cached_kn01_csr;
    190	iob();
    191
    192	raw_spin_unlock_irqrestore(&kn01_lock, flags);
    193
    194	/* Clear any leftover errors from the firmware. */
    195	dec_kn01_be_ack();
    196}