1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021 Mitchell Horne <mhorne@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kdb.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/signal.h>
35
36 #include <machine/frame.h>
37 #include <machine/gdb_machdep.h>
38 #include <machine/pcb.h>
39 #include <machine/riscvreg.h>
40
41 #include <gdb/gdb.h>
42
43 void *
gdb_cpu_getreg(int regnum,size_t * regsz)44 gdb_cpu_getreg(int regnum, size_t *regsz)
45 {
46 *regsz = gdb_cpu_regsz(regnum);
47
48 if (kdb_thread == curthread) {
49 switch (regnum) {
50 case GDB_REG_RA: return (&kdb_frame->tf_ra);
51 case GDB_REG_PC: return (&kdb_frame->tf_sepc);
52 case GDB_REG_SSTATUS: return (&kdb_frame->tf_sstatus);
53 case GDB_REG_STVAL: return (&kdb_frame->tf_stval);
54 case GDB_REG_SCAUSE: return (&kdb_frame->tf_scause);
55 default:
56 if (regnum >= GDB_REG_A0 && regnum < GDB_REG_S2)
57 return (&kdb_frame->tf_a[regnum - GDB_REG_A0]);
58 if (regnum >= GDB_REG_T0 && regnum < GDB_REG_FP)
59 return (&kdb_frame->tf_t[regnum - GDB_REG_T0]);
60 if (regnum >= GDB_REG_T3 && regnum < GDB_REG_PC)
61 return (&kdb_frame->tf_t[regnum - GDB_REG_T3]);
62 break;
63 }
64 }
65 switch (regnum) {
66 case GDB_REG_PC: /* FALLTHROUGH */
67 case GDB_REG_RA: return (&kdb_thrctx->pcb_ra);
68 case GDB_REG_SP: return (&kdb_thrctx->pcb_sp);
69 case GDB_REG_GP: return (&kdb_thrctx->pcb_gp);
70 case GDB_REG_TP: return (&kdb_thrctx->pcb_tp);
71 case GDB_REG_FP: return (&kdb_thrctx->pcb_s[0]);
72 case GDB_REG_S1: return (&kdb_thrctx->pcb_s[1]);
73 default:
74 if (regnum >= GDB_REG_S2 && regnum < GDB_REG_T3)
75 return (&kdb_thrctx->pcb_s[regnum - GDB_REG_S2]);
76 break;
77 }
78
79 return (NULL);
80 }
81
82 void
gdb_cpu_setreg(int regnum,void * val)83 gdb_cpu_setreg(int regnum, void *val)
84 {
85 register_t regval = *(register_t *)val;
86
87 /* For curthread, keep the pcb and trapframe in sync. */
88 if (kdb_thread == curthread) {
89 switch (regnum) {
90 case GDB_REG_PC: kdb_frame->tf_sepc = regval; break;
91 case GDB_REG_RA: kdb_frame->tf_ra = regval; break;
92 case GDB_REG_SP: kdb_frame->tf_sp = regval; break;
93 case GDB_REG_GP: kdb_frame->tf_gp = regval; break;
94 case GDB_REG_TP: kdb_frame->tf_tp = regval; break;
95 case GDB_REG_FP: kdb_frame->tf_s[0] = regval; break;
96 case GDB_REG_S1: kdb_frame->tf_s[1] = regval; break;
97 case GDB_REG_SSTATUS: kdb_frame->tf_sstatus = regval; break;
98 case GDB_REG_STVAL: kdb_frame->tf_stval = regval; break;
99 case GDB_REG_SCAUSE: kdb_frame->tf_scause = regval; break;
100 default:
101 if (regnum >= GDB_REG_A0 && regnum < GDB_REG_S2)
102 kdb_frame->tf_a[regnum - GDB_REG_A0] = regval;
103 if (regnum >= GDB_REG_S2 && regnum < GDB_REG_T3)
104 kdb_frame->tf_s[regnum - GDB_REG_S2] = regval;
105 if (regnum >= GDB_REG_T0 && regnum < GDB_REG_FP)
106 kdb_frame->tf_t[regnum - GDB_REG_T0] = regval;
107 if (regnum >= GDB_REG_T3 && regnum < GDB_REG_PC)
108 kdb_frame->tf_t[regnum - GDB_REG_T3] = regval;
109 break;
110 }
111 }
112 switch (regnum) {
113 case GDB_REG_PC: /* FALLTHROUGH */
114 case GDB_REG_RA: kdb_thrctx->pcb_ra = regval; break;
115 case GDB_REG_SP: kdb_thrctx->pcb_sp = regval; break;
116 case GDB_REG_GP: kdb_thrctx->pcb_gp = regval; break;
117 case GDB_REG_TP: kdb_thrctx->pcb_tp = regval; break;
118 case GDB_REG_FP: kdb_thrctx->pcb_s[0] = regval; break;
119 case GDB_REG_S1: kdb_thrctx->pcb_s[1] = regval; break;
120 default:
121 if (regnum >= GDB_REG_S2 && regnum < GDB_REG_T3)
122 kdb_thrctx->pcb_s[regnum - GDB_REG_S2] = regval;
123 break;
124 }
125 }
126
127 int
gdb_cpu_signal(int type,int code)128 gdb_cpu_signal(int type, int code)
129 {
130
131 if (type == SCAUSE_BREAKPOINT)
132 return (SIGTRAP);
133
134 return (SIGEMT);
135 }
136