xref: /freebsd/sys/riscv/riscv/gdb_machdep.c (revision 81ad6265)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 *
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
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
128 gdb_cpu_signal(int type, int code)
129 {
130 
131 	if (type == SCAUSE_BREAKPOINT)
132 		return (SIGTRAP);
133 
134 	return (SIGEMT);
135 }
136