diff mbox series

[v5,5/5] RISC-V: Add hooks to use the gdb xml files.

Message ID 1552645619-18244-6-git-send-email-chihmin.chao@sifive.com
State New
Headers show
Series RISC-V: Add gdb xml files and gdbstub support | expand

Commit Message

Chih-Min Chao March 15, 2019, 10:26 a.m. UTC
From: Jim Wilson <jimw@sifive.com>

The gdb CSR xml file has registers in documentation order, not numerical
order, so we need a table to map the register numbers.  This also adds
fairly standard gdb hooks to access xml specified registers.

notice:
    The fpu xml from gdb 8.3 has unused register #, 65 and make first
    csr register # become 69. We register extra register on gdb to correct
    csr offset calculation

Signed-off-by: Jim Wilson <jimw@sifive.com>
Signed-off-by: Chih-Min Chao <chihmin.chao@sifive.com>
---
 target/riscv/cpu.c     |   9 +-
 target/riscv/cpu.h     |   2 +
 target/riscv/gdbstub.c | 350 +++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 349 insertions(+), 12 deletions(-)

Comments

Alistair Francis March 15, 2019, 6:34 p.m. UTC | #1
On Fri, Mar 15, 2019 at 7:01 AM Chih-Min Chao <chihmin.chao@sifive.com> wrote:
>
> From: Jim Wilson <jimw@sifive.com>
>
> The gdb CSR xml file has registers in documentation order, not numerical
> order, so we need a table to map the register numbers.  This also adds
> fairly standard gdb hooks to access xml specified registers.
>
> notice:
>     The fpu xml from gdb 8.3 has unused register #, 65 and make first
>     csr register # become 69. We register extra register on gdb to correct
>     csr offset calculation
>
> Signed-off-by: Jim Wilson <jimw@sifive.com>
> Signed-off-by: Chih-Min Chao <chihmin.chao@sifive.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu.c     |   9 +-
>  target/riscv/cpu.h     |   2 +
>  target/riscv/gdbstub.c | 350 +++++++++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 349 insertions(+), 12 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index cc3ddc0..feea169 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -311,6 +311,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>
> +    riscv_cpu_register_gdb_regs_for_features(cs);
> +
>      qemu_init_vcpu(cs);
>      cpu_reset(cs);
>
> @@ -351,7 +353,12 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
>      cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
>      cc->gdb_read_register = riscv_cpu_gdb_read_register;
>      cc->gdb_write_register = riscv_cpu_gdb_write_register;
> -    cc->gdb_num_core_regs = 65;
> +    cc->gdb_num_core_regs = 33;
> +#if defined(TARGET_RISCV32)
> +    cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
> +#elif defined(TARGET_RISCV64)
> +    cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
> +#endif
>      cc->gdb_stop_before_watchpoint = true;
>      cc->disas_set_info = riscv_cpu_disas_set_info;
>  #ifdef CONFIG_USER_ONLY
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 4c5de30..9b673de 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -330,6 +330,8 @@ typedef struct {
>  void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
>  void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
>
> +void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
> +
>  #include "exec/cpu-all.h"
>
>  #endif /* RISCV_CPU_H */
> diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
> index 3cabb21..dfcdd83 100644
> --- a/target/riscv/gdbstub.c
> +++ b/target/riscv/gdbstub.c
> @@ -21,6 +21,255 @@
>  #include "exec/gdbstub.h"
>  #include "cpu.h"
>
> +/*
> + * The GDB CSR xml files list them in documentation order, not numerical order,
> + * and are missing entries for unnamed CSRs.  So we need to map the gdb numbers
> + * to the hardware numbers.
> + */
> +
> +static int csr_register_map[] = {
> +    CSR_USTATUS,
> +    CSR_UIE,
> +    CSR_UTVEC,
> +    CSR_USCRATCH,
> +    CSR_UEPC,
> +    CSR_UCAUSE,
> +    CSR_UTVAL,
> +    CSR_UIP,
> +    CSR_FFLAGS,
> +    CSR_FRM,
> +    CSR_FCSR,
> +    CSR_CYCLE,
> +    CSR_TIME,
> +    CSR_INSTRET,
> +    CSR_HPMCOUNTER3,
> +    CSR_HPMCOUNTER4,
> +    CSR_HPMCOUNTER5,
> +    CSR_HPMCOUNTER6,
> +    CSR_HPMCOUNTER7,
> +    CSR_HPMCOUNTER8,
> +    CSR_HPMCOUNTER9,
> +    CSR_HPMCOUNTER10,
> +    CSR_HPMCOUNTER11,
> +    CSR_HPMCOUNTER12,
> +    CSR_HPMCOUNTER13,
> +    CSR_HPMCOUNTER14,
> +    CSR_HPMCOUNTER15,
> +    CSR_HPMCOUNTER16,
> +    CSR_HPMCOUNTER17,
> +    CSR_HPMCOUNTER18,
> +    CSR_HPMCOUNTER19,
> +    CSR_HPMCOUNTER20,
> +    CSR_HPMCOUNTER21,
> +    CSR_HPMCOUNTER22,
> +    CSR_HPMCOUNTER23,
> +    CSR_HPMCOUNTER24,
> +    CSR_HPMCOUNTER25,
> +    CSR_HPMCOUNTER26,
> +    CSR_HPMCOUNTER27,
> +    CSR_HPMCOUNTER28,
> +    CSR_HPMCOUNTER29,
> +    CSR_HPMCOUNTER30,
> +    CSR_HPMCOUNTER31,
> +    CSR_CYCLEH,
> +    CSR_TIMEH,
> +    CSR_INSTRETH,
> +    CSR_HPMCOUNTER3H,
> +    CSR_HPMCOUNTER4H,
> +    CSR_HPMCOUNTER5H,
> +    CSR_HPMCOUNTER6H,
> +    CSR_HPMCOUNTER7H,
> +    CSR_HPMCOUNTER8H,
> +    CSR_HPMCOUNTER9H,
> +    CSR_HPMCOUNTER10H,
> +    CSR_HPMCOUNTER11H,
> +    CSR_HPMCOUNTER12H,
> +    CSR_HPMCOUNTER13H,
> +    CSR_HPMCOUNTER14H,
> +    CSR_HPMCOUNTER15H,
> +    CSR_HPMCOUNTER16H,
> +    CSR_HPMCOUNTER17H,
> +    CSR_HPMCOUNTER18H,
> +    CSR_HPMCOUNTER19H,
> +    CSR_HPMCOUNTER20H,
> +    CSR_HPMCOUNTER21H,
> +    CSR_HPMCOUNTER22H,
> +    CSR_HPMCOUNTER23H,
> +    CSR_HPMCOUNTER24H,
> +    CSR_HPMCOUNTER25H,
> +    CSR_HPMCOUNTER26H,
> +    CSR_HPMCOUNTER27H,
> +    CSR_HPMCOUNTER28H,
> +    CSR_HPMCOUNTER29H,
> +    CSR_HPMCOUNTER30H,
> +    CSR_HPMCOUNTER31H,
> +    CSR_SSTATUS,
> +    CSR_SEDELEG,
> +    CSR_SIDELEG,
> +    CSR_SIE,
> +    CSR_STVEC,
> +    CSR_SCOUNTEREN,
> +    CSR_SSCRATCH,
> +    CSR_SEPC,
> +    CSR_SCAUSE,
> +    CSR_STVAL,
> +    CSR_SIP,
> +    CSR_SATP,
> +    CSR_MVENDORID,
> +    CSR_MARCHID,
> +    CSR_MIMPID,
> +    CSR_MHARTID,
> +    CSR_MSTATUS,
> +    CSR_MISA,
> +    CSR_MEDELEG,
> +    CSR_MIDELEG,
> +    CSR_MIE,
> +    CSR_MTVEC,
> +    CSR_MCOUNTEREN,
> +    CSR_MSCRATCH,
> +    CSR_MEPC,
> +    CSR_MCAUSE,
> +    CSR_MTVAL,
> +    CSR_MIP,
> +    CSR_PMPCFG0,
> +    CSR_PMPCFG1,
> +    CSR_PMPCFG2,
> +    CSR_PMPCFG3,
> +    CSR_PMPADDR0,
> +    CSR_PMPADDR1,
> +    CSR_PMPADDR2,
> +    CSR_PMPADDR3,
> +    CSR_PMPADDR4,
> +    CSR_PMPADDR5,
> +    CSR_PMPADDR6,
> +    CSR_PMPADDR7,
> +    CSR_PMPADDR8,
> +    CSR_PMPADDR9,
> +    CSR_PMPADDR10,
> +    CSR_PMPADDR11,
> +    CSR_PMPADDR12,
> +    CSR_PMPADDR13,
> +    CSR_PMPADDR14,
> +    CSR_PMPADDR15,
> +    CSR_MCYCLE,
> +    CSR_MINSTRET,
> +    CSR_MHPMCOUNTER3,
> +    CSR_MHPMCOUNTER4,
> +    CSR_MHPMCOUNTER5,
> +    CSR_MHPMCOUNTER6,
> +    CSR_MHPMCOUNTER7,
> +    CSR_MHPMCOUNTER8,
> +    CSR_MHPMCOUNTER9,
> +    CSR_MHPMCOUNTER10,
> +    CSR_MHPMCOUNTER11,
> +    CSR_MHPMCOUNTER12,
> +    CSR_MHPMCOUNTER13,
> +    CSR_MHPMCOUNTER14,
> +    CSR_MHPMCOUNTER15,
> +    CSR_MHPMCOUNTER16,
> +    CSR_MHPMCOUNTER17,
> +    CSR_MHPMCOUNTER18,
> +    CSR_MHPMCOUNTER19,
> +    CSR_MHPMCOUNTER20,
> +    CSR_MHPMCOUNTER21,
> +    CSR_MHPMCOUNTER22,
> +    CSR_MHPMCOUNTER23,
> +    CSR_MHPMCOUNTER24,
> +    CSR_MHPMCOUNTER25,
> +    CSR_MHPMCOUNTER26,
> +    CSR_MHPMCOUNTER27,
> +    CSR_MHPMCOUNTER28,
> +    CSR_MHPMCOUNTER29,
> +    CSR_MHPMCOUNTER30,
> +    CSR_MHPMCOUNTER31,
> +    CSR_MCYCLEH,
> +    CSR_MINSTRETH,
> +    CSR_MHPMCOUNTER3H,
> +    CSR_MHPMCOUNTER4H,
> +    CSR_MHPMCOUNTER5H,
> +    CSR_MHPMCOUNTER6H,
> +    CSR_MHPMCOUNTER7H,
> +    CSR_MHPMCOUNTER8H,
> +    CSR_MHPMCOUNTER9H,
> +    CSR_MHPMCOUNTER10H,
> +    CSR_MHPMCOUNTER11H,
> +    CSR_MHPMCOUNTER12H,
> +    CSR_MHPMCOUNTER13H,
> +    CSR_MHPMCOUNTER14H,
> +    CSR_MHPMCOUNTER15H,
> +    CSR_MHPMCOUNTER16H,
> +    CSR_MHPMCOUNTER17H,
> +    CSR_MHPMCOUNTER18H,
> +    CSR_MHPMCOUNTER19H,
> +    CSR_MHPMCOUNTER20H,
> +    CSR_MHPMCOUNTER21H,
> +    CSR_MHPMCOUNTER22H,
> +    CSR_MHPMCOUNTER23H,
> +    CSR_MHPMCOUNTER24H,
> +    CSR_MHPMCOUNTER25H,
> +    CSR_MHPMCOUNTER26H,
> +    CSR_MHPMCOUNTER27H,
> +    CSR_MHPMCOUNTER28H,
> +    CSR_MHPMCOUNTER29H,
> +    CSR_MHPMCOUNTER30H,
> +    CSR_MHPMCOUNTER31H,
> +    CSR_MHPMEVENT3,
> +    CSR_MHPMEVENT4,
> +    CSR_MHPMEVENT5,
> +    CSR_MHPMEVENT6,
> +    CSR_MHPMEVENT7,
> +    CSR_MHPMEVENT8,
> +    CSR_MHPMEVENT9,
> +    CSR_MHPMEVENT10,
> +    CSR_MHPMEVENT11,
> +    CSR_MHPMEVENT12,
> +    CSR_MHPMEVENT13,
> +    CSR_MHPMEVENT14,
> +    CSR_MHPMEVENT15,
> +    CSR_MHPMEVENT16,
> +    CSR_MHPMEVENT17,
> +    CSR_MHPMEVENT18,
> +    CSR_MHPMEVENT19,
> +    CSR_MHPMEVENT20,
> +    CSR_MHPMEVENT21,
> +    CSR_MHPMEVENT22,
> +    CSR_MHPMEVENT23,
> +    CSR_MHPMEVENT24,
> +    CSR_MHPMEVENT25,
> +    CSR_MHPMEVENT26,
> +    CSR_MHPMEVENT27,
> +    CSR_MHPMEVENT28,
> +    CSR_MHPMEVENT29,
> +    CSR_MHPMEVENT30,
> +    CSR_MHPMEVENT31,
> +    CSR_TSELECT,
> +    CSR_TDATA1,
> +    CSR_TDATA2,
> +    CSR_TDATA3,
> +    CSR_DCSR,
> +    CSR_DPC,
> +    CSR_DSCRATCH,
> +    CSR_HSTATUS,
> +    CSR_HEDELEG,
> +    CSR_HIDELEG,
> +    CSR_HIE,
> +    CSR_HTVEC,
> +    CSR_HSCRATCH,
> +    CSR_HEPC,
> +    CSR_HCAUSE,
> +    CSR_HBADADDR,
> +    CSR_HIP,
> +    CSR_MBASE,
> +    CSR_MBOUND,
> +    CSR_MIBASE,
> +    CSR_MIBOUND,
> +    CSR_MDBASE,
> +    CSR_MDBOUND,
> +    CSR_MUCOUNTEREN,
> +    CSR_MSCOUNTEREN,
> +    CSR_MHCOUNTEREN,
> +};
> +
>  int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
>  {
>      RISCVCPU *cpu = RISCV_CPU(cs);
> @@ -30,13 +279,6 @@ int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
>          return gdb_get_regl(mem_buf, env->gpr[n]);
>      } else if (n == 32) {
>          return gdb_get_regl(mem_buf, env->pc);
> -    } else if (n < 65) {
> -        return gdb_get_reg64(mem_buf, env->fpr[n - 33]);
> -    } else if (n < 4096 + 65) {
> -        target_ulong val = 0;
> -        if (riscv_csrrw(env, n - 65, &val, 0, 0) == 0) {
> -            return gdb_get_regl(mem_buf, val);
> -        }
>      }
>      return 0;
>  }
> @@ -55,14 +297,100 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
>      } else if (n == 32) {
>          env->pc = ldtul_p(mem_buf);
>          return sizeof(target_ulong);
> -    } else if (n < 65) {
> -        env->fpr[n - 33] = ldq_p(mem_buf); /* always 64-bit */
> +    }
> +    return 0;
> +}
> +
> +static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
> +{
> +    if (n < 32) {
> +        return gdb_get_reg64(mem_buf, env->fpr[n]);
> +    /* there is hole between ft11 and fflags in fpu.xml */
> +    } else if (n < 36 && n > 32) {
> +        target_ulong val = 0;
> +        int result;
> +        /*
> +         * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP
> +         * register 33, so we recalculate the map index.
> +         * This also works for CSR_FRM and CSR_FCSR.
> +         */
> +        result = riscv_csrrw_debug(env, n - 33 +  8, &val, 0, 0);
> +        if (result == 0) {
> +            return gdb_get_regl(mem_buf, val);
> +        }
> +    }
> +    return 0;
> +}
> +
> +static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
> +{
> +    if (n < 32) {
> +        env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
>          return sizeof(uint64_t);
> -    } else if (n < 4096 + 65) {
> +    /* there is hole between ft11 and fflags in fpu.xml */
> +    } else if (n < 36 && n > 32) {
>          target_ulong val = ldtul_p(mem_buf);
> -        if (riscv_csrrw(env, n - 65, NULL, val, -1) == 0) {
> +        int result;
> +        /*
> +         * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP
> +         * register 33, so we recalculate the map index.
> +         * This also works for CSR_FRM and CSR_FCSR.
> +         */
> +        result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1);
> +        if (result == 0) {
>              return sizeof(target_ulong);
>          }
>      }
>      return 0;
>  }
> +
> +static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
> +{
> +    if (n < ARRAY_SIZE(csr_register_map)) {
> +        target_ulong val = 0;
> +        int result;
> +
> +        result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
> +        if (result == 0) {
> +            return gdb_get_regl(mem_buf, val);
> +        }
> +    }
> +    return 0;
> +}
> +
> +static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
> +{
> +    if (n < ARRAY_SIZE(csr_register_map)) {
> +        target_ulong val = ldtul_p(mem_buf);
> +        int result;
> +
> +        result = riscv_csrrw_debug(env, csr_register_map[n], NULL, val, -1);
> +        if (result == 0) {
> +            return sizeof(target_ulong);
> +        }
> +    }
> +    return 0;
> +}
> +
> +void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
> +{
> +    RISCVCPU *cpu = RISCV_CPU(cs);
> +    CPURISCVState *env = &cpu->env;
> +#if defined(TARGET_RISCV32)
> +    if (env->misa & RVF) {
> +        gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
> +                                 36, "riscv-32bit-fpu.xml", 0);
> +    }
> +
> +    gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
> +                             4096, "riscv-32bit-csr.xml", 0);
> +#elif defined(TARGET_RISCV64)
> +    if (env->misa & RVF) {
> +        gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
> +                                 36, "riscv-64bit-fpu.xml", 0);
> +    }
> +
> +    gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
> +                             4096, "riscv-64bit-csr.xml", 0);
> +#endif
> +}
> --
> 2.7.4
>
>
diff mbox series

Patch

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index cc3ddc0..feea169 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -311,6 +311,8 @@  static void riscv_cpu_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    riscv_cpu_register_gdb_regs_for_features(cs);
+
     qemu_init_vcpu(cs);
     cpu_reset(cs);
 
@@ -351,7 +353,12 @@  static void riscv_cpu_class_init(ObjectClass *c, void *data)
     cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
     cc->gdb_read_register = riscv_cpu_gdb_read_register;
     cc->gdb_write_register = riscv_cpu_gdb_write_register;
-    cc->gdb_num_core_regs = 65;
+    cc->gdb_num_core_regs = 33;
+#if defined(TARGET_RISCV32)
+    cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
+#elif defined(TARGET_RISCV64)
+    cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
+#endif
     cc->gdb_stop_before_watchpoint = true;
     cc->disas_set_info = riscv_cpu_disas_set_info;
 #ifdef CONFIG_USER_ONLY
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4c5de30..9b673de 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -330,6 +330,8 @@  typedef struct {
 void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
 void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
 
+void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
+
 #include "exec/cpu-all.h"
 
 #endif /* RISCV_CPU_H */
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 3cabb21..dfcdd83 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -21,6 +21,255 @@ 
 #include "exec/gdbstub.h"
 #include "cpu.h"
 
+/*
+ * The GDB CSR xml files list them in documentation order, not numerical order,
+ * and are missing entries for unnamed CSRs.  So we need to map the gdb numbers
+ * to the hardware numbers.
+ */
+
+static int csr_register_map[] = {
+    CSR_USTATUS,
+    CSR_UIE,
+    CSR_UTVEC,
+    CSR_USCRATCH,
+    CSR_UEPC,
+    CSR_UCAUSE,
+    CSR_UTVAL,
+    CSR_UIP,
+    CSR_FFLAGS,
+    CSR_FRM,
+    CSR_FCSR,
+    CSR_CYCLE,
+    CSR_TIME,
+    CSR_INSTRET,
+    CSR_HPMCOUNTER3,
+    CSR_HPMCOUNTER4,
+    CSR_HPMCOUNTER5,
+    CSR_HPMCOUNTER6,
+    CSR_HPMCOUNTER7,
+    CSR_HPMCOUNTER8,
+    CSR_HPMCOUNTER9,
+    CSR_HPMCOUNTER10,
+    CSR_HPMCOUNTER11,
+    CSR_HPMCOUNTER12,
+    CSR_HPMCOUNTER13,
+    CSR_HPMCOUNTER14,
+    CSR_HPMCOUNTER15,
+    CSR_HPMCOUNTER16,
+    CSR_HPMCOUNTER17,
+    CSR_HPMCOUNTER18,
+    CSR_HPMCOUNTER19,
+    CSR_HPMCOUNTER20,
+    CSR_HPMCOUNTER21,
+    CSR_HPMCOUNTER22,
+    CSR_HPMCOUNTER23,
+    CSR_HPMCOUNTER24,
+    CSR_HPMCOUNTER25,
+    CSR_HPMCOUNTER26,
+    CSR_HPMCOUNTER27,
+    CSR_HPMCOUNTER28,
+    CSR_HPMCOUNTER29,
+    CSR_HPMCOUNTER30,
+    CSR_HPMCOUNTER31,
+    CSR_CYCLEH,
+    CSR_TIMEH,
+    CSR_INSTRETH,
+    CSR_HPMCOUNTER3H,
+    CSR_HPMCOUNTER4H,
+    CSR_HPMCOUNTER5H,
+    CSR_HPMCOUNTER6H,
+    CSR_HPMCOUNTER7H,
+    CSR_HPMCOUNTER8H,
+    CSR_HPMCOUNTER9H,
+    CSR_HPMCOUNTER10H,
+    CSR_HPMCOUNTER11H,
+    CSR_HPMCOUNTER12H,
+    CSR_HPMCOUNTER13H,
+    CSR_HPMCOUNTER14H,
+    CSR_HPMCOUNTER15H,
+    CSR_HPMCOUNTER16H,
+    CSR_HPMCOUNTER17H,
+    CSR_HPMCOUNTER18H,
+    CSR_HPMCOUNTER19H,
+    CSR_HPMCOUNTER20H,
+    CSR_HPMCOUNTER21H,
+    CSR_HPMCOUNTER22H,
+    CSR_HPMCOUNTER23H,
+    CSR_HPMCOUNTER24H,
+    CSR_HPMCOUNTER25H,
+    CSR_HPMCOUNTER26H,
+    CSR_HPMCOUNTER27H,
+    CSR_HPMCOUNTER28H,
+    CSR_HPMCOUNTER29H,
+    CSR_HPMCOUNTER30H,
+    CSR_HPMCOUNTER31H,
+    CSR_SSTATUS,
+    CSR_SEDELEG,
+    CSR_SIDELEG,
+    CSR_SIE,
+    CSR_STVEC,
+    CSR_SCOUNTEREN,
+    CSR_SSCRATCH,
+    CSR_SEPC,
+    CSR_SCAUSE,
+    CSR_STVAL,
+    CSR_SIP,
+    CSR_SATP,
+    CSR_MVENDORID,
+    CSR_MARCHID,
+    CSR_MIMPID,
+    CSR_MHARTID,
+    CSR_MSTATUS,
+    CSR_MISA,
+    CSR_MEDELEG,
+    CSR_MIDELEG,
+    CSR_MIE,
+    CSR_MTVEC,
+    CSR_MCOUNTEREN,
+    CSR_MSCRATCH,
+    CSR_MEPC,
+    CSR_MCAUSE,
+    CSR_MTVAL,
+    CSR_MIP,
+    CSR_PMPCFG0,
+    CSR_PMPCFG1,
+    CSR_PMPCFG2,
+    CSR_PMPCFG3,
+    CSR_PMPADDR0,
+    CSR_PMPADDR1,
+    CSR_PMPADDR2,
+    CSR_PMPADDR3,
+    CSR_PMPADDR4,
+    CSR_PMPADDR5,
+    CSR_PMPADDR6,
+    CSR_PMPADDR7,
+    CSR_PMPADDR8,
+    CSR_PMPADDR9,
+    CSR_PMPADDR10,
+    CSR_PMPADDR11,
+    CSR_PMPADDR12,
+    CSR_PMPADDR13,
+    CSR_PMPADDR14,
+    CSR_PMPADDR15,
+    CSR_MCYCLE,
+    CSR_MINSTRET,
+    CSR_MHPMCOUNTER3,
+    CSR_MHPMCOUNTER4,
+    CSR_MHPMCOUNTER5,
+    CSR_MHPMCOUNTER6,
+    CSR_MHPMCOUNTER7,
+    CSR_MHPMCOUNTER8,
+    CSR_MHPMCOUNTER9,
+    CSR_MHPMCOUNTER10,
+    CSR_MHPMCOUNTER11,
+    CSR_MHPMCOUNTER12,
+    CSR_MHPMCOUNTER13,
+    CSR_MHPMCOUNTER14,
+    CSR_MHPMCOUNTER15,
+    CSR_MHPMCOUNTER16,
+    CSR_MHPMCOUNTER17,
+    CSR_MHPMCOUNTER18,
+    CSR_MHPMCOUNTER19,
+    CSR_MHPMCOUNTER20,
+    CSR_MHPMCOUNTER21,
+    CSR_MHPMCOUNTER22,
+    CSR_MHPMCOUNTER23,
+    CSR_MHPMCOUNTER24,
+    CSR_MHPMCOUNTER25,
+    CSR_MHPMCOUNTER26,
+    CSR_MHPMCOUNTER27,
+    CSR_MHPMCOUNTER28,
+    CSR_MHPMCOUNTER29,
+    CSR_MHPMCOUNTER30,
+    CSR_MHPMCOUNTER31,
+    CSR_MCYCLEH,
+    CSR_MINSTRETH,
+    CSR_MHPMCOUNTER3H,
+    CSR_MHPMCOUNTER4H,
+    CSR_MHPMCOUNTER5H,
+    CSR_MHPMCOUNTER6H,
+    CSR_MHPMCOUNTER7H,
+    CSR_MHPMCOUNTER8H,
+    CSR_MHPMCOUNTER9H,
+    CSR_MHPMCOUNTER10H,
+    CSR_MHPMCOUNTER11H,
+    CSR_MHPMCOUNTER12H,
+    CSR_MHPMCOUNTER13H,
+    CSR_MHPMCOUNTER14H,
+    CSR_MHPMCOUNTER15H,
+    CSR_MHPMCOUNTER16H,
+    CSR_MHPMCOUNTER17H,
+    CSR_MHPMCOUNTER18H,
+    CSR_MHPMCOUNTER19H,
+    CSR_MHPMCOUNTER20H,
+    CSR_MHPMCOUNTER21H,
+    CSR_MHPMCOUNTER22H,
+    CSR_MHPMCOUNTER23H,
+    CSR_MHPMCOUNTER24H,
+    CSR_MHPMCOUNTER25H,
+    CSR_MHPMCOUNTER26H,
+    CSR_MHPMCOUNTER27H,
+    CSR_MHPMCOUNTER28H,
+    CSR_MHPMCOUNTER29H,
+    CSR_MHPMCOUNTER30H,
+    CSR_MHPMCOUNTER31H,
+    CSR_MHPMEVENT3,
+    CSR_MHPMEVENT4,
+    CSR_MHPMEVENT5,
+    CSR_MHPMEVENT6,
+    CSR_MHPMEVENT7,
+    CSR_MHPMEVENT8,
+    CSR_MHPMEVENT9,
+    CSR_MHPMEVENT10,
+    CSR_MHPMEVENT11,
+    CSR_MHPMEVENT12,
+    CSR_MHPMEVENT13,
+    CSR_MHPMEVENT14,
+    CSR_MHPMEVENT15,
+    CSR_MHPMEVENT16,
+    CSR_MHPMEVENT17,
+    CSR_MHPMEVENT18,
+    CSR_MHPMEVENT19,
+    CSR_MHPMEVENT20,
+    CSR_MHPMEVENT21,
+    CSR_MHPMEVENT22,
+    CSR_MHPMEVENT23,
+    CSR_MHPMEVENT24,
+    CSR_MHPMEVENT25,
+    CSR_MHPMEVENT26,
+    CSR_MHPMEVENT27,
+    CSR_MHPMEVENT28,
+    CSR_MHPMEVENT29,
+    CSR_MHPMEVENT30,
+    CSR_MHPMEVENT31,
+    CSR_TSELECT,
+    CSR_TDATA1,
+    CSR_TDATA2,
+    CSR_TDATA3,
+    CSR_DCSR,
+    CSR_DPC,
+    CSR_DSCRATCH,
+    CSR_HSTATUS,
+    CSR_HEDELEG,
+    CSR_HIDELEG,
+    CSR_HIE,
+    CSR_HTVEC,
+    CSR_HSCRATCH,
+    CSR_HEPC,
+    CSR_HCAUSE,
+    CSR_HBADADDR,
+    CSR_HIP,
+    CSR_MBASE,
+    CSR_MBOUND,
+    CSR_MIBASE,
+    CSR_MIBOUND,
+    CSR_MDBASE,
+    CSR_MDBOUND,
+    CSR_MUCOUNTEREN,
+    CSR_MSCOUNTEREN,
+    CSR_MHCOUNTEREN,
+};
+
 int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
 {
     RISCVCPU *cpu = RISCV_CPU(cs);
@@ -30,13 +279,6 @@  int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
         return gdb_get_regl(mem_buf, env->gpr[n]);
     } else if (n == 32) {
         return gdb_get_regl(mem_buf, env->pc);
-    } else if (n < 65) {
-        return gdb_get_reg64(mem_buf, env->fpr[n - 33]);
-    } else if (n < 4096 + 65) {
-        target_ulong val = 0;
-        if (riscv_csrrw(env, n - 65, &val, 0, 0) == 0) {
-            return gdb_get_regl(mem_buf, val);
-        }
     }
     return 0;
 }
@@ -55,14 +297,100 @@  int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     } else if (n == 32) {
         env->pc = ldtul_p(mem_buf);
         return sizeof(target_ulong);
-    } else if (n < 65) {
-        env->fpr[n - 33] = ldq_p(mem_buf); /* always 64-bit */
+    }
+    return 0;
+}
+
+static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        return gdb_get_reg64(mem_buf, env->fpr[n]);
+    /* there is hole between ft11 and fflags in fpu.xml */
+    } else if (n < 36 && n > 32) {
+        target_ulong val = 0;
+        int result;
+        /*
+         * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP
+         * register 33, so we recalculate the map index.
+         * This also works for CSR_FRM and CSR_FCSR.
+         */
+        result = riscv_csrrw_debug(env, n - 33 +  8, &val, 0, 0);
+        if (result == 0) {
+            return gdb_get_regl(mem_buf, val);
+        }
+    }
+    return 0;
+}
+
+static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        env->fpr[n] = ldq_p(mem_buf); /* always 64-bit */
         return sizeof(uint64_t);
-    } else if (n < 4096 + 65) {
+    /* there is hole between ft11 and fflags in fpu.xml */
+    } else if (n < 36 && n > 32) {
         target_ulong val = ldtul_p(mem_buf);
-        if (riscv_csrrw(env, n - 65, NULL, val, -1) == 0) {
+        int result;
+        /*
+         * CSR_FFLAGS is at index 8 in csr_register, and gdb says it is FP
+         * register 33, so we recalculate the map index.
+         * This also works for CSR_FRM and CSR_FCSR.
+         */
+        result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1);
+        if (result == 0) {
             return sizeof(target_ulong);
         }
     }
     return 0;
 }
+
+static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+    if (n < ARRAY_SIZE(csr_register_map)) {
+        target_ulong val = 0;
+        int result;
+
+        result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
+        if (result == 0) {
+            return gdb_get_regl(mem_buf, val);
+        }
+    }
+    return 0;
+}
+
+static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
+{
+    if (n < ARRAY_SIZE(csr_register_map)) {
+        target_ulong val = ldtul_p(mem_buf);
+        int result;
+
+        result = riscv_csrrw_debug(env, csr_register_map[n], NULL, val, -1);
+        if (result == 0) {
+            return sizeof(target_ulong);
+        }
+    }
+    return 0;
+}
+
+void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+#if defined(TARGET_RISCV32)
+    if (env->misa & RVF) {
+        gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+                                 36, "riscv-32bit-fpu.xml", 0);
+    }
+
+    gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
+                             4096, "riscv-32bit-csr.xml", 0);
+#elif defined(TARGET_RISCV64)
+    if (env->misa & RVF) {
+        gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
+                                 36, "riscv-64bit-fpu.xml", 0);
+    }
+
+    gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
+                             4096, "riscv-64bit-csr.xml", 0);
+#endif
+}