new file mode 100644
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+static const char gdb_query_pkt[10] = "Supported:";
+
+static const char gdb_reply_feature[64] =
+ "PacketSize=2048;qXfer:features:read+;";
+
+static const char gdb_xfer_read_target[25] = "Xfer:features:read:target";
+
+static const char gdb_xfer_read_cpuxml[38] =
+ "Xfer:features:read:riscv-64bit-cpu.xml";
+
+static const char gdb_target_desc[256] =
+"l<?xml version=\"1.0\"?>"
+"<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+"<target>"
+"<xi:include href=\"riscv-64bit-cpu.xml\"/>"
+"</target>";
+
+static const char gdb_cpuxml[2048] =
+"l<?xml version=\"1.0\"?>"
+"<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
+"<feature name=\"org.gnu.gdb.riscv.cpu\">"
+"<reg name=\""PT_REG_ZERO"\" bitsize=\"64\" type=\"int\" regnum=\"0\"/>"
+"<reg name=\""PT_REG_RA"\" bitsize=\"64\" type=\"code_ptr\"/>"
+"<reg name=\""PT_REG_SP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""PT_REG_GP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""PT_REG_TP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""PT_REG_T0"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_T1"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_T2"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_FP"\" bitsize=\"64\" type=\"data_ptr\"/>"
+"<reg name=\""PT_REG_S1"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A0"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A1"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A2"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A3"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A4"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A5"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A6"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_A7"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S2"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S3"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S4"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S5"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S6"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S7"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S8"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S9"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S10"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_S11"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_T3"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_T4"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_T5"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_T6"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_SEPC"\" bitsize=\"64\" type=\"code_ptr\"/>"
+"<reg name=\""PT_REG_SSTATUS"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_STVAL"\" bitsize=\"64\" type=\"int\"/>"
+"<reg name=\""PT_REG_SCAUSE"\" bitsize=\"64\" type=\"int\"/>"
+"</feature>";
@@ -7,7 +7,7 @@
#define GDB_SIZEOF_REG sizeof(unsigned long)
-#define DBG_MAX_REG_NUM (33)
+#define DBG_MAX_REG_NUM (36)
#define NUMREGBYTES ((DBG_MAX_REG_NUM) * GDB_SIZEOF_REG)
#define CACHE_FLUSH_IS_SAFE 1
#define BUFMAX 2048
@@ -66,6 +66,9 @@ static inline void arch_kgdb_breakpoint(void)
#define PT_REG_T5 "t5"
#define PT_REG_T6 "t6"
#define PT_REG_SEPC "pc"
+#define PT_REG_SSTATUS "sstatus"
+#define PT_REG_STVAL "stval"
+#define PT_REG_SCAUSE "scause"
#endif
#endif
@@ -7,6 +7,7 @@
#include <linux/irqflags.h>
#include <linux/string.h>
#include <asm/cacheflush.h>
+#include <asm/gdb_xml.h>
enum {
NOT_KGDB_BREAK = 0,
@@ -48,6 +49,9 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
{PT_REG_T5, GDB_SIZEOF_REG, offsetof(struct pt_regs, t5)},
{PT_REG_T6, GDB_SIZEOF_REG, offsetof(struct pt_regs, t6)},
{PT_REG_SEPC, GDB_SIZEOF_REG, offsetof(struct pt_regs, epc)},
+ {PT_REG_SSTATUS, GDB_SIZEOF_REG, offsetof(struct pt_regs, status)},
+ {PT_REG_STVAL, GDB_SIZEOF_REG, offsetof(struct pt_regs, badaddr)},
+ {PT_REG_SCAUSE, GDB_SIZEOF_REG, offsetof(struct pt_regs, cause)},
};
char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
@@ -100,6 +104,29 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
regs->epc = pc;
}
+void kgdb_arch_cmd_query(char *remcom_in_buffer, char *remcom_out_buffer)
+{
+ switch (remcom_in_buffer[1]) {
+ case 'S':
+ if (!strncmp(remcom_in_buffer + 1,
+ gdb_query_pkt, sizeof(gdb_query_pkt)))
+ strcpy(remcom_out_buffer, gdb_reply_feature);
+ break;
+ case 'X':
+ if (!strncmp(remcom_in_buffer + 1,
+ gdb_xfer_read_target,
+ sizeof(gdb_xfer_read_target)))
+ strcpy(remcom_out_buffer, gdb_target_desc);
+ else if (!strncmp(remcom_in_buffer + 1,
+ gdb_xfer_read_cpuxml,
+ sizeof(gdb_xfer_read_cpuxml)))
+ strcpy(remcom_out_buffer, gdb_cpuxml);
+ break;
+ default:
+ break;
+ }
+}
+
static inline void kgdb_arch_update_addr(struct pt_regs *regs,
char *remcom_in_buffer)
{
The sstatus, badaddr and scause registers belonged to the thread context, and KGDB can obtain their contents from pt_regs in each trap. However, the sequential number of these registers is far from the general purpose registers. It causes riscv to report many trivial middle registers in the reply packets. In order to solve this problem, the GDB query mechanism was introduced to enable KGDB to customize the reported register list through the XML target descriptions. Signed-off-by: Vincent Chen <vincent.chen@sifive.com> --- arch/riscv/include/asm/gdb_xml.h | 60 ++++++++++++++++++++++++++++++++++++++++ arch/riscv/include/asm/kgdb.h | 5 +++- arch/riscv/kernel/kgdb.c | 27 ++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/gdb_xml.h