diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv --- a/sys/conf/files.riscv +++ b/sys/conf/files.riscv @@ -46,6 +46,7 @@ riscv/riscv/elf_machdep.c standard riscv/riscv/exception.S standard riscv/riscv/exec_machdep.c standard +riscv/riscv/gdb_machdep.c optional gdb riscv/riscv/intr_machdep.c standard riscv/riscv/identcpu.c standard riscv/riscv/locore.S standard no-obj diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -173,7 +173,7 @@ options KDB_TRACE # Print a stack trace for a panic. # For full debugger support use (turn off in stable branch): options DDB # Support DDB. -# options GDB # Support remote GDB. +options GDB # Support remote GDB. options DEADLKRES # Enable the deadlock resolver options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS diff --git a/sys/riscv/conf/NOTES b/sys/riscv/conf/NOTES --- a/sys/riscv/conf/NOTES +++ b/sys/riscv/conf/NOTES @@ -90,9 +90,6 @@ nooptions COMPAT_FREEBSD10 nooptions COMPAT_FREEBSD11 -# No support for remote GDB -nooptions GDB - # riscv doesn't support inb/outb, so disable chipset probing which needs it nooptions PPC_PROBE_CHIPSET diff --git a/sys/riscv/include/gdb_machdep.h b/sys/riscv/include/gdb_machdep.h new file mode 100644 --- /dev/null +++ b/sys/riscv/include/gdb_machdep.h @@ -0,0 +1,88 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Mitchell Horne + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_GDB_MACHDEP_H_ +#define _MACHINE_GDB_MACHDEP_H_ + +#define GDB_BUFSZ 4096 +#define GDB_NREGS 33 +#define GDB_REG_ZERO 0 +#define GDB_REG_RA 1 +#define GDB_REG_SP 2 +#define GDB_REG_GP 3 +#define GDB_REG_TP 4 +#define GDB_REG_T0 5 +#define GDB_REG_FP 8 +#define GDB_REG_S1 9 +#define GDB_REG_A0 10 +#define GDB_REG_S2 18 +#define GDB_REG_T3 28 +#define GDB_REG_PC 32 +#define GDB_REG_CSR_BASE 65 +#define GDB_REG_SSTATUS (GDB_REG_CSR_BASE + 0x100) +#define GDB_REG_SCAUSE (GDB_REG_CSR_BASE + 0x142) +#define GDB_REG_STVAL (GDB_REG_CSR_BASE + 0x143) +_Static_assert(GDB_BUFSZ >= (GDB_NREGS * 8), "buffer fits 'g' regs"); + +static __inline size_t +gdb_cpu_regsz(int regnum __unused) +{ + + return (8); +} + +static __inline int +gdb_cpu_query(void) +{ + return (0); +} + +static __inline void * +gdb_begin_write(void) +{ + + return (NULL); +} + +static __inline void +gdb_end_write(void *arg __unused) +{ + +} + +static __inline void +gdb_cpu_stop_reason(int type __unused, int code __unused) +{ + +} + +void *gdb_cpu_getreg(int, size_t *); +void gdb_cpu_setreg(int, void *); +int gdb_cpu_signal(int, int); + +#endif /* !_MACHINE_GDB_MACHDEP_H_ */ diff --git a/sys/riscv/riscv/gdb_machdep.c b/sys/riscv/riscv/gdb_machdep.c new file mode 100644 --- /dev/null +++ b/sys/riscv/riscv/gdb_machdep.c @@ -0,0 +1,135 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Mitchell Horne + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +void * +gdb_cpu_getreg(int regnum, size_t *regsz) +{ + *regsz = gdb_cpu_regsz(regnum); + + if (kdb_thread == curthread) { + switch (regnum) { + case GDB_REG_RA: return (&kdb_frame->tf_ra); + case GDB_REG_PC: return (&kdb_frame->tf_sepc); + case GDB_REG_SSTATUS: return (&kdb_frame->tf_sstatus); + case GDB_REG_STVAL: return (&kdb_frame->tf_stval); + case GDB_REG_SCAUSE: return (&kdb_frame->tf_scause); + default: + if (regnum >= GDB_REG_A0 && regnum < GDB_REG_S2) + return (&kdb_frame->tf_a[regnum - GDB_REG_A0]); + if (regnum >= GDB_REG_T0 && regnum < GDB_REG_FP) + return (&kdb_frame->tf_t[regnum - GDB_REG_T0]); + if (regnum >= GDB_REG_T3 && regnum < GDB_REG_PC) + return (&kdb_frame->tf_t[regnum - GDB_REG_T3]); + break; + } + } + switch (regnum) { + case GDB_REG_PC: /* FALLTHROUGH */ + case GDB_REG_RA: return (&kdb_thrctx->pcb_ra); + case GDB_REG_SP: return (&kdb_thrctx->pcb_sp); + case GDB_REG_GP: return (&kdb_thrctx->pcb_gp); + case GDB_REG_TP: return (&kdb_thrctx->pcb_tp); + case GDB_REG_FP: return (&kdb_thrctx->pcb_s[0]); + case GDB_REG_S1: return (&kdb_thrctx->pcb_s[1]); + default: + if (regnum >= GDB_REG_S2 && regnum < GDB_REG_T3) + return (&kdb_thrctx->pcb_s[regnum - GDB_REG_S2]); + break; + } + + return (NULL); +} + +void +gdb_cpu_setreg(int regnum, void *val) +{ + register_t regval = *(register_t *)val; + + /* For curthread, keep the pcb and trapframe in sync. */ + if (kdb_thread == curthread) { + switch (regnum) { + case GDB_REG_PC: kdb_frame->tf_sepc = regval; break; + case GDB_REG_RA: kdb_frame->tf_ra = regval; break; + case GDB_REG_SP: kdb_frame->tf_sp = regval; break; + case GDB_REG_GP: kdb_frame->tf_gp = regval; break; + case GDB_REG_TP: kdb_frame->tf_tp = regval; break; + case GDB_REG_FP: kdb_frame->tf_s[0] = regval; break; + case GDB_REG_S1: kdb_frame->tf_s[1] = regval; break; + case GDB_REG_SSTATUS: kdb_frame->tf_sstatus = regval; break; + case GDB_REG_STVAL: kdb_frame->tf_stval = regval; break; + case GDB_REG_SCAUSE: kdb_frame->tf_scause = regval; break; + default: + if (regnum >= GDB_REG_A0 && regnum < GDB_REG_S2) + kdb_frame->tf_a[regnum - GDB_REG_A0] = regval; + if (regnum >= GDB_REG_S2 && regnum < GDB_REG_T3) + kdb_frame->tf_s[regnum - GDB_REG_S2] = regval; + if (regnum >= GDB_REG_T0 && regnum < GDB_REG_FP) + kdb_frame->tf_t[regnum - GDB_REG_T0] = regval; + if (regnum >= GDB_REG_T3 && regnum < GDB_REG_PC) + kdb_frame->tf_t[regnum - GDB_REG_T3] = regval; + break; + } + } + switch (regnum) { + case GDB_REG_PC: /* FALLTHROUGH */ + case GDB_REG_RA: kdb_thrctx->pcb_ra = regval; break; + case GDB_REG_SP: kdb_thrctx->pcb_sp = regval; break; + case GDB_REG_GP: kdb_thrctx->pcb_gp = regval; break; + case GDB_REG_TP: kdb_thrctx->pcb_tp = regval; break; + case GDB_REG_FP: kdb_thrctx->pcb_s[0] = regval; break; + case GDB_REG_S1: kdb_thrctx->pcb_s[1] = regval; break; + default: + if (regnum >= GDB_REG_S2 && regnum < GDB_REG_T3) + kdb_thrctx->pcb_s[regnum - GDB_REG_S2] = regval; + break; + } +} + +int +gdb_cpu_signal(int type, int code) +{ + + if (type == SCAUSE_BREAKPOINT) + return (SIGTRAP); + + return (SIGEMT); +}