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 (5080B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * kgdb support for ARC
      4 *
      5 * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
      6 */
      7
      8#include <linux/kgdb.h>
      9#include <linux/sched.h>
     10#include <linux/sched/task_stack.h>
     11#include <asm/disasm.h>
     12#include <asm/cacheflush.h>
     13
     14static void to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
     15			struct callee_regs *cregs)
     16{
     17	int regno;
     18
     19	for (regno = 0; regno <= 26; regno++)
     20		gdb_regs[_R0 + regno] = get_reg(regno, kernel_regs, cregs);
     21
     22	for (regno = 27; regno < GDB_MAX_REGS; regno++)
     23		gdb_regs[regno] = 0;
     24
     25	gdb_regs[_FP]		= kernel_regs->fp;
     26	gdb_regs[__SP]		= kernel_regs->sp;
     27	gdb_regs[_BLINK]	= kernel_regs->blink;
     28	gdb_regs[_RET]		= kernel_regs->ret;
     29	gdb_regs[_STATUS32]	= kernel_regs->status32;
     30	gdb_regs[_LP_COUNT]	= kernel_regs->lp_count;
     31	gdb_regs[_LP_END]	= kernel_regs->lp_end;
     32	gdb_regs[_LP_START]	= kernel_regs->lp_start;
     33	gdb_regs[_BTA]		= kernel_regs->bta;
     34	gdb_regs[_STOP_PC]	= kernel_regs->ret;
     35}
     36
     37static void from_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
     38			struct callee_regs *cregs)
     39{
     40	int regno;
     41
     42	for (regno = 0; regno <= 26; regno++)
     43		set_reg(regno, gdb_regs[regno + _R0], kernel_regs, cregs);
     44
     45	kernel_regs->fp		= gdb_regs[_FP];
     46	kernel_regs->sp		= gdb_regs[__SP];
     47	kernel_regs->blink	= gdb_regs[_BLINK];
     48	kernel_regs->ret	= gdb_regs[_RET];
     49	kernel_regs->status32	= gdb_regs[_STATUS32];
     50	kernel_regs->lp_count	= gdb_regs[_LP_COUNT];
     51	kernel_regs->lp_end	= gdb_regs[_LP_END];
     52	kernel_regs->lp_start	= gdb_regs[_LP_START];
     53	kernel_regs->bta	= gdb_regs[_BTA];
     54}
     55
     56
     57void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
     58{
     59	to_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
     60		current->thread.callee_reg);
     61}
     62
     63void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
     64{
     65	from_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
     66		current->thread.callee_reg);
     67}
     68
     69void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
     70				 struct task_struct *task)
     71{
     72	if (task)
     73		to_gdb_regs(gdb_regs, task_pt_regs(task),
     74			(struct callee_regs *) task->thread.callee_reg);
     75}
     76
     77struct single_step_data_t {
     78	uint16_t opcode[2];
     79	unsigned long address[2];
     80	int is_branch;
     81	int armed;
     82} single_step_data;
     83
     84static void undo_single_step(struct pt_regs *regs)
     85{
     86	if (single_step_data.armed) {
     87		int i;
     88
     89		for (i = 0; i < (single_step_data.is_branch ? 2 : 1); i++) {
     90			memcpy((void *) single_step_data.address[i],
     91				&single_step_data.opcode[i],
     92				BREAK_INSTR_SIZE);
     93
     94			flush_icache_range(single_step_data.address[i],
     95				single_step_data.address[i] +
     96				BREAK_INSTR_SIZE);
     97		}
     98		single_step_data.armed = 0;
     99	}
    100}
    101
    102static void place_trap(unsigned long address, void *save)
    103{
    104	memcpy(save, (void *) address, BREAK_INSTR_SIZE);
    105	memcpy((void *) address, &arch_kgdb_ops.gdb_bpt_instr,
    106		BREAK_INSTR_SIZE);
    107	flush_icache_range(address, address + BREAK_INSTR_SIZE);
    108}
    109
    110static void do_single_step(struct pt_regs *regs)
    111{
    112	single_step_data.is_branch = disasm_next_pc((unsigned long)
    113		regs->ret, regs, (struct callee_regs *)
    114		current->thread.callee_reg,
    115		&single_step_data.address[0],
    116		&single_step_data.address[1]);
    117
    118	place_trap(single_step_data.address[0], &single_step_data.opcode[0]);
    119
    120	if (single_step_data.is_branch) {
    121		place_trap(single_step_data.address[1],
    122			&single_step_data.opcode[1]);
    123	}
    124
    125	single_step_data.armed++;
    126}
    127
    128int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
    129			       char *remcomInBuffer, char *remcomOutBuffer,
    130			       struct pt_regs *regs)
    131{
    132	unsigned long addr;
    133	char *ptr;
    134
    135	undo_single_step(regs);
    136
    137	switch (remcomInBuffer[0]) {
    138	case 's':
    139	case 'c':
    140		ptr = &remcomInBuffer[1];
    141		if (kgdb_hex2long(&ptr, &addr))
    142			regs->ret = addr;
    143		fallthrough;
    144
    145	case 'D':
    146	case 'k':
    147		atomic_set(&kgdb_cpu_doing_single_step, -1);
    148
    149		if (remcomInBuffer[0] == 's') {
    150			do_single_step(regs);
    151			atomic_set(&kgdb_cpu_doing_single_step,
    152				   smp_processor_id());
    153		}
    154
    155		return 0;
    156	}
    157	return -1;
    158}
    159
    160int kgdb_arch_init(void)
    161{
    162	single_step_data.armed = 0;
    163	return 0;
    164}
    165
    166void kgdb_trap(struct pt_regs *regs)
    167{
    168	/* trap_s 3 is used for breakpoints that overwrite existing
    169	 * instructions, while trap_s 4 is used for compiled breakpoints.
    170	 *
    171	 * with trap_s 3 breakpoints the original instruction needs to be
    172	 * restored and continuation needs to start at the location of the
    173	 * breakpoint.
    174	 *
    175	 * with trap_s 4 (compiled) breakpoints, continuation needs to
    176	 * start after the breakpoint.
    177	 */
    178	if (regs->ecr_param == 3)
    179		instruction_pointer(regs) -= BREAK_INSTR_SIZE;
    180
    181	kgdb_handle_exception(1, SIGTRAP, 0, regs);
    182}
    183
    184void kgdb_arch_exit(void)
    185{
    186}
    187
    188void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
    189{
    190	instruction_pointer(regs) = ip;
    191}
    192
    193void kgdb_call_nmi_hook(void *ignored)
    194{
    195	/* Default implementation passes get_irq_regs() but we don't */
    196	kgdb_nmicallback(raw_smp_processor_id(), NULL);
    197}
    198
    199const struct kgdb_arch arch_kgdb_ops = {
    200	/* breakpoint instruction: TRAP_S 0x3 */
    201#ifdef CONFIG_CPU_BIG_ENDIAN
    202	.gdb_bpt_instr		= {0x78, 0x7e},
    203#else
    204	.gdb_bpt_instr		= {0x7e, 0x78},
    205#endif
    206};