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


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arch/arm/kernel/kgdb.c
      4 *
      5 * ARM KGDB support
      6 *
      7 * Copyright (c) 2002-2004 MontaVista Software, Inc
      8 * Copyright (c) 2008 Wind River Systems, Inc.
      9 *
     10 * Authors:  George Davis <davis_g@mvista.com>
     11 *           Deepak Saxena <dsaxena@plexity.net>
     12 */
     13#include <linux/irq.h>
     14#include <linux/kdebug.h>
     15#include <linux/kgdb.h>
     16#include <linux/uaccess.h>
     17
     18#include <asm/patch.h>
     19#include <asm/traps.h>
     20
     21struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
     22{
     23	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
     24	{ "r1", 4, offsetof(struct pt_regs, ARM_r1)},
     25	{ "r2", 4, offsetof(struct pt_regs, ARM_r2)},
     26	{ "r3", 4, offsetof(struct pt_regs, ARM_r3)},
     27	{ "r4", 4, offsetof(struct pt_regs, ARM_r4)},
     28	{ "r5", 4, offsetof(struct pt_regs, ARM_r5)},
     29	{ "r6", 4, offsetof(struct pt_regs, ARM_r6)},
     30	{ "r7", 4, offsetof(struct pt_regs, ARM_r7)},
     31	{ "r8", 4, offsetof(struct pt_regs, ARM_r8)},
     32	{ "r9", 4, offsetof(struct pt_regs, ARM_r9)},
     33	{ "r10", 4, offsetof(struct pt_regs, ARM_r10)},
     34	{ "fp", 4, offsetof(struct pt_regs, ARM_fp)},
     35	{ "ip", 4, offsetof(struct pt_regs, ARM_ip)},
     36	{ "sp", 4, offsetof(struct pt_regs, ARM_sp)},
     37	{ "lr", 4, offsetof(struct pt_regs, ARM_lr)},
     38	{ "pc", 4, offsetof(struct pt_regs, ARM_pc)},
     39	{ "f0", 12, -1 },
     40	{ "f1", 12, -1 },
     41	{ "f2", 12, -1 },
     42	{ "f3", 12, -1 },
     43	{ "f4", 12, -1 },
     44	{ "f5", 12, -1 },
     45	{ "f6", 12, -1 },
     46	{ "f7", 12, -1 },
     47	{ "fps", 4, -1 },
     48	{ "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)},
     49};
     50
     51char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
     52{
     53	if (regno >= DBG_MAX_REG_NUM || regno < 0)
     54		return NULL;
     55
     56	if (dbg_reg_def[regno].offset != -1)
     57		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
     58		       dbg_reg_def[regno].size);
     59	else
     60		memset(mem, 0, dbg_reg_def[regno].size);
     61	return dbg_reg_def[regno].name;
     62}
     63
     64int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
     65{
     66	if (regno >= DBG_MAX_REG_NUM || regno < 0)
     67		return -EINVAL;
     68
     69	if (dbg_reg_def[regno].offset != -1)
     70		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
     71		       dbg_reg_def[regno].size);
     72	return 0;
     73}
     74
     75void
     76sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
     77{
     78	struct thread_info *ti;
     79	int regno;
     80
     81	/* Just making sure... */
     82	if (task == NULL)
     83		return;
     84
     85	/* Initialize to zero */
     86	for (regno = 0; regno < GDB_MAX_REGS; regno++)
     87		gdb_regs[regno] = 0;
     88
     89	/* Otherwise, we have only some registers from switch_to() */
     90	ti			= task_thread_info(task);
     91	gdb_regs[_R4]		= ti->cpu_context.r4;
     92	gdb_regs[_R5]		= ti->cpu_context.r5;
     93	gdb_regs[_R6]		= ti->cpu_context.r6;
     94	gdb_regs[_R7]		= ti->cpu_context.r7;
     95	gdb_regs[_R8]		= ti->cpu_context.r8;
     96	gdb_regs[_R9]		= ti->cpu_context.r9;
     97	gdb_regs[_R10]		= ti->cpu_context.sl;
     98	gdb_regs[_FP]		= ti->cpu_context.fp;
     99	gdb_regs[_SPT]		= ti->cpu_context.sp;
    100	gdb_regs[_PC]		= ti->cpu_context.pc;
    101}
    102
    103void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
    104{
    105	regs->ARM_pc = pc;
    106}
    107
    108static int compiled_break;
    109
    110int kgdb_arch_handle_exception(int exception_vector, int signo,
    111			       int err_code, char *remcom_in_buffer,
    112			       char *remcom_out_buffer,
    113			       struct pt_regs *linux_regs)
    114{
    115	unsigned long addr;
    116	char *ptr;
    117
    118	switch (remcom_in_buffer[0]) {
    119	case 'D':
    120	case 'k':
    121	case 'c':
    122		/*
    123		 * Try to read optional parameter, pc unchanged if no parm.
    124		 * If this was a compiled breakpoint, we need to move
    125		 * to the next instruction or we will just breakpoint
    126		 * over and over again.
    127		 */
    128		ptr = &remcom_in_buffer[1];
    129		if (kgdb_hex2long(&ptr, &addr))
    130			linux_regs->ARM_pc = addr;
    131		else if (compiled_break == 1)
    132			linux_regs->ARM_pc += 4;
    133
    134		compiled_break = 0;
    135
    136		return 0;
    137	}
    138
    139	return -1;
    140}
    141
    142static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
    143{
    144	kgdb_handle_exception(1, SIGTRAP, 0, regs);
    145
    146	return 0;
    147}
    148
    149static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
    150{
    151	compiled_break = 1;
    152	kgdb_handle_exception(1, SIGTRAP, 0, regs);
    153
    154	return 0;
    155}
    156
    157static struct undef_hook kgdb_brkpt_arm_hook = {
    158	.instr_mask		= 0xffffffff,
    159	.instr_val		= KGDB_BREAKINST,
    160	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
    161	.cpsr_val		= SVC_MODE,
    162	.fn			= kgdb_brk_fn
    163};
    164
    165static struct undef_hook kgdb_brkpt_thumb_hook = {
    166	.instr_mask		= 0xffff,
    167	.instr_val		= KGDB_BREAKINST & 0xffff,
    168	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
    169	.cpsr_val		= PSR_T_BIT | SVC_MODE,
    170	.fn			= kgdb_brk_fn
    171};
    172
    173static struct undef_hook kgdb_compiled_brkpt_arm_hook = {
    174	.instr_mask		= 0xffffffff,
    175	.instr_val		= KGDB_COMPILED_BREAK,
    176	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
    177	.cpsr_val		= SVC_MODE,
    178	.fn			= kgdb_compiled_brk_fn
    179};
    180
    181static struct undef_hook kgdb_compiled_brkpt_thumb_hook = {
    182	.instr_mask		= 0xffff,
    183	.instr_val		= KGDB_COMPILED_BREAK & 0xffff,
    184	.cpsr_mask		= PSR_T_BIT | MODE_MASK,
    185	.cpsr_val		= PSR_T_BIT | SVC_MODE,
    186	.fn			= kgdb_compiled_brk_fn
    187};
    188
    189static int __kgdb_notify(struct die_args *args, unsigned long cmd)
    190{
    191	struct pt_regs *regs = args->regs;
    192
    193	if (kgdb_handle_exception(1, args->signr, cmd, regs))
    194		return NOTIFY_DONE;
    195	return NOTIFY_STOP;
    196}
    197static int
    198kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
    199{
    200	unsigned long flags;
    201	int ret;
    202
    203	local_irq_save(flags);
    204	ret = __kgdb_notify(ptr, cmd);
    205	local_irq_restore(flags);
    206
    207	return ret;
    208}
    209
    210static struct notifier_block kgdb_notifier = {
    211	.notifier_call	= kgdb_notify,
    212	.priority	= -INT_MAX,
    213};
    214
    215
    216/**
    217 *	kgdb_arch_init - Perform any architecture specific initalization.
    218 *
    219 *	This function will handle the initalization of any architecture
    220 *	specific callbacks.
    221 */
    222int kgdb_arch_init(void)
    223{
    224	int ret = register_die_notifier(&kgdb_notifier);
    225
    226	if (ret != 0)
    227		return ret;
    228
    229	register_undef_hook(&kgdb_brkpt_arm_hook);
    230	register_undef_hook(&kgdb_brkpt_thumb_hook);
    231	register_undef_hook(&kgdb_compiled_brkpt_arm_hook);
    232	register_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
    233
    234	return 0;
    235}
    236
    237/**
    238 *	kgdb_arch_exit - Perform any architecture specific uninitalization.
    239 *
    240 *	This function will handle the uninitalization of any architecture
    241 *	specific callbacks, for dynamic registration and unregistration.
    242 */
    243void kgdb_arch_exit(void)
    244{
    245	unregister_undef_hook(&kgdb_brkpt_arm_hook);
    246	unregister_undef_hook(&kgdb_brkpt_thumb_hook);
    247	unregister_undef_hook(&kgdb_compiled_brkpt_arm_hook);
    248	unregister_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
    249	unregister_die_notifier(&kgdb_notifier);
    250}
    251
    252int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
    253{
    254	int err;
    255
    256	/* patch_text() only supports int-sized breakpoints */
    257	BUILD_BUG_ON(sizeof(int) != BREAK_INSTR_SIZE);
    258
    259	err = copy_from_kernel_nofault(bpt->saved_instr, (char *)bpt->bpt_addr,
    260				BREAK_INSTR_SIZE);
    261	if (err)
    262		return err;
    263
    264	/* Machine is already stopped, so we can use __patch_text() directly */
    265	__patch_text((void *)bpt->bpt_addr,
    266		     *(unsigned int *)arch_kgdb_ops.gdb_bpt_instr);
    267
    268	return err;
    269}
    270
    271int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
    272{
    273	/* Machine is already stopped, so we can use __patch_text() directly */
    274	__patch_text((void *)bpt->bpt_addr, *(unsigned int *)bpt->saved_instr);
    275
    276	return 0;
    277}
    278
    279/*
    280 * Register our undef instruction hooks with ARM undef core.
    281 * We register a hook specifically looking for the KGB break inst
    282 * and we handle the normal undef case within the do_undefinstr
    283 * handler.
    284 */
    285const struct kgdb_arch arch_kgdb_ops = {
    286#ifndef __ARMEB__
    287	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
    288#else /* ! __ARMEB__ */
    289	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
    290#endif
    291};