mirror of
https://github.com/qemu/qemu.git
synced 2025-08-15 13:47:03 +00:00

If the number of registers reported to the gdbstub code does not match the number in the associated XML file, then the register numbers used by the stub may get out of sync with a remote GDB instance. Signed-off-by: Jonathan Behrens <jonathan@fintelia.io> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
398 lines
9.4 KiB
C
398 lines
9.4 KiB
C
/*
|
|
* RISC-V GDB Server Stub
|
|
*
|
|
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2 or later, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#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);
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
if (n < 32) {
|
|
return gdb_get_regl(mem_buf, env->gpr[n]);
|
|
} else if (n == 32) {
|
|
return gdb_get_regl(mem_buf, env->pc);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|
{
|
|
RISCVCPU *cpu = RISCV_CPU(cs);
|
|
CPURISCVState *env = &cpu->env;
|
|
|
|
if (n == 0) {
|
|
/* discard writes to x0 */
|
|
return sizeof(target_ulong);
|
|
} else if (n < 32) {
|
|
env->gpr[n] = ldtul_p(mem_buf);
|
|
return sizeof(target_ulong);
|
|
} else if (n == 32) {
|
|
env->pc = ldtul_p(mem_buf);
|
|
return sizeof(target_ulong);
|
|
}
|
|
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 + csr_register_map[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);
|
|
/* there is hole between ft11 and fflags in fpu.xml */
|
|
} else if (n < 36 && n > 32) {
|
|
target_ulong val = ldtul_p(mem_buf);
|
|
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 + csr_register_map[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,
|
|
240, "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,
|
|
240, "riscv-64bit-csr.xml", 0);
|
|
#endif
|
|
}
|