1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
6 * Copyright (c) 2022 Helge Deller <deller@gmx.de>
10 #include <linux/kgdb.h>
11 #include <linux/string.h>
12 #include <linux/sched.h>
13 #include <linux/notifier.h>
14 #include <linux/kdebug.h>
15 #include <linux/uaccess.h>
16 #include <asm/ptrace.h>
17 #include <asm/traps.h>
18 #include <asm/processor.h>
19 #include <asm/text-patching.h>
20 #include <asm/cacheflush.h>
22 const struct kgdb_arch arch_kgdb_ops
= {
23 .gdb_bpt_instr
= { 0x03, 0xff, 0xa0, 0x1f }
26 static int __kgdb_notify(struct die_args
*args
, unsigned long cmd
)
28 struct pt_regs
*regs
= args
->regs
;
30 if (kgdb_handle_exception(1, args
->signr
, cmd
, regs
))
35 static int kgdb_notify(struct notifier_block
*self
,
36 unsigned long cmd
, void *ptr
)
41 local_irq_save(flags
);
42 ret
= __kgdb_notify(ptr
, cmd
);
43 local_irq_restore(flags
);
48 static struct notifier_block kgdb_notifier
= {
49 .notifier_call
= kgdb_notify
,
53 int kgdb_arch_init(void)
55 return register_die_notifier(&kgdb_notifier
);
58 void kgdb_arch_exit(void)
60 unregister_die_notifier(&kgdb_notifier
);
63 void pt_regs_to_gdb_regs(unsigned long *gdb_regs
, struct pt_regs
*regs
)
65 struct parisc_gdb_regs
*gr
= (struct parisc_gdb_regs
*)gdb_regs
;
67 memset(gr
, 0, sizeof(struct parisc_gdb_regs
));
69 memcpy(gr
->gpr
, regs
->gr
, sizeof(gr
->gpr
));
70 memcpy(gr
->fr
, regs
->fr
, sizeof(gr
->fr
));
72 gr
->sr0
= regs
->sr
[0];
73 gr
->sr1
= regs
->sr
[1];
74 gr
->sr2
= regs
->sr
[2];
75 gr
->sr3
= regs
->sr
[3];
76 gr
->sr4
= regs
->sr
[4];
77 gr
->sr5
= regs
->sr
[5];
78 gr
->sr6
= regs
->sr
[6];
79 gr
->sr7
= regs
->sr
[7];
85 gr
->ipsw
= regs
->ipsw
;
86 gr
->cr27
= regs
->cr27
;
88 gr
->iaoq_f
= regs
->iaoq
[0];
89 gr
->iasq_f
= regs
->iasq
[0];
91 gr
->iaoq_b
= regs
->iaoq
[1];
92 gr
->iasq_b
= regs
->iasq
[1];
95 void gdb_regs_to_pt_regs(unsigned long *gdb_regs
, struct pt_regs
*regs
)
97 struct parisc_gdb_regs
*gr
= (struct parisc_gdb_regs
*)gdb_regs
;
100 memcpy(regs
->gr
, gr
->gpr
, sizeof(regs
->gr
));
101 memcpy(regs
->fr
, gr
->fr
, sizeof(regs
->fr
));
103 regs
->sr
[0] = gr
->sr0
;
104 regs
->sr
[1] = gr
->sr1
;
105 regs
->sr
[2] = gr
->sr2
;
106 regs
->sr
[3] = gr
->sr3
;
107 regs
->sr
[4] = gr
->sr4
;
108 regs
->sr
[5] = gr
->sr5
;
109 regs
->sr
[6] = gr
->sr6
;
110 regs
->sr
[7] = gr
->sr7
;
116 regs
->ipsw
= gr
->ipsw
;
117 regs
->cr27
= gr
->cr27
;
119 regs
->iaoq
[0] = gr
->iaoq_f
;
120 regs
->iasq
[0] = gr
->iasq_f
;
122 regs
->iaoq
[1] = gr
->iaoq_b
;
123 regs
->iasq
[1] = gr
->iasq_b
;
126 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs
,
127 struct task_struct
*task
)
129 struct pt_regs
*regs
= task_pt_regs(task
);
130 unsigned long gr30
, iaoq
;
133 iaoq
= regs
->iaoq
[0];
135 regs
->gr
[30] = regs
->ksp
;
136 regs
->iaoq
[0] = regs
->kpc
;
137 pt_regs_to_gdb_regs(gdb_regs
, regs
);
140 regs
->iaoq
[0] = iaoq
;
144 static void step_instruction_queue(struct pt_regs
*regs
)
146 regs
->iaoq
[0] = regs
->iaoq
[1];
150 void kgdb_arch_set_pc(struct pt_regs
*regs
, unsigned long ip
)
153 regs
->iaoq
[1] = ip
+ 4;
156 int kgdb_arch_set_breakpoint(struct kgdb_bkpt
*bpt
)
158 int ret
= copy_from_kernel_nofault(bpt
->saved_instr
,
159 (char *)bpt
->bpt_addr
, BREAK_INSTR_SIZE
);
163 __patch_text((void *)bpt
->bpt_addr
,
164 *(unsigned int *)&arch_kgdb_ops
.gdb_bpt_instr
);
168 int kgdb_arch_remove_breakpoint(struct kgdb_bkpt
*bpt
)
170 __patch_text((void *)bpt
->bpt_addr
, *(unsigned int *)&bpt
->saved_instr
);
174 int kgdb_arch_handle_exception(int trap
, int signo
,
175 int err_code
, char *inbuf
, char *outbuf
,
176 struct pt_regs
*regs
)
185 kgdb_contthread
= NULL
;
186 kgdb_single_step
= 0;
188 if (kgdb_hex2long(&p
, &addr
))
189 kgdb_arch_set_pc(regs
, addr
);
190 else if (trap
== 9 && regs
->iir
==
191 PARISC_KGDB_COMPILED_BREAK_INSN
)
192 step_instruction_queue(regs
);
195 kgdb_single_step
= 1;
196 if (kgdb_hex2long(&p
, &addr
)) {
197 kgdb_arch_set_pc(regs
, addr
);
198 } else if (trap
== 9 && regs
->iir
==
199 PARISC_KGDB_COMPILED_BREAK_INSN
) {
200 step_instruction_queue(regs
);
205 regs
->gr
[0] |= PSW_R
;