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

kgdb.c (4064B)


      1/*
      2 * Microblaze KGDB support
      3 *
      4 * This file is subject to the terms and conditions of the GNU General Public
      5 * License.  See the file "COPYING" in the main directory of this archive
      6 * for more details.
      7 */
      8
      9#include <linux/kgdb.h>
     10#include <linux/kdebug.h>
     11#include <linux/irq.h>
     12#include <linux/io.h>
     13#include <asm/cacheflush.h>
     14#include <asm/asm-offsets.h>
     15#include <asm/kgdb.h>
     16#include <asm/pvr.h>
     17
     18#define GDB_REG		0
     19#define GDB_PC		32
     20#define GDB_MSR		33
     21#define GDB_EAR		34
     22#define GDB_ESR		35
     23#define GDB_FSR		36
     24#define GDB_BTR		37
     25#define GDB_PVR		38
     26#define GDB_REDR	50
     27#define GDB_RPID	51
     28#define GDB_RZPR	52
     29#define GDB_RTLBX	53
     30#define GDB_RTLBSX	54 /* mfs can't read it */
     31#define GDB_RTLBLO	55
     32#define GDB_RTLBHI	56
     33
     34/* keep pvr separately because it is unchangeable */
     35static struct pvr_s pvr;
     36
     37void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
     38{
     39	unsigned int i;
     40	unsigned long *pt_regb = (unsigned long *)regs;
     41	int temp;
     42
     43	/* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
     44	for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
     45		gdb_regs[i] = pt_regb[i];
     46
     47	/* Branch target register can't be changed */
     48	__asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : );
     49	gdb_regs[GDB_BTR] = temp;
     50
     51	/* pvr part  - we have 11 pvr regs */
     52	for (i = 0; i < sizeof(struct pvr_s)/4; i++)
     53		gdb_regs[GDB_PVR + i] = pvr.pvr[i];
     54
     55	/* read special registers - can't be changed */
     56	__asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : );
     57	gdb_regs[GDB_REDR] = temp;
     58	__asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : );
     59	gdb_regs[GDB_RPID] = temp;
     60	__asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : );
     61	gdb_regs[GDB_RZPR] = temp;
     62	__asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : );
     63	gdb_regs[GDB_RTLBX] = temp;
     64	__asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : );
     65	gdb_regs[GDB_RTLBLO] = temp;
     66	__asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : );
     67	gdb_regs[GDB_RTLBHI] = temp;
     68}
     69
     70void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
     71{
     72	unsigned int i;
     73	unsigned long *pt_regb = (unsigned long *)regs;
     74
     75	/* pt_regs and gdb_regs have the same 37 values.
     76	 * The rest of gdb_regs are unused and can't be changed.
     77	 * r0 register value can't be changed too. */
     78	for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++)
     79		pt_regb[i] = gdb_regs[i];
     80}
     81
     82asmlinkage void microblaze_kgdb_break(struct pt_regs *regs)
     83{
     84	if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
     85		return;
     86
     87	/* Jump over the first arch_kgdb_breakpoint which is barrier to
     88	 * get kgdb work. The same solution is used for powerpc */
     89	if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
     90		regs->pc += BREAK_INSTR_SIZE;
     91}
     92
     93/* untested */
     94void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
     95{
     96	unsigned int i;
     97	unsigned long *pt_regb = (unsigned long *)(p->thread.regs);
     98
     99	/* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */
    100	for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++)
    101		gdb_regs[i] = pt_regb[i];
    102
    103	/* pvr part  - we have 11 pvr regs */
    104	for (i = 0; i < sizeof(struct pvr_s)/4; i++)
    105		gdb_regs[GDB_PVR + i] = pvr.pvr[i];
    106}
    107
    108void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
    109{
    110	regs->pc = ip;
    111}
    112
    113int kgdb_arch_handle_exception(int vector, int signo, int err_code,
    114			       char *remcom_in_buffer, char *remcom_out_buffer,
    115			       struct pt_regs *regs)
    116{
    117	char *ptr;
    118	unsigned long address;
    119
    120	switch (remcom_in_buffer[0]) {
    121	case 'c':
    122		/* handle the optional parameter */
    123		ptr = &remcom_in_buffer[1];
    124		if (kgdb_hex2long(&ptr, &address))
    125			regs->pc = address;
    126
    127		return 0;
    128	}
    129	return -1; /* this means that we do not want to exit from the handler */
    130}
    131
    132int kgdb_arch_init(void)
    133{
    134	get_pvr(&pvr); /* Fill PVR structure */
    135	return 0;
    136}
    137
    138void kgdb_arch_exit(void)
    139{
    140	/* Nothing to do */
    141}
    142
    143/*
    144 * Global data
    145 */
    146const struct kgdb_arch arch_kgdb_ops = {
    147#ifdef __MICROBLAZEEL__
    148	.gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
    149#else
    150	.gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
    151#endif
    152};