qemu/target/riscv/gdbstub.c
Alex Bennée a010bdbe71 gdbstub: extend GByteArray to read register helpers
Instead of passing a pointer to memory now just extend the GByteArray
to all the read register helpers. They can then safely append their
data through the normal way. We don't bother with this abstraction for
write registers as we have already ensured the buffer being copied
from is the correct size.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>

Message-Id: <20200316172155.971-15-alex.bennee@linaro.org>
2020-03-17 17:38:38 +00:00

433 lines
10 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_MTINST,
CSR_MTVAL2,
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_HCOUNTEREN,
CSR_HTVAL,
CSR_HIP,
CSR_HTINST,
CSR_HGATP,
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, GByteArray *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, GByteArray *buf, int n)
{
if (n < 32) {
if (env->misa & RVD) {
return gdb_get_reg64(buf, env->fpr[n]);
}
if (env->misa & RVF) {
return gdb_get_reg32(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(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, GByteArray *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(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;
}
static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
{
if (n == 0) {
#ifdef CONFIG_USER_ONLY
return gdb_get_regl(buf, 0);
#else
return gdb_get_regl(buf, cs->priv);
#endif
}
return 0;
}
static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
{
if (n == 0) {
#ifndef CONFIG_USER_ONLY
cs->priv = ldtul_p(mem_buf) & 0x3;
if (cs->priv == PRV_H) {
cs->priv = PRV_S;
}
#endif
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 (env->misa & RVD) {
gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
36, "riscv-64bit-fpu.xml", 0);
} else if (env->misa & RVF) {
gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
36, "riscv-32bit-fpu.xml", 0);
}
#if defined(TARGET_RISCV32)
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
240, "riscv-32bit-csr.xml", 0);
gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
1, "riscv-32bit-virtual.xml", 0);
#elif defined(TARGET_RISCV64)
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
240, "riscv-64bit-csr.xml", 0);
gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
1, "riscv-64bit-virtual.xml", 0);
#endif
}