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

toc.c (3124B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <linux/kernel.h>
      4#include <linux/kgdb.h>
      5#include <linux/printk.h>
      6#include <linux/sched/debug.h>
      7#include <linux/delay.h>
      8#include <linux/reboot.h>
      9
     10#include <asm/pdc.h>
     11#include <asm/pdc_chassis.h>
     12#include <asm/ldcw.h>
     13#include <asm/processor.h>
     14
     15static unsigned int __aligned(16) toc_lock = 1;
     16DEFINE_PER_CPU_PAGE_ALIGNED(char [16384], toc_stack) __visible;
     17
     18static void toc20_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_20 *toc)
     19{
     20	int i;
     21
     22	regs->gr[0] = (unsigned long)toc->cr[22];
     23
     24	for (i = 1; i < 32; i++)
     25		regs->gr[i] = (unsigned long)toc->gr[i];
     26
     27	for (i = 0; i < 8; i++)
     28		regs->sr[i] = (unsigned long)toc->sr[i];
     29
     30	regs->iasq[0] = (unsigned long)toc->cr[17];
     31	regs->iasq[1] = (unsigned long)toc->iasq_back;
     32	regs->iaoq[0] = (unsigned long)toc->cr[18];
     33	regs->iaoq[1] = (unsigned long)toc->iaoq_back;
     34
     35	regs->sar = (unsigned long)toc->cr[11];
     36	regs->iir = (unsigned long)toc->cr[19];
     37	regs->isr = (unsigned long)toc->cr[20];
     38	regs->ior = (unsigned long)toc->cr[21];
     39}
     40
     41static void toc11_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_11 *toc)
     42{
     43	int i;
     44
     45	regs->gr[0] = toc->cr[22];
     46
     47	for (i = 1; i < 32; i++)
     48		regs->gr[i] = toc->gr[i];
     49
     50	for (i = 0; i < 8; i++)
     51		regs->sr[i] = toc->sr[i];
     52
     53	regs->iasq[0] = toc->cr[17];
     54	regs->iasq[1] = toc->iasq_back;
     55	regs->iaoq[0] = toc->cr[18];
     56	regs->iaoq[1] = toc->iaoq_back;
     57
     58	regs->sar  = toc->cr[11];
     59	regs->iir  = toc->cr[19];
     60	regs->isr  = toc->cr[20];
     61	regs->ior  = toc->cr[21];
     62}
     63
     64void notrace __noreturn __cold toc_intr(struct pt_regs *regs)
     65{
     66	struct pdc_toc_pim_20 pim_data20;
     67	struct pdc_toc_pim_11 pim_data11;
     68
     69	/* verify we wrote regs to the correct stack */
     70	BUG_ON(regs != (struct pt_regs *)&per_cpu(toc_stack, raw_smp_processor_id()));
     71
     72	if (boot_cpu_data.cpu_type >= pcxu) {
     73		if (pdc_pim_toc20(&pim_data20))
     74			panic("Failed to get PIM data");
     75		toc20_to_pt_regs(regs, &pim_data20);
     76	} else {
     77		if (pdc_pim_toc11(&pim_data11))
     78			panic("Failed to get PIM data");
     79		toc11_to_pt_regs(regs, &pim_data11);
     80	}
     81
     82#ifdef CONFIG_KGDB
     83	nmi_enter();
     84
     85	if (atomic_read(&kgdb_active) != -1)
     86		kgdb_nmicallback(raw_smp_processor_id(), regs);
     87	kgdb_handle_exception(9, SIGTRAP, 0, regs);
     88#endif
     89
     90	/* serialize output, otherwise all CPUs write backtrace at once */
     91	while (__ldcw(&toc_lock) == 0)
     92		; /* wait */
     93	show_regs(regs);
     94	toc_lock = 1;	 /* release lock for next CPU */
     95
     96	if (raw_smp_processor_id() != 0)
     97		while (1) ; /* all but monarch CPU will wait endless. */
     98
     99	/* give other CPUs time to show their backtrace */
    100	mdelay(2000);
    101
    102	machine_restart("TOC");
    103
    104	/* should never reach this */
    105	panic("TOC");
    106}
    107
    108static __init int setup_toc(void)
    109{
    110	unsigned int csum = 0;
    111	unsigned long toc_code = (unsigned long)dereference_function_descriptor(toc_handler);
    112	int i;
    113
    114	PAGE0->vec_toc = __pa(toc_code) & 0xffffffff;
    115#ifdef CONFIG_64BIT
    116	PAGE0->vec_toc_hi = __pa(toc_code) >> 32;
    117#endif
    118	PAGE0->vec_toclen = toc_handler_size;
    119
    120	for (i = 0; i < toc_handler_size/4; i++)
    121		csum += ((u32 *)toc_code)[i];
    122	toc_handler_csum = -csum;
    123	pr_info("TOC handler registered\n");
    124	return 0;
    125}
    126early_initcall(setup_toc);