From d1933d9ce7aeb9c3da1339e850720dbc30237f58 Mon Sep 17 00:00:00 2001 From: Peter Yuen Date: Tue, 12 Jan 2021 00:38:23 +0800 Subject: [PATCH] arch-riscv: CSR registers support in RISC-V remote GDB. Note: Some less frequently needed CSR registers (e.g. hpm and pmp registers) are commented out on purpose. Instructions to add them back are described in remote_gdb.hh comments. This is to avoid spamming the remote GDB log when using `info reg all`. Changes: 1. Added GDB XML files to the ext/ directory (mostly from QEMU) 2. Modified RiscvGdbRegCache - struct r: added CSR registers - getRegs, setRegs: reading / setting CSR registers 3. Modified RemoteGDB - availableFeatures: indicate support for XML registers - getXferFeaturesRead: return XML blobs Change-Id: Ica03b63edb3f0c9b6a7789228b995891dbfb26b2 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/38955 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- ext/gdb-xml/riscv-64bit-cpu.xml | 48 ++++++ ext/gdb-xml/riscv-64bit-csr.xml | 248 +++++++++++++++++++++++++++ ext/gdb-xml/riscv-64bit-fpu.xml | 58 +++++++ ext/gdb-xml/riscv.xml | 13 ++ src/arch/riscv/SConscript | 6 + src/arch/riscv/remote_gdb.cc | 293 +++++++++++++++++++++++++++++++- src/arch/riscv/remote_gdb.hh | 76 +++++++++ 7 files changed, 740 insertions(+), 2 deletions(-) create mode 100644 ext/gdb-xml/riscv-64bit-cpu.xml create mode 100644 ext/gdb-xml/riscv-64bit-csr.xml create mode 100644 ext/gdb-xml/riscv-64bit-fpu.xml create mode 100644 ext/gdb-xml/riscv.xml diff --git a/ext/gdb-xml/riscv-64bit-cpu.xml b/ext/gdb-xml/riscv-64bit-cpu.xml new file mode 100644 index 000000000..ca59ac307 --- /dev/null +++ b/ext/gdb-xml/riscv-64bit-cpu.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/gdb-xml/riscv-64bit-csr.xml b/ext/gdb-xml/riscv-64bit-csr.xml new file mode 100644 index 000000000..6b2ae790f --- /dev/null +++ b/ext/gdb-xml/riscv-64bit-csr.xml @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/gdb-xml/riscv-64bit-fpu.xml b/ext/gdb-xml/riscv-64bit-fpu.xml new file mode 100644 index 000000000..7b68ba4d6 --- /dev/null +++ b/ext/gdb-xml/riscv-64bit-fpu.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/gdb-xml/riscv.xml b/ext/gdb-xml/riscv.xml new file mode 100644 index 000000000..cae8bf7ab --- /dev/null +++ b/ext/gdb-xml/riscv.xml @@ -0,0 +1,13 @@ + + + + + riscv + + + + \ No newline at end of file diff --git a/src/arch/riscv/SConscript b/src/arch/riscv/SConscript index 3913be9d1..0179fbcd4 100644 --- a/src/arch/riscv/SConscript +++ b/src/arch/riscv/SConscript @@ -3,6 +3,7 @@ # Copyright (c) 2013 ARM Limited # Copyright (c) 2014 Sven Karlsson # Copyright (c) 2020 Barkhausen Institut +# Copyright (c) 2021 Huawei International # All rights reserved # # The license below extends only to copyright in the software and shall @@ -73,3 +74,8 @@ if env['TARGET_ISA'] == 'riscv': # Add in files generated by the ISA description. ISADesc('isa/main.isa') + + GdbXml('riscv.xml', 'gdb_xml_riscv_target') + GdbXml('riscv-64bit-cpu.xml', 'gdb_xml_riscv_cpu') + GdbXml('riscv-64bit-fpu.xml', 'gdb_xml_riscv_fpu') + GdbXml('riscv-64bit-csr.xml', 'gdb_xml_riscv_csr') diff --git a/src/arch/riscv/remote_gdb.cc b/src/arch/riscv/remote_gdb.cc index 0e4c544ba..75f1820e4 100644 --- a/src/arch/riscv/remote_gdb.cc +++ b/src/arch/riscv/remote_gdb.cc @@ -1,4 +1,5 @@ /* + * Copyright (c) 2021 Huawei International * Copyright 2015 LabWare * Copyright 2014 Google, Inc. * Copyright (c) 2010 ARM Limited @@ -137,6 +138,11 @@ #include "arch/riscv/mmu.hh" #include "arch/riscv/pagetable_walker.hh" #include "arch/riscv/registers.hh" +#include "arch/riscv/tlb.hh" +#include "blobs/gdb_xml_riscv_cpu.hh" +#include "blobs/gdb_xml_riscv_csr.hh" +#include "blobs/gdb_xml_riscv_fpu.hh" +#include "blobs/gdb_xml_riscv_target.hh" #include "cpu/thread_state.hh" #include "debug/GDBAcc.hh" #include "mem/page_table.hh" @@ -165,7 +171,7 @@ RemoteGDB::acc(Addr va, size_t len) satp.mode != AddrXlateMode::BARE) { Walker *walker = mmu->getDataWalker(); Fault fault = walker->startFunctional( - context(), paddr, logBytes, BaseTLB::Read); + context(), paddr, logBytes, BaseTLB::Read); if (fault != NoFault) return false; } @@ -179,21 +185,304 @@ void RemoteGDB::RiscvGdbRegCache::getRegs(ThreadContext *context) { DPRINTF(GDBAcc, "getregs in remotegdb, size %lu\n", size()); + + // General registers for (int i = 0; i < NumIntArchRegs; i++) + { r.gpr[i] = context->readIntReg(i); + } r.pc = context->pcState().pc(); + + // Floating point registers + for (int i = 0; i < NumFloatRegs; i++) + r.fpu[i] = context->readFloatReg(i); + r.fflags = context->readMiscRegNoEffect( + CSRData.at(CSR_FFLAGS).physIndex) & CSRMasks.at(CSR_FFLAGS); + r.frm = context->readMiscRegNoEffect( + CSRData.at(CSR_FRM).physIndex) & CSRMasks.at(CSR_FRM); + r.fcsr = context->readMiscRegNoEffect( + CSRData.at(CSR_FCSR).physIndex) & CSRMasks.at(CSR_FCSR); + + // CSR registers + r.cycle = context->readMiscRegNoEffect( + CSRData.at(CSR_CYCLE).physIndex); + r.time = context->readMiscRegNoEffect( + CSRData.at(CSR_TIME).physIndex); + + // U mode CSR + r.ustatus = context->readMiscRegNoEffect( + CSRData.at(CSR_USTATUS).physIndex) & CSRMasks.at(CSR_USTATUS); + r.uie = context->readMiscRegNoEffect( + CSRData.at(CSR_UIE).physIndex) & CSRMasks.at(CSR_UIE); + r.utvec = context->readMiscRegNoEffect( + CSRData.at(CSR_UTVEC).physIndex); + r.uscratch = context->readMiscRegNoEffect( + CSRData.at(CSR_USCRATCH).physIndex); + r.uepc = context->readMiscRegNoEffect( + CSRData.at(CSR_UEPC).physIndex); + r.ucause = context->readMiscRegNoEffect( + CSRData.at(CSR_UCAUSE).physIndex); + r.utval = context->readMiscRegNoEffect( + CSRData.at(CSR_UTVAL).physIndex); + r.uip = context->readMiscRegNoEffect( + CSRData.at(CSR_UIP).physIndex) & CSRMasks.at(CSR_UIP); + + // S mode CSR + r.sstatus = context->readMiscRegNoEffect( + CSRData.at(CSR_SSTATUS).physIndex) & CSRMasks.at(CSR_SSTATUS); + r.sedeleg = context->readMiscRegNoEffect( + CSRData.at(CSR_SEDELEG).physIndex); + r.sideleg = context->readMiscRegNoEffect( + CSRData.at(CSR_SIDELEG).physIndex); + r.sie = context->readMiscRegNoEffect( + CSRData.at(CSR_SIE).physIndex) & CSRMasks.at(CSR_SIE); + r.stvec = context->readMiscRegNoEffect( + CSRData.at(CSR_STVEC).physIndex); + r.scounteren = context->readMiscRegNoEffect( + CSRData.at(CSR_SCOUNTEREN).physIndex); + r.sscratch = context->readMiscRegNoEffect( + CSRData.at(CSR_SSCRATCH).physIndex); + r.sepc = context->readMiscRegNoEffect( + CSRData.at(CSR_SEPC).physIndex); + r.scause = context->readMiscRegNoEffect( + CSRData.at(CSR_SCAUSE).physIndex); + r.stval = context->readMiscRegNoEffect( + CSRData.at(CSR_STVAL).physIndex); + r.sip = context->readMiscRegNoEffect( + CSRData.at(CSR_SIP).physIndex) & CSRMasks.at(CSR_SIP); + r.satp = context->readMiscRegNoEffect( + CSRData.at(CSR_SATP).physIndex); + + // M mode CSR + r.mvendorid = context->readMiscRegNoEffect( + CSRData.at(CSR_MVENDORID).physIndex); + r.marchid = context->readMiscRegNoEffect( + CSRData.at(CSR_MARCHID).physIndex); + r.mimpid = context->readMiscRegNoEffect( + CSRData.at(CSR_MIMPID).physIndex); + r.mhartid = context->readMiscRegNoEffect( + CSRData.at(CSR_MHARTID).physIndex); + r.mstatus = context->readMiscRegNoEffect( + CSRData.at(CSR_MSTATUS).physIndex) & CSRMasks.at(CSR_MSTATUS); + r.misa = context->readMiscRegNoEffect( + CSRData.at(CSR_MISA).physIndex) & CSRMasks.at(CSR_MISA); + r.medeleg = context->readMiscRegNoEffect( + CSRData.at(CSR_MEDELEG).physIndex); + r.mideleg = context->readMiscRegNoEffect( + CSRData.at(CSR_MIDELEG).physIndex); + r.mie = context->readMiscRegNoEffect( + CSRData.at(CSR_MIE).physIndex) & CSRMasks.at(CSR_MIE); + r.mtvec = context->readMiscRegNoEffect( + CSRData.at(CSR_MTVEC).physIndex); + r.mcounteren = context->readMiscRegNoEffect( + CSRData.at(CSR_MCOUNTEREN).physIndex); + r.mscratch = context->readMiscRegNoEffect( + CSRData.at(CSR_MSCRATCH).physIndex); + r.mepc = context->readMiscRegNoEffect( + CSRData.at(CSR_MEPC).physIndex); + r.mcause = context->readMiscRegNoEffect( + CSRData.at(CSR_MCAUSE).physIndex); + r.mtval = context->readMiscRegNoEffect( + CSRData.at(CSR_MTVAL).physIndex); + r.mip = context->readMiscRegNoEffect( + CSRData.at(CSR_MIP).physIndex) & CSRMasks.at(CSR_MIP); + + // H mode CSR (to be implemented) } void RemoteGDB::RiscvGdbRegCache::setRegs(ThreadContext *context) const { + // NOTE: no error will be reported for attempting to set masked bits. + RegVal oldVal; + int mask; + RegVal newVal; + DPRINTF(GDBAcc, "setregs in remotegdb \n"); for (int i = 0; i < NumIntArchRegs; i++) context->setIntReg(i, r.gpr[i]); context->pcState(r.pc); + + // Floating point registers + for (int i = 0; i < NumFloatRegs; i++) + context->setFloatReg(i, r.fpu[i]); + + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_FFLAGS).physIndex); + mask = CSRMasks.at(CSR_FFLAGS); + newVal = (oldVal & ~mask) | (r.fflags & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_FFLAGS).physIndex, newVal); + + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_FRM).physIndex); + mask = CSRMasks.at(CSR_FRM); + newVal = (oldVal & ~mask) | (r.frm & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_FRM).physIndex, newVal); + + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_FCSR).physIndex); + mask = CSRMasks.at(CSR_FCSR); + newVal = (oldVal & ~mask) | (r.fcsr & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_FCSR).physIndex, newVal); + + // CSR registers + context->setMiscRegNoEffect( + CSRData.at(CSR_CYCLE).physIndex, r.cycle); + context->setMiscRegNoEffect( + CSRData.at(CSR_TIME).physIndex, r.time); + + // U mode CSR + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_USTATUS).physIndex); + mask = CSRMasks.at(CSR_USTATUS); + newVal = (oldVal & ~mask) | (r.ustatus & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_USTATUS).physIndex, newVal); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_UIE).physIndex); + mask = CSRMasks.at(CSR_UIE); + newVal = (oldVal & ~mask) | (r.uie & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_UIE).physIndex, newVal); + context->setMiscRegNoEffect( + CSRData.at(CSR_UTVEC).physIndex, r.utvec); + context->setMiscRegNoEffect( + CSRData.at(CSR_USCRATCH).physIndex, r.uscratch); + context->setMiscRegNoEffect( + CSRData.at(CSR_UEPC).physIndex, r.uepc); + context->setMiscRegNoEffect( + CSRData.at(CSR_UCAUSE).physIndex, r.ucause); + context->setMiscRegNoEffect( + CSRData.at(CSR_UTVAL).physIndex, r.utval); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_UIP).physIndex); + mask = CSRMasks.at(CSR_UIP); + newVal = (oldVal & ~mask) | (r.uip & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_UIP).physIndex, newVal); + + // S mode CSR + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_SSTATUS).physIndex); + mask = CSRMasks.at(CSR_SSTATUS); + newVal = (oldVal & ~mask) | (r.sstatus & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_SSTATUS).physIndex, newVal); + context->setMiscRegNoEffect( + CSRData.at(CSR_SEDELEG).physIndex, r.sedeleg); + context->setMiscRegNoEffect( + CSRData.at(CSR_SIDELEG).physIndex, r.sideleg); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_SIE).physIndex); + mask = CSRMasks.at(CSR_SIE); + newVal = (oldVal & ~mask) | (r.sie & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_SIE).physIndex, newVal); + context->setMiscRegNoEffect( + CSRData.at(CSR_STVEC).physIndex, r.stvec); + context->setMiscRegNoEffect( + CSRData.at(CSR_SCOUNTEREN).physIndex, r.scounteren); + context->setMiscRegNoEffect( + CSRData.at(CSR_SSCRATCH).physIndex, r.sscratch); + context->setMiscRegNoEffect( + CSRData.at(CSR_SEPC).physIndex, r.sepc); + context->setMiscRegNoEffect( + CSRData.at(CSR_SCAUSE).physIndex, r.scause); + context->setMiscRegNoEffect( + CSRData.at(CSR_STVAL).physIndex, r.stval); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_SIP).physIndex); + mask = CSRMasks.at(CSR_SIP); + newVal = (oldVal & ~mask) | (r.sip & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_SIP).physIndex, newVal); + context->setMiscRegNoEffect( + CSRData.at(CSR_SATP).physIndex, r.satp); + + // M mode CSR + context->setMiscRegNoEffect( + CSRData.at(CSR_MVENDORID).physIndex, r.mvendorid); + context->setMiscRegNoEffect( + CSRData.at(CSR_MARCHID).physIndex, r.marchid); + context->setMiscRegNoEffect( + CSRData.at(CSR_MIMPID).physIndex, r.mimpid); + context->setMiscRegNoEffect( + CSRData.at(CSR_MHARTID).physIndex, r.mhartid); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_MSTATUS).physIndex); + mask = CSRMasks.at(CSR_MSTATUS); + newVal = (oldVal & ~mask) | (r.mstatus & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_MSTATUS).physIndex, newVal); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_MISA).physIndex); + mask = CSRMasks.at(CSR_MISA); + newVal = (oldVal & ~mask) | (r.misa & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_MISA).physIndex, newVal); + context->setMiscRegNoEffect( + CSRData.at(CSR_MEDELEG).physIndex, r.medeleg); + context->setMiscRegNoEffect( + CSRData.at(CSR_MIDELEG).physIndex, r.mideleg); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_MIE).physIndex); + mask = CSRMasks.at(CSR_MIE); + newVal = (oldVal & ~mask) | (r.mie & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_MIE).physIndex, newVal); + context->setMiscRegNoEffect( + CSRData.at(CSR_MTVEC).physIndex, r.mtvec); + context->setMiscRegNoEffect( + CSRData.at(CSR_MCOUNTEREN).physIndex, r.mcounteren); + context->setMiscRegNoEffect( + CSRData.at(CSR_MSCRATCH).physIndex, r.mscratch); + context->setMiscRegNoEffect( + CSRData.at(CSR_MEPC).physIndex, r.mepc); + context->setMiscRegNoEffect( + CSRData.at(CSR_MCAUSE).physIndex, r.mcause); + context->setMiscRegNoEffect( + CSRData.at(CSR_MTVAL).physIndex, r.mtval); + oldVal = context->readMiscRegNoEffect( + CSRData.at(CSR_MIP).physIndex); + mask = CSRMasks.at(CSR_MIP); + newVal = (oldVal & ~mask) | (r.mip & mask); + context->setMiscRegNoEffect( + CSRData.at(CSR_MIP).physIndex, newVal); + + // H mode CSR (to be implemented) +} + +bool +RemoteGDB::getXferFeaturesRead(const std::string &annex, std::string &output) +{ + /** + * Blobs e.g. gdb_xml_riscv_target are generated by adding + * GdbXml(, ) to src/arch/riscv/Sconscript. + * + * Import using #include blobs/.hh + */ +#define GDB_XML(x, s) \ + { \ + x, std::string(reinterpret_cast(Blobs::s), \ + Blobs::s##_len) \ + } + static const std::map annexMap{ + GDB_XML("target.xml", gdb_xml_riscv_target), + GDB_XML("riscv-64bit-cpu.xml", gdb_xml_riscv_cpu), + GDB_XML("riscv-64bit-fpu.xml", gdb_xml_riscv_fpu), + GDB_XML("riscv-64bit-csr.xml", gdb_xml_riscv_csr)}; +#undef GDB_XML + auto it = annexMap.find(annex); + if (it == annexMap.end()) + return false; + output = it->second; + return true; } -BaseGdbRegCache* +BaseGdbRegCache * RemoteGDB::gdbRegs() { return ®Cache; diff --git a/src/arch/riscv/remote_gdb.hh b/src/arch/riscv/remote_gdb.hh index a9d3b0c5c..545a43c4a 100644 --- a/src/arch/riscv/remote_gdb.hh +++ b/src/arch/riscv/remote_gdb.hh @@ -1,4 +1,5 @@ /* + * Copyright (c) 2021 Huawei International * Copyright (c) 2017 The University of Virginia * Copyright 2015 LabWare * Copyright 2014 Google, Inc. @@ -57,9 +58,71 @@ class RemoteGDB : public BaseRemoteGDB { using BaseGdbRegCache::BaseGdbRegCache; private: + /** + * RISC-V Register Cache + * Order and sizes of registers found in ext/gdb-xml/riscv.xml + * To add support for more CSRs: + * 1. Uncomment relevant lines in ext/gdb-xml/riscv-64bit-csr.xml + * 2. Add register to struct below + * 3. Modify RiscvGdbRegCache::getRegs and setRegs + */ struct { uint64_t gpr[NumIntArchRegs]; uint64_t pc; + uint64_t fpu[NumFloatRegs]; + uint32_t fflags; + uint32_t frm; + uint32_t fcsr; + // Placeholder for byte alignment + uint32_t placeholder; + uint64_t cycle; + uint64_t time; + uint64_t ustatus; + uint64_t uie; + uint64_t utvec; + uint64_t uscratch; + uint64_t uepc; + uint64_t ucause; + uint64_t utval; + uint64_t uip; + uint64_t sstatus; + uint64_t sedeleg; + uint64_t sideleg; + uint64_t sie; + uint64_t stvec; + uint64_t scounteren; + uint64_t sscratch; + uint64_t sepc; + uint64_t scause; + uint64_t stval; + uint64_t sip; + uint64_t satp; + uint64_t mvendorid; + uint64_t marchid; + uint64_t mimpid; + uint64_t mhartid; + uint64_t mstatus; + uint64_t misa; + uint64_t medeleg; + uint64_t mideleg; + uint64_t mie; + uint64_t mtvec; + uint64_t mcounteren; + uint64_t mscratch; + uint64_t mepc; + uint64_t mcause; + uint64_t mtval; + uint64_t mip; + uint64_t hstatus; + uint64_t hedeleg; + uint64_t hideleg; + uint64_t hie; + uint64_t htvec; + uint64_t hscratch; + uint64_t hepc; + uint64_t hcause; + uint64_t hbadaddr; + uint64_t hip; } r; public: char *data() const { return (char *)&r; } @@ -79,6 +142,19 @@ class RemoteGDB : public BaseRemoteGDB public: RemoteGDB(System *_system, ThreadContext *tc, int _port); BaseGdbRegCache *gdbRegs() override; + /** + * Informs GDB remote serial protocol that XML features are supported + * GDB then queries for xml blobs using qXfer:features:read:xxx.xml + */ + std::vector + availableFeatures() const + { + return {"qXfer:features:read+"}; + }; + /** + * Reply to qXfer:features:read:xxx.xml qeuries + */ + bool getXferFeaturesRead(const std::string &annex, std::string &output); }; } // namespace RiscvISA -- 2.30.2