13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
282da3ff8SIngo Molnar /*
382da3ff8SIngo Molnar */
482da3ff8SIngo Molnar
582da3ff8SIngo Molnar /*
682da3ff8SIngo Molnar * Copyright (C) 2004 Amit S. Kale <amitkale@linsyssoft.com>
782da3ff8SIngo Molnar * Copyright (C) 2000-2001 VERITAS Software Corporation.
882da3ff8SIngo Molnar * Copyright (C) 2002 Andi Kleen, SuSE Labs
982da3ff8SIngo Molnar * Copyright (C) 2004 LinSysSoft Technologies Pvt. Ltd.
1082da3ff8SIngo Molnar * Copyright (C) 2007 MontaVista Software, Inc.
1182da3ff8SIngo Molnar * Copyright (C) 2007-2008 Jason Wessel, Wind River Systems, Inc.
1282da3ff8SIngo Molnar */
1382da3ff8SIngo Molnar /****************************************************************************
1482da3ff8SIngo Molnar * Contributor: Lake Stevens Instrument Division$
1582da3ff8SIngo Molnar * Written by: Glenn Engel $
1682da3ff8SIngo Molnar * Updated by: Amit Kale<akale@veritas.com>
1782da3ff8SIngo Molnar * Updated by: Tom Rini <trini@kernel.crashing.org>
1882da3ff8SIngo Molnar * Updated by: Jason Wessel <jason.wessel@windriver.com>
1982da3ff8SIngo Molnar * Modified for 386 by Jim Kingdon, Cygnus Support.
20*d9f6e12fSIngo Molnar * Original kgdb, compatibility with 2.1.xx kernel by
2182da3ff8SIngo Molnar * David Grothe <dave@gcom.com>
2282da3ff8SIngo Molnar * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
2382da3ff8SIngo Molnar * X86_64 changes from Andi Kleen's patch merged by Jim Houston
2482da3ff8SIngo Molnar */
2582da3ff8SIngo Molnar #include <linux/spinlock.h>
2682da3ff8SIngo Molnar #include <linux/kdebug.h>
2782da3ff8SIngo Molnar #include <linux/string.h>
2882da3ff8SIngo Molnar #include <linux/kernel.h>
2982da3ff8SIngo Molnar #include <linux/ptrace.h>
3082da3ff8SIngo Molnar #include <linux/sched.h>
3182da3ff8SIngo Molnar #include <linux/delay.h>
3282da3ff8SIngo Molnar #include <linux/kgdb.h>
3382da3ff8SIngo Molnar #include <linux/smp.h>
34d3597524SJason Wessel #include <linux/nmi.h>
35cc096749SJason Wessel #include <linux/hw_breakpoint.h>
363751d3e8SJason Wessel #include <linux/uaccess.h>
373751d3e8SJason Wessel #include <linux/memory.h>
3882da3ff8SIngo Molnar
3935de5b06SAndy Lutomirski #include <asm/text-patching.h>
4062edab90SK.Prasad #include <asm/debugreg.h>
4182da3ff8SIngo Molnar #include <asm/apicdef.h>
427b6aa335SIngo Molnar #include <asm/apic.h>
43166d7514SDon Zickus #include <asm/nmi.h>
447b32aeadSBrian Gerst #include <asm/switch_to.h>
4582da3ff8SIngo Molnar
4612bfa3deSJason Wessel struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
4782da3ff8SIngo Molnar {
4882da3ff8SIngo Molnar #ifdef CONFIG_X86_32
4912bfa3deSJason Wessel { "ax", 4, offsetof(struct pt_regs, ax) },
5012bfa3deSJason Wessel { "cx", 4, offsetof(struct pt_regs, cx) },
5112bfa3deSJason Wessel { "dx", 4, offsetof(struct pt_regs, dx) },
5212bfa3deSJason Wessel { "bx", 4, offsetof(struct pt_regs, bx) },
5312bfa3deSJason Wessel { "sp", 4, offsetof(struct pt_regs, sp) },
5412bfa3deSJason Wessel { "bp", 4, offsetof(struct pt_regs, bp) },
5512bfa3deSJason Wessel { "si", 4, offsetof(struct pt_regs, si) },
5612bfa3deSJason Wessel { "di", 4, offsetof(struct pt_regs, di) },
5712bfa3deSJason Wessel { "ip", 4, offsetof(struct pt_regs, ip) },
5812bfa3deSJason Wessel { "flags", 4, offsetof(struct pt_regs, flags) },
5912bfa3deSJason Wessel { "cs", 4, offsetof(struct pt_regs, cs) },
6012bfa3deSJason Wessel { "ss", 4, offsetof(struct pt_regs, ss) },
6112bfa3deSJason Wessel { "ds", 4, offsetof(struct pt_regs, ds) },
6212bfa3deSJason Wessel { "es", 4, offsetof(struct pt_regs, es) },
6382da3ff8SIngo Molnar #else
6412bfa3deSJason Wessel { "ax", 8, offsetof(struct pt_regs, ax) },
6512bfa3deSJason Wessel { "bx", 8, offsetof(struct pt_regs, bx) },
6612bfa3deSJason Wessel { "cx", 8, offsetof(struct pt_regs, cx) },
6712bfa3deSJason Wessel { "dx", 8, offsetof(struct pt_regs, dx) },
68f59df35fSSteffen Liebergeld { "si", 8, offsetof(struct pt_regs, si) },
6912bfa3deSJason Wessel { "di", 8, offsetof(struct pt_regs, di) },
7012bfa3deSJason Wessel { "bp", 8, offsetof(struct pt_regs, bp) },
7112bfa3deSJason Wessel { "sp", 8, offsetof(struct pt_regs, sp) },
7212bfa3deSJason Wessel { "r8", 8, offsetof(struct pt_regs, r8) },
7312bfa3deSJason Wessel { "r9", 8, offsetof(struct pt_regs, r9) },
7412bfa3deSJason Wessel { "r10", 8, offsetof(struct pt_regs, r10) },
7512bfa3deSJason Wessel { "r11", 8, offsetof(struct pt_regs, r11) },
7612bfa3deSJason Wessel { "r12", 8, offsetof(struct pt_regs, r12) },
7712bfa3deSJason Wessel { "r13", 8, offsetof(struct pt_regs, r13) },
7812bfa3deSJason Wessel { "r14", 8, offsetof(struct pt_regs, r14) },
7912bfa3deSJason Wessel { "r15", 8, offsetof(struct pt_regs, r15) },
8012bfa3deSJason Wessel { "ip", 8, offsetof(struct pt_regs, ip) },
8112bfa3deSJason Wessel { "flags", 4, offsetof(struct pt_regs, flags) },
8212bfa3deSJason Wessel { "cs", 4, offsetof(struct pt_regs, cs) },
8312bfa3deSJason Wessel { "ss", 4, offsetof(struct pt_regs, ss) },
84639077fbSJan Kiszka { "ds", 4, -1 },
85639077fbSJan Kiszka { "es", 4, -1 },
86cf6f196dSJason Wessel #endif
87639077fbSJan Kiszka { "fs", 4, -1 },
88639077fbSJan Kiszka { "gs", 4, -1 },
8912bfa3deSJason Wessel };
9012bfa3deSJason Wessel
dbg_set_reg(int regno,void * mem,struct pt_regs * regs)9112bfa3deSJason Wessel int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
9212bfa3deSJason Wessel {
9312bfa3deSJason Wessel if (
9412bfa3deSJason Wessel #ifdef CONFIG_X86_32
9512bfa3deSJason Wessel regno == GDB_SS || regno == GDB_FS || regno == GDB_GS ||
9612bfa3deSJason Wessel #endif
9712bfa3deSJason Wessel regno == GDB_SP || regno == GDB_ORIG_AX)
9812bfa3deSJason Wessel return 0;
9912bfa3deSJason Wessel
10012bfa3deSJason Wessel if (dbg_reg_def[regno].offset != -1)
10112bfa3deSJason Wessel memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
10212bfa3deSJason Wessel dbg_reg_def[regno].size);
10312bfa3deSJason Wessel return 0;
10412bfa3deSJason Wessel }
10512bfa3deSJason Wessel
dbg_get_reg(int regno,void * mem,struct pt_regs * regs)10612bfa3deSJason Wessel char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
10712bfa3deSJason Wessel {
10812bfa3deSJason Wessel if (regno == GDB_ORIG_AX) {
10912bfa3deSJason Wessel memcpy(mem, ®s->orig_ax, sizeof(regs->orig_ax));
11012bfa3deSJason Wessel return "orig_ax";
11112bfa3deSJason Wessel }
11212bfa3deSJason Wessel if (regno >= DBG_MAX_REG_NUM || regno < 0)
11312bfa3deSJason Wessel return NULL;
11412bfa3deSJason Wessel
11512bfa3deSJason Wessel if (dbg_reg_def[regno].offset != -1)
11612bfa3deSJason Wessel memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
11712bfa3deSJason Wessel dbg_reg_def[regno].size);
11812bfa3deSJason Wessel
11912bfa3deSJason Wessel #ifdef CONFIG_X86_32
12021431c29SJason Wessel switch (regno) {
12112bfa3deSJason Wessel case GDB_GS:
12212bfa3deSJason Wessel case GDB_FS:
12312bfa3deSJason Wessel *(unsigned long *)mem = 0xFFFF;
12412bfa3deSJason Wessel break;
12512bfa3deSJason Wessel }
12621431c29SJason Wessel #endif
12712bfa3deSJason Wessel return dbg_reg_def[regno].name;
12882da3ff8SIngo Molnar }
12982da3ff8SIngo Molnar
13082da3ff8SIngo Molnar /**
13182da3ff8SIngo Molnar * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs
13282da3ff8SIngo Molnar * @gdb_regs: A pointer to hold the registers in the order GDB wants.
13382da3ff8SIngo Molnar * @p: The &struct task_struct of the desired process.
13482da3ff8SIngo Molnar *
13582da3ff8SIngo Molnar * Convert the register values of the sleeping process in @p to
13682da3ff8SIngo Molnar * the format that GDB expects.
13782da3ff8SIngo Molnar * This function is called when kgdb does not have access to the
13882da3ff8SIngo Molnar * &struct pt_regs and therefore it should fill the gdb registers
13982da3ff8SIngo Molnar * @gdb_regs with what has been saved in &struct thread_struct
14082da3ff8SIngo Molnar * thread field during switch_to.
14182da3ff8SIngo Molnar */
sleeping_thread_to_gdb_regs(unsigned long * gdb_regs,struct task_struct * p)14282da3ff8SIngo Molnar void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
14382da3ff8SIngo Molnar {
144703a1edcSJason Wessel #ifndef CONFIG_X86_32
145703a1edcSJason Wessel u32 *gdb_regs32 = (u32 *)gdb_regs;
146703a1edcSJason Wessel #endif
14782da3ff8SIngo Molnar gdb_regs[GDB_AX] = 0;
14882da3ff8SIngo Molnar gdb_regs[GDB_BX] = 0;
14982da3ff8SIngo Molnar gdb_regs[GDB_CX] = 0;
15082da3ff8SIngo Molnar gdb_regs[GDB_DX] = 0;
15182da3ff8SIngo Molnar gdb_regs[GDB_SI] = 0;
15282da3ff8SIngo Molnar gdb_regs[GDB_DI] = 0;
1537b32aeadSBrian Gerst gdb_regs[GDB_BP] = ((struct inactive_task_frame *)p->thread.sp)->bp;
15482da3ff8SIngo Molnar #ifdef CONFIG_X86_32
15582da3ff8SIngo Molnar gdb_regs[GDB_DS] = __KERNEL_DS;
15682da3ff8SIngo Molnar gdb_regs[GDB_ES] = __KERNEL_DS;
15782da3ff8SIngo Molnar gdb_regs[GDB_PS] = 0;
15882da3ff8SIngo Molnar gdb_regs[GDB_CS] = __KERNEL_CS;
15982da3ff8SIngo Molnar gdb_regs[GDB_SS] = __KERNEL_DS;
16082da3ff8SIngo Molnar gdb_regs[GDB_FS] = 0xFFFF;
16182da3ff8SIngo Molnar gdb_regs[GDB_GS] = 0xFFFF;
16282da3ff8SIngo Molnar #else
16316363019SBrian Gerst gdb_regs32[GDB_PS] = 0;
164703a1edcSJason Wessel gdb_regs32[GDB_CS] = __KERNEL_CS;
165703a1edcSJason Wessel gdb_regs32[GDB_SS] = __KERNEL_DS;
16682da3ff8SIngo Molnar gdb_regs[GDB_R8] = 0;
16782da3ff8SIngo Molnar gdb_regs[GDB_R9] = 0;
16882da3ff8SIngo Molnar gdb_regs[GDB_R10] = 0;
16982da3ff8SIngo Molnar gdb_regs[GDB_R11] = 0;
17082da3ff8SIngo Molnar gdb_regs[GDB_R12] = 0;
17182da3ff8SIngo Molnar gdb_regs[GDB_R13] = 0;
17282da3ff8SIngo Molnar gdb_regs[GDB_R14] = 0;
17382da3ff8SIngo Molnar gdb_regs[GDB_R15] = 0;
17482da3ff8SIngo Molnar #endif
1754e047aa7SBrian Gerst gdb_regs[GDB_PC] = 0;
17682da3ff8SIngo Molnar gdb_regs[GDB_SP] = p->thread.sp;
17782da3ff8SIngo Molnar }
17882da3ff8SIngo Molnar
17964e9ee30SJason Wessel static struct hw_breakpoint {
18064e9ee30SJason Wessel unsigned enabled;
18164e9ee30SJason Wessel unsigned long addr;
182cc096749SJason Wessel int len;
183cc096749SJason Wessel int type;
1848c8aefceSNamhyung Kim struct perf_event * __percpu *pev;
185df493935SDongdong Deng } breakinfo[HBP_NUM];
18664e9ee30SJason Wessel
187031acd8cSJason Wessel static unsigned long early_dr7;
188031acd8cSJason Wessel
kgdb_correct_hw_break(void)18964e9ee30SJason Wessel static void kgdb_correct_hw_break(void)
19064e9ee30SJason Wessel {
19164e9ee30SJason Wessel int breakno;
19264e9ee30SJason Wessel
193df493935SDongdong Deng for (breakno = 0; breakno < HBP_NUM; breakno++) {
194cc096749SJason Wessel struct perf_event *bp;
195cc096749SJason Wessel struct arch_hw_breakpoint *info;
196cc096749SJason Wessel int val;
197cc096749SJason Wessel int cpu = raw_smp_processor_id();
198cc096749SJason Wessel if (!breakinfo[breakno].enabled)
199cc096749SJason Wessel continue;
200031acd8cSJason Wessel if (dbg_is_early) {
201031acd8cSJason Wessel set_debugreg(breakinfo[breakno].addr, breakno);
202031acd8cSJason Wessel early_dr7 |= encode_dr7(breakno,
203031acd8cSJason Wessel breakinfo[breakno].len,
204031acd8cSJason Wessel breakinfo[breakno].type);
205031acd8cSJason Wessel set_debugreg(early_dr7, 7);
206031acd8cSJason Wessel continue;
207031acd8cSJason Wessel }
208cc096749SJason Wessel bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
209cc096749SJason Wessel info = counter_arch_bp(bp);
210cc096749SJason Wessel if (bp->attr.disabled != 1)
211cc096749SJason Wessel continue;
212cc096749SJason Wessel bp->attr.bp_addr = breakinfo[breakno].addr;
213cc096749SJason Wessel bp->attr.bp_len = breakinfo[breakno].len;
214cc096749SJason Wessel bp->attr.bp_type = breakinfo[breakno].type;
215cc096749SJason Wessel info->address = breakinfo[breakno].addr;
216cc096749SJason Wessel info->len = breakinfo[breakno].len;
217cc096749SJason Wessel info->type = breakinfo[breakno].type;
218cc096749SJason Wessel val = arch_install_hw_breakpoint(bp);
219cc096749SJason Wessel if (!val)
220cc096749SJason Wessel bp->attr.disabled = 0;
22164e9ee30SJason Wessel }
222031acd8cSJason Wessel if (!dbg_is_early)
223cc096749SJason Wessel hw_breakpoint_restore();
22464e9ee30SJason Wessel }
22564e9ee30SJason Wessel
hw_break_reserve_slot(int breakno)2265352ae63SJason Wessel static int hw_break_reserve_slot(int breakno)
2275352ae63SJason Wessel {
2285352ae63SJason Wessel int cpu;
2295352ae63SJason Wessel int cnt = 0;
2305352ae63SJason Wessel struct perf_event **pevent;
2315352ae63SJason Wessel
232031acd8cSJason Wessel if (dbg_is_early)
233031acd8cSJason Wessel return 0;
234031acd8cSJason Wessel
2355352ae63SJason Wessel for_each_online_cpu(cpu) {
2365352ae63SJason Wessel cnt++;
2375352ae63SJason Wessel pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
2385352ae63SJason Wessel if (dbg_reserve_bp_slot(*pevent))
2395352ae63SJason Wessel goto fail;
2405352ae63SJason Wessel }
2415352ae63SJason Wessel
2425352ae63SJason Wessel return 0;
2435352ae63SJason Wessel
2445352ae63SJason Wessel fail:
2455352ae63SJason Wessel for_each_online_cpu(cpu) {
2465352ae63SJason Wessel cnt--;
2475352ae63SJason Wessel if (!cnt)
2485352ae63SJason Wessel break;
2495352ae63SJason Wessel pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
2505352ae63SJason Wessel dbg_release_bp_slot(*pevent);
2515352ae63SJason Wessel }
2525352ae63SJason Wessel return -1;
2535352ae63SJason Wessel }
2545352ae63SJason Wessel
hw_break_release_slot(int breakno)2555352ae63SJason Wessel static int hw_break_release_slot(int breakno)
2565352ae63SJason Wessel {
2575352ae63SJason Wessel struct perf_event **pevent;
2585352ae63SJason Wessel int cpu;
2595352ae63SJason Wessel
260031acd8cSJason Wessel if (dbg_is_early)
261031acd8cSJason Wessel return 0;
262031acd8cSJason Wessel
2635352ae63SJason Wessel for_each_online_cpu(cpu) {
2645352ae63SJason Wessel pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
2655352ae63SJason Wessel if (dbg_release_bp_slot(*pevent))
2665352ae63SJason Wessel /*
2670d2eb44fSLucas De Marchi * The debugger is responsible for handing the retry on
2685352ae63SJason Wessel * remove failure.
2695352ae63SJason Wessel */
2705352ae63SJason Wessel return -1;
2715352ae63SJason Wessel }
2725352ae63SJason Wessel return 0;
2735352ae63SJason Wessel }
2745352ae63SJason Wessel
27564e9ee30SJason Wessel static int
kgdb_remove_hw_break(unsigned long addr,int len,enum kgdb_bptype bptype)27664e9ee30SJason Wessel kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
27764e9ee30SJason Wessel {
27864e9ee30SJason Wessel int i;
27964e9ee30SJason Wessel
280df493935SDongdong Deng for (i = 0; i < HBP_NUM; i++)
28164e9ee30SJason Wessel if (breakinfo[i].addr == addr && breakinfo[i].enabled)
28264e9ee30SJason Wessel break;
283df493935SDongdong Deng if (i == HBP_NUM)
28464e9ee30SJason Wessel return -1;
28564e9ee30SJason Wessel
2865352ae63SJason Wessel if (hw_break_release_slot(i)) {
2875352ae63SJason Wessel printk(KERN_ERR "Cannot remove hw breakpoint at %lx\n", addr);
2885352ae63SJason Wessel return -1;
2895352ae63SJason Wessel }
29064e9ee30SJason Wessel breakinfo[i].enabled = 0;
29164e9ee30SJason Wessel
29264e9ee30SJason Wessel return 0;
29364e9ee30SJason Wessel }
29464e9ee30SJason Wessel
kgdb_remove_all_hw_break(void)29564e9ee30SJason Wessel static void kgdb_remove_all_hw_break(void)
29664e9ee30SJason Wessel {
29764e9ee30SJason Wessel int i;
298cc096749SJason Wessel int cpu = raw_smp_processor_id();
299cc096749SJason Wessel struct perf_event *bp;
30064e9ee30SJason Wessel
301df493935SDongdong Deng for (i = 0; i < HBP_NUM; i++) {
302cc096749SJason Wessel if (!breakinfo[i].enabled)
303cc096749SJason Wessel continue;
304cc096749SJason Wessel bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
30510a6e676SJason Wessel if (!bp->attr.disabled) {
30610a6e676SJason Wessel arch_uninstall_hw_breakpoint(bp);
30710a6e676SJason Wessel bp->attr.disabled = 1;
308cc096749SJason Wessel continue;
30910a6e676SJason Wessel }
310031acd8cSJason Wessel if (dbg_is_early)
311031acd8cSJason Wessel early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
312031acd8cSJason Wessel breakinfo[i].type);
31310a6e676SJason Wessel else if (hw_break_release_slot(i))
31410a6e676SJason Wessel printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n",
31510a6e676SJason Wessel breakinfo[i].addr);
31610a6e676SJason Wessel breakinfo[i].enabled = 0;
317cc096749SJason Wessel }
31864e9ee30SJason Wessel }
31964e9ee30SJason Wessel
32064e9ee30SJason Wessel static int
kgdb_set_hw_break(unsigned long addr,int len,enum kgdb_bptype bptype)32164e9ee30SJason Wessel kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype)
32264e9ee30SJason Wessel {
32364e9ee30SJason Wessel int i;
32464e9ee30SJason Wessel
325df493935SDongdong Deng for (i = 0; i < HBP_NUM; i++)
32664e9ee30SJason Wessel if (!breakinfo[i].enabled)
32764e9ee30SJason Wessel break;
328df493935SDongdong Deng if (i == HBP_NUM)
32964e9ee30SJason Wessel return -1;
33064e9ee30SJason Wessel
33164e9ee30SJason Wessel switch (bptype) {
33264e9ee30SJason Wessel case BP_HARDWARE_BREAKPOINT:
33364e9ee30SJason Wessel len = 1;
334cc096749SJason Wessel breakinfo[i].type = X86_BREAKPOINT_EXECUTE;
33564e9ee30SJason Wessel break;
33664e9ee30SJason Wessel case BP_WRITE_WATCHPOINT:
337cc096749SJason Wessel breakinfo[i].type = X86_BREAKPOINT_WRITE;
33864e9ee30SJason Wessel break;
33964e9ee30SJason Wessel case BP_ACCESS_WATCHPOINT:
340cc096749SJason Wessel breakinfo[i].type = X86_BREAKPOINT_RW;
34164e9ee30SJason Wessel break;
34264e9ee30SJason Wessel default:
34364e9ee30SJason Wessel return -1;
34464e9ee30SJason Wessel }
345cc096749SJason Wessel switch (len) {
346cc096749SJason Wessel case 1:
347cc096749SJason Wessel breakinfo[i].len = X86_BREAKPOINT_LEN_1;
348cc096749SJason Wessel break;
349cc096749SJason Wessel case 2:
350cc096749SJason Wessel breakinfo[i].len = X86_BREAKPOINT_LEN_2;
351cc096749SJason Wessel break;
352cc096749SJason Wessel case 4:
353cc096749SJason Wessel breakinfo[i].len = X86_BREAKPOINT_LEN_4;
354cc096749SJason Wessel break;
355cc096749SJason Wessel #ifdef CONFIG_X86_64
356cc096749SJason Wessel case 8:
357cc096749SJason Wessel breakinfo[i].len = X86_BREAKPOINT_LEN_8;
358cc096749SJason Wessel break;
359cc096749SJason Wessel #endif
360cc096749SJason Wessel default:
36164e9ee30SJason Wessel return -1;
362cc096749SJason Wessel }
36364e9ee30SJason Wessel breakinfo[i].addr = addr;
3645352ae63SJason Wessel if (hw_break_reserve_slot(i)) {
3655352ae63SJason Wessel breakinfo[i].addr = 0;
3665352ae63SJason Wessel return -1;
3675352ae63SJason Wessel }
368cc096749SJason Wessel breakinfo[i].enabled = 1;
36964e9ee30SJason Wessel
37064e9ee30SJason Wessel return 0;
37164e9ee30SJason Wessel }
37264e9ee30SJason Wessel
37364e9ee30SJason Wessel /**
37464e9ee30SJason Wessel * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb.
37564e9ee30SJason Wessel * @regs: Current &struct pt_regs.
37664e9ee30SJason Wessel *
37764e9ee30SJason Wessel * This function will be called if the particular architecture must
37864e9ee30SJason Wessel * disable hardware debugging while it is processing gdb packets or
37964e9ee30SJason Wessel * handling exception.
38064e9ee30SJason Wessel */
kgdb_disable_hw_debug(struct pt_regs * regs)381d7ba979dSDongdong Deng static void kgdb_disable_hw_debug(struct pt_regs *regs)
38264e9ee30SJason Wessel {
383cc096749SJason Wessel int i;
384cc096749SJason Wessel int cpu = raw_smp_processor_id();
385cc096749SJason Wessel struct perf_event *bp;
386cc096749SJason Wessel
38764e9ee30SJason Wessel /* Disable hardware debugging while we are in kgdb: */
38864e9ee30SJason Wessel set_debugreg(0UL, 7);
389df493935SDongdong Deng for (i = 0; i < HBP_NUM; i++) {
390cc096749SJason Wessel if (!breakinfo[i].enabled)
391cc096749SJason Wessel continue;
392031acd8cSJason Wessel if (dbg_is_early) {
393031acd8cSJason Wessel early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
394031acd8cSJason Wessel breakinfo[i].type);
395031acd8cSJason Wessel continue;
396031acd8cSJason Wessel }
397cc096749SJason Wessel bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
398cc096749SJason Wessel if (bp->attr.disabled == 1)
399cc096749SJason Wessel continue;
400cc096749SJason Wessel arch_uninstall_hw_breakpoint(bp);
401cc096749SJason Wessel bp->attr.disabled = 1;
402cc096749SJason Wessel }
40364e9ee30SJason Wessel }
40464e9ee30SJason Wessel
40582da3ff8SIngo Molnar #ifdef CONFIG_SMP
40682da3ff8SIngo Molnar /**
40782da3ff8SIngo Molnar * kgdb_roundup_cpus - Get other CPUs into a holding pattern
40882da3ff8SIngo Molnar *
40982da3ff8SIngo Molnar * On SMP systems, we need to get the attention of the other CPUs
41082da3ff8SIngo Molnar * and get them be in a known state. This should do what is needed
41182da3ff8SIngo Molnar * to get the other CPUs to call kgdb_wait(). Note that on some arches,
41282da3ff8SIngo Molnar * the NMI approach is not used for rounding up all the CPUs. For example,
4139ef7fa50SDouglas Anderson * in case of MIPS, smp_call_function() is used to roundup CPUs.
41482da3ff8SIngo Molnar *
41582da3ff8SIngo Molnar * On non-SMP systems, this is not called.
41682da3ff8SIngo Molnar */
kgdb_roundup_cpus(void)4179ef7fa50SDouglas Anderson void kgdb_roundup_cpus(void)
41882da3ff8SIngo Molnar {
41922ca7ee9SThomas Gleixner apic_send_IPI_allbutself(NMI_VECTOR);
42082da3ff8SIngo Molnar }
42182da3ff8SIngo Molnar #endif
42282da3ff8SIngo Molnar
42382da3ff8SIngo Molnar /**
42482da3ff8SIngo Molnar * kgdb_arch_handle_exception - Handle architecture specific GDB packets.
425c15acff3SWanpeng Li * @e_vector: The error vector of the exception that happened.
42682da3ff8SIngo Molnar * @signo: The signal number of the exception that happened.
42782da3ff8SIngo Molnar * @err_code: The error code of the exception that happened.
428c15acff3SWanpeng Li * @remcomInBuffer: The buffer of the packet we have read.
429c15acff3SWanpeng Li * @remcomOutBuffer: The buffer of %BUFMAX bytes to write a packet into.
430c15acff3SWanpeng Li * @linux_regs: The &struct pt_regs of the current process.
43182da3ff8SIngo Molnar *
43282da3ff8SIngo Molnar * This function MUST handle the 'c' and 's' command packets,
43382da3ff8SIngo Molnar * as well packets to set / remove a hardware breakpoint, if used.
43482da3ff8SIngo Molnar * If there are additional packets which the hardware needs to handle,
43582da3ff8SIngo Molnar * they are handled here. The code should return -1 if it wants to
43682da3ff8SIngo Molnar * process more packets, and a %0 or %1 if it wants to exit from the
43782da3ff8SIngo Molnar * kgdb callback.
43882da3ff8SIngo Molnar */
kgdb_arch_handle_exception(int e_vector,int signo,int err_code,char * remcomInBuffer,char * remcomOutBuffer,struct pt_regs * linux_regs)43982da3ff8SIngo Molnar int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
44082da3ff8SIngo Molnar char *remcomInBuffer, char *remcomOutBuffer,
44182da3ff8SIngo Molnar struct pt_regs *linux_regs)
44282da3ff8SIngo Molnar {
44382da3ff8SIngo Molnar unsigned long addr;
44482da3ff8SIngo Molnar char *ptr;
44582da3ff8SIngo Molnar
44682da3ff8SIngo Molnar switch (remcomInBuffer[0]) {
44782da3ff8SIngo Molnar case 'c':
44882da3ff8SIngo Molnar case 's':
44982da3ff8SIngo Molnar /* try to read optional parameter, pc unchanged if no parm */
45082da3ff8SIngo Molnar ptr = &remcomInBuffer[1];
45182da3ff8SIngo Molnar if (kgdb_hex2long(&ptr, &addr))
45282da3ff8SIngo Molnar linux_regs->ip = addr;
453df561f66SGustavo A. R. Silva fallthrough;
454737a460fSJason Wessel case 'D':
455737a460fSJason Wessel case 'k':
45682da3ff8SIngo Molnar /* clear the trace bit */
457fda31d7dSHarvey Harrison linux_regs->flags &= ~X86_EFLAGS_TF;
45882da3ff8SIngo Molnar atomic_set(&kgdb_cpu_doing_single_step, -1);
45982da3ff8SIngo Molnar
46082da3ff8SIngo Molnar /* set the trace bit if we're stepping */
46182da3ff8SIngo Molnar if (remcomInBuffer[0] == 's') {
462fda31d7dSHarvey Harrison linux_regs->flags |= X86_EFLAGS_TF;
46382da3ff8SIngo Molnar atomic_set(&kgdb_cpu_doing_single_step,
46482da3ff8SIngo Molnar raw_smp_processor_id());
46582da3ff8SIngo Molnar }
46682da3ff8SIngo Molnar
46782da3ff8SIngo Molnar return 0;
46882da3ff8SIngo Molnar }
46982da3ff8SIngo Molnar
47082da3ff8SIngo Molnar /* this means that we do not want to exit from the handler: */
47182da3ff8SIngo Molnar return -1;
47282da3ff8SIngo Molnar }
47382da3ff8SIngo Molnar
47482da3ff8SIngo Molnar static inline int
single_step_cont(struct pt_regs * regs,struct die_args * args)47582da3ff8SIngo Molnar single_step_cont(struct pt_regs *regs, struct die_args *args)
47682da3ff8SIngo Molnar {
47782da3ff8SIngo Molnar /*
47882da3ff8SIngo Molnar * Single step exception from kernel space to user space so
47982da3ff8SIngo Molnar * eat the exception and continue the process:
48082da3ff8SIngo Molnar */
48182da3ff8SIngo Molnar printk(KERN_ERR "KGDB: trap/step from kernel to user space, "
48282da3ff8SIngo Molnar "resuming...\n");
48382da3ff8SIngo Molnar kgdb_arch_handle_exception(args->trapnr, args->signr,
48482da3ff8SIngo Molnar args->err, "c", "", regs);
48562edab90SK.Prasad /*
48662edab90SK.Prasad * Reset the BS bit in dr6 (pointed by args->err) to
48762edab90SK.Prasad * denote completion of processing
48862edab90SK.Prasad */
48962edab90SK.Prasad (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP;
49082da3ff8SIngo Molnar
49182da3ff8SIngo Molnar return NOTIFY_STOP;
49282da3ff8SIngo Molnar }
49382da3ff8SIngo Molnar
4940d44975dSDenys Vlasenko static DECLARE_BITMAP(was_in_debug_nmi, NR_CPUS);
495d3597524SJason Wessel
kgdb_nmi_handler(unsigned int cmd,struct pt_regs * regs)4969c48f1c6SDon Zickus static int kgdb_nmi_handler(unsigned int cmd, struct pt_regs *regs)
49782da3ff8SIngo Molnar {
4980d44975dSDenys Vlasenko int cpu;
4990d44975dSDenys Vlasenko
50082da3ff8SIngo Molnar switch (cmd) {
5019c48f1c6SDon Zickus case NMI_LOCAL:
50282da3ff8SIngo Molnar if (atomic_read(&kgdb_active) != -1) {
50382da3ff8SIngo Molnar /* KGDB CPU roundup */
5040d44975dSDenys Vlasenko cpu = raw_smp_processor_id();
5050d44975dSDenys Vlasenko kgdb_nmicallback(cpu, regs);
5060d44975dSDenys Vlasenko set_bit(cpu, was_in_debug_nmi);
507d3597524SJason Wessel touch_nmi_watchdog();
5080d44975dSDenys Vlasenko
5099c48f1c6SDon Zickus return NMI_HANDLED;
51082da3ff8SIngo Molnar }
5119c48f1c6SDon Zickus break;
51282da3ff8SIngo Molnar
5139c48f1c6SDon Zickus case NMI_UNKNOWN:
5140d44975dSDenys Vlasenko cpu = raw_smp_processor_id();
5150d44975dSDenys Vlasenko
5160d44975dSDenys Vlasenko if (__test_and_clear_bit(cpu, was_in_debug_nmi))
5179c48f1c6SDon Zickus return NMI_HANDLED;
5180d44975dSDenys Vlasenko
5199c48f1c6SDon Zickus break;
5209c48f1c6SDon Zickus default:
5219c48f1c6SDon Zickus /* do nothing */
5229c48f1c6SDon Zickus break;
5239c48f1c6SDon Zickus }
5249c48f1c6SDon Zickus return NMI_DONE;
5259c48f1c6SDon Zickus }
52682da3ff8SIngo Molnar
__kgdb_notify(struct die_args * args,unsigned long cmd)5279c48f1c6SDon Zickus static int __kgdb_notify(struct die_args *args, unsigned long cmd)
5289c48f1c6SDon Zickus {
5299c48f1c6SDon Zickus struct pt_regs *regs = args->regs;
5309c48f1c6SDon Zickus
5319c48f1c6SDon Zickus switch (cmd) {
53282da3ff8SIngo Molnar case DIE_DEBUG:
533cc096749SJason Wessel if (atomic_read(&kgdb_cpu_doing_single_step) != -1) {
534d7161a65SJason Wessel if (user_mode(regs))
53582da3ff8SIngo Molnar return single_step_cont(regs, args);
536d7161a65SJason Wessel break;
537d7161a65SJason Wessel } else if (test_thread_flag(TIF_SINGLESTEP))
538d7161a65SJason Wessel /* This means a user thread is single stepping
539d7161a65SJason Wessel * a system call which should be ignored
540d7161a65SJason Wessel */
541d7161a65SJason Wessel return NOTIFY_DONE;
542df561f66SGustavo A. R. Silva fallthrough;
54382da3ff8SIngo Molnar default:
54482da3ff8SIngo Molnar if (user_mode(regs))
54582da3ff8SIngo Molnar return NOTIFY_DONE;
54682da3ff8SIngo Molnar }
54782da3ff8SIngo Molnar
548f503b5aeSJason Wessel if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs))
54982da3ff8SIngo Molnar return NOTIFY_DONE;
55082da3ff8SIngo Molnar
551737a460fSJason Wessel /* Must touch watchdog before return to normal operation */
552737a460fSJason Wessel touch_nmi_watchdog();
55382da3ff8SIngo Molnar return NOTIFY_STOP;
55482da3ff8SIngo Molnar }
55582da3ff8SIngo Molnar
kgdb_ll_trap(int cmd,const char * str,struct pt_regs * regs,long err,int trap,int sig)556f503b5aeSJason Wessel int kgdb_ll_trap(int cmd, const char *str,
557f503b5aeSJason Wessel struct pt_regs *regs, long err, int trap, int sig)
558f503b5aeSJason Wessel {
559f503b5aeSJason Wessel struct die_args args = {
560f503b5aeSJason Wessel .regs = regs,
561f503b5aeSJason Wessel .str = str,
562f503b5aeSJason Wessel .err = err,
563f503b5aeSJason Wessel .trapnr = trap,
564f503b5aeSJason Wessel .signr = sig,
565f503b5aeSJason Wessel
566f503b5aeSJason Wessel };
567f503b5aeSJason Wessel
568f503b5aeSJason Wessel if (!kgdb_io_module_registered)
569f503b5aeSJason Wessel return NOTIFY_DONE;
570f503b5aeSJason Wessel
571f503b5aeSJason Wessel return __kgdb_notify(&args, cmd);
572f503b5aeSJason Wessel }
573f503b5aeSJason Wessel
57482da3ff8SIngo Molnar static int
kgdb_notify(struct notifier_block * self,unsigned long cmd,void * ptr)57582da3ff8SIngo Molnar kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
57682da3ff8SIngo Molnar {
57782da3ff8SIngo Molnar unsigned long flags;
57882da3ff8SIngo Molnar int ret;
57982da3ff8SIngo Molnar
58082da3ff8SIngo Molnar local_irq_save(flags);
58182da3ff8SIngo Molnar ret = __kgdb_notify(ptr, cmd);
58282da3ff8SIngo Molnar local_irq_restore(flags);
58382da3ff8SIngo Molnar
58482da3ff8SIngo Molnar return ret;
58582da3ff8SIngo Molnar }
58682da3ff8SIngo Molnar
58782da3ff8SIngo Molnar static struct notifier_block kgdb_notifier = {
58882da3ff8SIngo Molnar .notifier_call = kgdb_notify,
58982da3ff8SIngo Molnar };
59082da3ff8SIngo Molnar
59182da3ff8SIngo Molnar /**
5926a6256f9SAdam Buchbinder * kgdb_arch_init - Perform any architecture specific initialization.
59382da3ff8SIngo Molnar *
5946a6256f9SAdam Buchbinder * This function will handle the initialization of any architecture
59582da3ff8SIngo Molnar * specific callbacks.
59682da3ff8SIngo Molnar */
kgdb_arch_init(void)59782da3ff8SIngo Molnar int kgdb_arch_init(void)
59882da3ff8SIngo Molnar {
5999c48f1c6SDon Zickus int retval;
6009c48f1c6SDon Zickus
6019c48f1c6SDon Zickus retval = register_die_notifier(&kgdb_notifier);
6029c48f1c6SDon Zickus if (retval)
6039c48f1c6SDon Zickus goto out;
6049c48f1c6SDon Zickus
6059c48f1c6SDon Zickus retval = register_nmi_handler(NMI_LOCAL, kgdb_nmi_handler,
6069c48f1c6SDon Zickus 0, "kgdb");
6079c48f1c6SDon Zickus if (retval)
6089c48f1c6SDon Zickus goto out1;
6099c48f1c6SDon Zickus
6109c48f1c6SDon Zickus retval = register_nmi_handler(NMI_UNKNOWN, kgdb_nmi_handler,
6119c48f1c6SDon Zickus 0, "kgdb");
6129c48f1c6SDon Zickus
6139c48f1c6SDon Zickus if (retval)
6149c48f1c6SDon Zickus goto out2;
6159c48f1c6SDon Zickus
6169c48f1c6SDon Zickus return retval;
6179c48f1c6SDon Zickus
6189c48f1c6SDon Zickus out2:
6199c48f1c6SDon Zickus unregister_nmi_handler(NMI_LOCAL, "kgdb");
6209c48f1c6SDon Zickus out1:
6219c48f1c6SDon Zickus unregister_die_notifier(&kgdb_notifier);
6229c48f1c6SDon Zickus out:
6239c48f1c6SDon Zickus return retval;
6240b4b3827SJason Wessel }
6250b4b3827SJason Wessel
kgdb_hw_overflow_handler(struct perf_event * event,struct perf_sample_data * data,struct pt_regs * regs)626a8b0ca17SPeter Zijlstra static void kgdb_hw_overflow_handler(struct perf_event *event,
627ba773f7cSJason Wessel struct perf_sample_data *data, struct pt_regs *regs)
628ba773f7cSJason Wessel {
629fad99facSJason Wessel struct task_struct *tsk = current;
630fad99facSJason Wessel int i;
631fad99facSJason Wessel
632d53d9bc0SPeter Zijlstra for (i = 0; i < 4; i++) {
633fad99facSJason Wessel if (breakinfo[i].enabled)
634d53d9bc0SPeter Zijlstra tsk->thread.virtual_dr6 |= (DR_TRAP0 << i);
635d53d9bc0SPeter Zijlstra }
636ba773f7cSJason Wessel }
637ba773f7cSJason Wessel
kgdb_arch_late(void)6380b4b3827SJason Wessel void kgdb_arch_late(void)
6390b4b3827SJason Wessel {
640cc096749SJason Wessel int i, cpu;
641cc096749SJason Wessel struct perf_event_attr attr;
642cc096749SJason Wessel struct perf_event **pevent;
643cc096749SJason Wessel
644cc096749SJason Wessel /*
645*d9f6e12fSIngo Molnar * Pre-allocate the hw breakpoint instructions in the non-atomic
646cc096749SJason Wessel * portion of kgdb because this operation requires mutexs to
647cc096749SJason Wessel * complete.
648cc096749SJason Wessel */
649ab310b5eSJason Wessel hw_breakpoint_init(&attr);
650cc096749SJason Wessel attr.bp_addr = (unsigned long)kgdb_arch_init;
651cc096749SJason Wessel attr.bp_len = HW_BREAKPOINT_LEN_1;
652cc096749SJason Wessel attr.bp_type = HW_BREAKPOINT_W;
653cc096749SJason Wessel attr.disabled = 1;
654df493935SDongdong Deng for (i = 0; i < HBP_NUM; i++) {
6550b4b3827SJason Wessel if (breakinfo[i].pev)
6560b4b3827SJason Wessel continue;
6574dc0da86SAvi Kivity breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL, NULL);
65891b152aaSJason Wessel if (IS_ERR((void * __force)breakinfo[i].pev)) {
6590b4b3827SJason Wessel printk(KERN_ERR "kgdb: Could not allocate hw"
6600b4b3827SJason Wessel "breakpoints\nDisabling the kernel debugger\n");
661cc096749SJason Wessel breakinfo[i].pev = NULL;
662cc096749SJason Wessel kgdb_arch_exit();
6630b4b3827SJason Wessel return;
664cc096749SJason Wessel }
665cc096749SJason Wessel for_each_online_cpu(cpu) {
666cc096749SJason Wessel pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
667cc096749SJason Wessel pevent[0]->hw.sample_period = 1;
668ba773f7cSJason Wessel pevent[0]->overflow_handler = kgdb_hw_overflow_handler;
669cc096749SJason Wessel if (pevent[0]->destroy != NULL) {
670cc096749SJason Wessel pevent[0]->destroy = NULL;
671cc096749SJason Wessel release_bp_slot(*pevent);
672cc096749SJason Wessel }
673cc096749SJason Wessel }
674cc096749SJason Wessel }
67582da3ff8SIngo Molnar }
67682da3ff8SIngo Molnar
67782da3ff8SIngo Molnar /**
67882da3ff8SIngo Molnar * kgdb_arch_exit - Perform any architecture specific uninitalization.
67982da3ff8SIngo Molnar *
68082da3ff8SIngo Molnar * This function will handle the uninitalization of any architecture
68182da3ff8SIngo Molnar * specific callbacks, for dynamic registration and unregistration.
68282da3ff8SIngo Molnar */
kgdb_arch_exit(void)68382da3ff8SIngo Molnar void kgdb_arch_exit(void)
68482da3ff8SIngo Molnar {
685cc096749SJason Wessel int i;
686cc096749SJason Wessel for (i = 0; i < 4; i++) {
687cc096749SJason Wessel if (breakinfo[i].pev) {
688cc096749SJason Wessel unregister_wide_hw_breakpoint(breakinfo[i].pev);
689cc096749SJason Wessel breakinfo[i].pev = NULL;
690cc096749SJason Wessel }
691cc096749SJason Wessel }
6929c48f1c6SDon Zickus unregister_nmi_handler(NMI_UNKNOWN, "kgdb");
6939c48f1c6SDon Zickus unregister_nmi_handler(NMI_LOCAL, "kgdb");
69482da3ff8SIngo Molnar unregister_die_notifier(&kgdb_notifier);
69582da3ff8SIngo Molnar }
69682da3ff8SIngo Molnar
69782da3ff8SIngo Molnar /**
69882da3ff8SIngo Molnar * kgdb_skipexception - Bail out of KGDB when we've been triggered.
69982da3ff8SIngo Molnar * @exception: Exception vector number
70082da3ff8SIngo Molnar * @regs: Current &struct pt_regs.
70182da3ff8SIngo Molnar *
70282da3ff8SIngo Molnar * On some architectures we need to skip a breakpoint exception when
70382da3ff8SIngo Molnar * it occurs after a breakpoint has been removed.
70482da3ff8SIngo Molnar *
70582da3ff8SIngo Molnar * Skip an int3 exception when it occurs after a breakpoint has been
70682da3ff8SIngo Molnar * removed. Backtrack eip by 1 since the int3 would have caused it to
70782da3ff8SIngo Molnar * increment by 1.
70882da3ff8SIngo Molnar */
kgdb_skipexception(int exception,struct pt_regs * regs)70982da3ff8SIngo Molnar int kgdb_skipexception(int exception, struct pt_regs *regs)
71082da3ff8SIngo Molnar {
71182da3ff8SIngo Molnar if (exception == 3 && kgdb_isremovedbreak(regs->ip - 1)) {
71282da3ff8SIngo Molnar regs->ip -= 1;
71382da3ff8SIngo Molnar return 1;
71482da3ff8SIngo Molnar }
71582da3ff8SIngo Molnar return 0;
71682da3ff8SIngo Molnar }
71782da3ff8SIngo Molnar
kgdb_arch_pc(int exception,struct pt_regs * regs)71882da3ff8SIngo Molnar unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
71982da3ff8SIngo Molnar {
72082da3ff8SIngo Molnar if (exception == 3)
72182da3ff8SIngo Molnar return instruction_pointer(regs) - 1;
72282da3ff8SIngo Molnar return instruction_pointer(regs);
72382da3ff8SIngo Molnar }
72482da3ff8SIngo Molnar
kgdb_arch_set_pc(struct pt_regs * regs,unsigned long ip)725dcc78711SJason Wessel void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
726dcc78711SJason Wessel {
727dcc78711SJason Wessel regs->ip = ip;
728dcc78711SJason Wessel }
729dcc78711SJason Wessel
kgdb_arch_set_breakpoint(struct kgdb_bkpt * bpt)7303751d3e8SJason Wessel int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
7313751d3e8SJason Wessel {
7323751d3e8SJason Wessel int err;
7333751d3e8SJason Wessel
7343751d3e8SJason Wessel bpt->type = BP_BREAKPOINT;
735fe557319SChristoph Hellwig err = copy_from_kernel_nofault(bpt->saved_instr, (char *)bpt->bpt_addr,
7363751d3e8SJason Wessel BREAK_INSTR_SIZE);
7373751d3e8SJason Wessel if (err)
7383751d3e8SJason Wessel return err;
739fe557319SChristoph Hellwig err = copy_to_kernel_nofault((char *)bpt->bpt_addr,
7403751d3e8SJason Wessel arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
7413751d3e8SJason Wessel if (!err)
7423751d3e8SJason Wessel return err;
7433751d3e8SJason Wessel /*
744e836673cSNadav Amit * It is safe to call text_poke_kgdb() because normal kernel execution
7453751d3e8SJason Wessel * is stopped on all cores, so long as the text_mutex is not locked.
7463751d3e8SJason Wessel */
7473751d3e8SJason Wessel if (mutex_is_locked(&text_mutex))
7483751d3e8SJason Wessel return -EBUSY;
749e836673cSNadav Amit text_poke_kgdb((void *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr,
7503751d3e8SJason Wessel BREAK_INSTR_SIZE);
7513751d3e8SJason Wessel bpt->type = BP_POKE_BREAKPOINT;
7529ccaf77cSKees Cook
75371ab8323SMatt Mullins return 0;
7543751d3e8SJason Wessel }
7553751d3e8SJason Wessel
kgdb_arch_remove_breakpoint(struct kgdb_bkpt * bpt)7563751d3e8SJason Wessel int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
7573751d3e8SJason Wessel {
7583751d3e8SJason Wessel if (bpt->type != BP_POKE_BREAKPOINT)
7593751d3e8SJason Wessel goto knl_write;
7603751d3e8SJason Wessel /*
761e836673cSNadav Amit * It is safe to call text_poke_kgdb() because normal kernel execution
7623751d3e8SJason Wessel * is stopped on all cores, so long as the text_mutex is not locked.
7633751d3e8SJason Wessel */
7643751d3e8SJason Wessel if (mutex_is_locked(&text_mutex))
7653751d3e8SJason Wessel goto knl_write;
766e836673cSNadav Amit text_poke_kgdb((void *)bpt->bpt_addr, bpt->saved_instr,
767e836673cSNadav Amit BREAK_INSTR_SIZE);
76886a22057SNadav Amit return 0;
7699ccaf77cSKees Cook
7703751d3e8SJason Wessel knl_write:
771fe557319SChristoph Hellwig return copy_to_kernel_nofault((char *)bpt->bpt_addr,
7723751d3e8SJason Wessel (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
7733751d3e8SJason Wessel }
7743751d3e8SJason Wessel
775cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops = {
77682da3ff8SIngo Molnar /* Breakpoint instruction: */
77782da3ff8SIngo Molnar .gdb_bpt_instr = { 0xcc },
77864e9ee30SJason Wessel .flags = KGDB_HW_BREAKPOINT,
77964e9ee30SJason Wessel .set_hw_breakpoint = kgdb_set_hw_break,
78064e9ee30SJason Wessel .remove_hw_breakpoint = kgdb_remove_hw_break,
781d7ba979dSDongdong Deng .disable_hw_break = kgdb_disable_hw_debug,
78264e9ee30SJason Wessel .remove_all_hw_break = kgdb_remove_all_hw_break,
78364e9ee30SJason Wessel .correct_hw_break = kgdb_correct_hw_break,
78482da3ff8SIngo Molnar };
785