mem-cache: Add multiple eviction stats
[gem5.git] / src / arch / arm / remote_gdb.cc
index bf763957523a11c002867ebc1ab3cb6868ecb4c2..ceb0ffafe9cb189e1c813738753043bb5e6810f5 100644 (file)
@@ -1,5 +1,7 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright 2015 LabWare
+ * Copyright 2014 Google Inc.
+ * Copyright (c) 2010, 2013, 2016, 2018-2019 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  *
  * Authors: Nathan Binkert
  *          William Wang
+ *          Boris Shingarov
  */
 
 /*
- * Copyright (c) 1990, 1993
- *      The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1990, 1993 The Regents of the University of California
+ * All rights reserved
  *
  * This software was developed by the Computer Systems Engineering group
  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
  * "Stub" to allow remote cpu to debug over a serial line using gdb.
  */
 
+#include "arch/arm/remote_gdb.hh"
+
 #include <sys/signal.h>
 #include <unistd.h>
 
 #include <string>
 
-#include "config/full_system.hh"
-#if FULL_SYSTEM
-#include "arch/arm/vtophys.hh"
-#endif
-
-#include "arch/arm/utility.hh"
-#include "arch/arm/remote_gdb.hh"
+#include "arch/arm/decoder.hh"
+#include "arch/arm/pagetable.hh"
 #include "arch/arm/registers.hh"
+#include "arch/arm/system.hh"
+#include "arch/arm/utility.hh"
 #include "arch/arm/vtophys.hh"
+#include "base/chunk_generator.hh"
 #include "base/intmath.hh"
 #include "base/remote_gdb.hh"
 #include "base/socket.hh"
 #include "base/trace.hh"
+#include "blobs/gdb_xml_aarch64_core.hh"
+#include "blobs/gdb_xml_aarch64_fpu.hh"
+#include "blobs/gdb_xml_aarch64_target.hh"
+#include "blobs/gdb_xml_arm_core.hh"
+#include "blobs/gdb_xml_arm_target.hh"
+#include "blobs/gdb_xml_arm_vfpv3.hh"
+#include "cpu/static_inst.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/thread_state.hh"
-#include "cpu/static_inst.hh"
+#include "debug/GDBAcc.hh"
+#include "debug/GDBMisc.hh"
+#include "mem/page_table.hh"
 #include "mem/physical.hh"
 #include "mem/port.hh"
+#include "sim/full_system.hh"
 #include "sim/system.hh"
-#include "arch/arm/pagetable.hh"
-#include "mem/page_table.hh"
 
 using namespace std;
 using namespace ArmISA;
 
-RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
-    : BaseRemoteGDB(_system, tc, NUMREGS)
+RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
+    : BaseRemoteGDB(_system, tc, _port), regCache32(this), regCache64(this)
 {
 }
 
@@ -170,177 +181,165 @@ RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
 bool
 RemoteGDB::acc(Addr va, size_t len)
 {
-#if FULL_SYSTEM
-    Addr last_va;
-    va       = truncPage(va);
-    last_va  = roundPage(va + len);
-
-    do  {
-        if (virtvalid(context, va)) {
-            return true;
+    if (FullSystem) {
+        for (ChunkGenerator gen(va, len, PageBytes); !gen.done(); gen.next()) {
+            if (!virtvalid(context(), gen.addr())) {
+                DPRINTF(GDBAcc, "acc:   %#x mapping is invalid\n", va);
+                return false;
+            }
         }
-        va += PageBytes;
-    } while (va < last_va);
 
-    DPRINTF(GDBAcc, "acc:   %#x mapping is valid\n", va);
-    return true;
-#else
-    TlbEntry entry;
-    //Check to make sure the first byte is mapped into the processes address
-    //space.
-    if (context->getProcessPtr()->pTable->lookup(va, entry))
+        DPRINTF(GDBAcc, "acc:   %#x mapping is valid\n", va);
         return true;
-    return false;
-#endif
+    } else {
+        // Check to make sure the first byte is mapped into the processes
+        // address space.
+        return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
+    }
 }
 
-/*
- * Translate the kernel debugger register format into the GDB register
- * format.
- */
 void
-RemoteGDB::getregs()
+RemoteGDB::AArch64GdbRegCache::getRegs(ThreadContext *context)
 {
-    DPRINTF(GDBAcc, "getregs in remotegdb \n");
-
-    memset(gdbregs.regs, 0, gdbregs.bytes());
-
-    // R0-R15 supervisor mode
-    // arm registers are 32 bits wide, gdb registers are 64 bits wide
-    // two arm registers are packed into one gdb register (little endian)
-    gdbregs.regs[REG_R0 + 0] = context->readIntReg(INTREG_R1) << 32 |
-                                       context->readIntReg(INTREG_R0);
-    gdbregs.regs[REG_R0 + 1] = context->readIntReg(INTREG_R3) << 32 |
-                                       context->readIntReg(INTREG_R2);
-    gdbregs.regs[REG_R0 + 2] = context->readIntReg(INTREG_R5) << 32 |
-                                       context->readIntReg(INTREG_R4);
-    gdbregs.regs[REG_R0 + 3] = context->readIntReg(INTREG_R7) << 32 |
-                                       context->readIntReg(INTREG_R6);
-    gdbregs.regs[REG_R0 + 4] = context->readIntReg(INTREG_R9) << 32 |
-                                       context->readIntReg(INTREG_R8);
-    gdbregs.regs[REG_R0 + 5] = context->readIntReg(INTREG_R11) << 32|
-                                       context->readIntReg(INTREG_R10);
-    gdbregs.regs[REG_R0 + 6] = context->readIntReg(INTREG_SP) << 32 |
-                                       context->readIntReg(INTREG_R12);
-    gdbregs.regs[REG_R0 + 7] = context->pcState().pc() << 32        |
-                                       context->readIntReg(INTREG_LR);
-
-    // CPSR
-    gdbregs.regs[REG_CPSR]  = context->readMiscRegNoEffect(MISCREG_CPSR);
-
-    // vfpv3/neon floating point registers (32 double or 64 float)
-
-    gdbregs.regs[REG_F0] =
-        static_cast<uint64_t>(context->readFloatRegBits(0)) << 32 |
-        gdbregs.regs[REG_CPSR];
-
-    for (int i = 1; i < (NumFloatArchRegs>>1); ++i) {
-      gdbregs.regs[i + REG_F0] =
-          static_cast<uint64_t>(context->readFloatRegBits(2*i)) << 32 |
-          context->readFloatRegBits(2*i-1);
+    DPRINTF(GDBAcc, "getRegs in remotegdb \n");
+
+    for (int i = 0; i < 31; ++i)
+        r.x[i] = context->readIntReg(INTREG_X0 + i);
+    r.spx = context->readIntReg(INTREG_SPX);
+    r.pc = context->pcState().pc();
+    r.cpsr = context->readMiscRegNoEffect(MISCREG_CPSR);
+
+    size_t base = 0;
+    for (int i = 0; i < NumVecV8ArchRegs; i++) {
+        auto v = (context->readVecReg(RegId(VecRegClass, i))).as<VecElem>();
+        for (size_t j = 0; j < NumVecElemPerNeonVecReg; j++) {
+            r.v[base] = v[j];
+            base++;
+        }
     }
-
-  // FPSCR
-    gdbregs.regs[REG_FPSCR] =
-        static_cast<uint64_t>(context->readMiscRegNoEffect(MISCREG_FPSCR)) << 32 |
-        context->readFloatRegBits(NumFloatArchRegs - 1);
+    r.fpsr = context->readMiscRegNoEffect(MISCREG_FPSR);
+    r.fpcr = context->readMiscRegNoEffect(MISCREG_FPCR);
 }
 
-/*
- * Translate the GDB register format into the kernel debugger register
- * format.
- */
 void
-RemoteGDB::setregs()
+RemoteGDB::AArch64GdbRegCache::setRegs(ThreadContext *context) const
 {
-
-    DPRINTF(GDBAcc, "setregs in remotegdb \n");
-
-    // R0-R15 supervisor mode
-    // arm registers are 32 bits wide, gdb registers are 64 bits wide
-    // two arm registers are packed into one gdb register (little endian)
-    context->setIntReg(INTREG_R0 , bits(gdbregs.regs[REG_R0 + 0], 31, 0));
-    context->setIntReg(INTREG_R1 , bits(gdbregs.regs[REG_R0 + 0], 63, 32));
-    context->setIntReg(INTREG_R2 , bits(gdbregs.regs[REG_R0 + 1], 31, 0));
-    context->setIntReg(INTREG_R3 , bits(gdbregs.regs[REG_R0 + 1], 63, 32));
-    context->setIntReg(INTREG_R4 , bits(gdbregs.regs[REG_R0 + 2], 31, 0));
-    context->setIntReg(INTREG_R5 , bits(gdbregs.regs[REG_R0 + 2], 63, 32));
-    context->setIntReg(INTREG_R6 , bits(gdbregs.regs[REG_R0 + 3], 31, 0));
-    context->setIntReg(INTREG_R7 , bits(gdbregs.regs[REG_R0 + 3], 63, 32));
-    context->setIntReg(INTREG_R8 , bits(gdbregs.regs[REG_R0 + 4], 31, 0));
-    context->setIntReg(INTREG_R9 , bits(gdbregs.regs[REG_R0 + 4], 63, 32));
-    context->setIntReg(INTREG_R10, bits(gdbregs.regs[REG_R0 + 5], 31, 0));
-    context->setIntReg(INTREG_R11, bits(gdbregs.regs[REG_R0 + 5], 63, 32));
-    context->setIntReg(INTREG_R12, bits(gdbregs.regs[REG_R0 + 6], 31, 0));
-    context->setIntReg(INTREG_SP , bits(gdbregs.regs[REG_R0 + 6], 63, 32));
-    context->setIntReg(INTREG_LR , bits(gdbregs.regs[REG_R0 + 7], 31, 0));
-    context->pcState(bits(gdbregs.regs[REG_R0 + 7], 63, 32));
-
-    //CPSR
-    context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs[REG_CPSR]);
-
-    //vfpv3/neon floating point registers (32 double or 64 float)
-    context->setFloatRegBits(0, gdbregs.regs[REG_F0]>>32);
-
-    for (int i = 1; i < NumFloatArchRegs; ++i) {
-      if(i%2){
-        int j = (i+1)/2;
-        context->setFloatRegBits(i, bits(gdbregs.regs[j + REG_F0], 31, 0));
-      }
-      else{
-        int j = i/2;
-        context->setFloatRegBits(i, gdbregs.regs[j + REG_F0]>>32);
-      }
+    DPRINTF(GDBAcc, "setRegs in remotegdb \n");
+
+    for (int i = 0; i < 31; ++i)
+        context->setIntReg(INTREG_X0 + i, r.x[i]);
+    auto pc_state = context->pcState();
+    pc_state.set(r.pc);
+    context->pcState(pc_state);
+    context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr);
+    // Update the stack pointer. This should be done after
+    // updating CPSR/PSTATE since that might affect how SPX gets
+    // mapped.
+    context->setIntReg(INTREG_SPX, r.spx);
+
+    size_t base = 0;
+    for (int i = 0; i < NumVecV8ArchRegs; i++) {
+        auto v = (context->getWritableVecReg(
+                RegId(VecRegClass, i))).as<VecElem>();
+        for (size_t j = 0; j < NumVecElemPerNeonVecReg; j++) {
+            v[j] = r.v[base];
+            base++;
+        }
     }
-
-    //FPSCR
-    context->setMiscRegNoEffect(MISCREG_FPSCR, gdbregs.regs[REG_FPSCR]>>32);
+    context->setMiscRegNoEffect(MISCREG_FPSR, r.fpsr);
+    context->setMiscRegNoEffect(MISCREG_FPCR, r.fpcr);
 }
 
 void
-RemoteGDB::clearSingleStep()
+RemoteGDB::AArch32GdbRegCache::getRegs(ThreadContext *context)
 {
-    DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
-            takenBkpt, notTakenBkpt);
-
-    if (takenBkpt != 0)
-        clearTempBreakpoint(takenBkpt);
-
-    if (notTakenBkpt != 0)
-        clearTempBreakpoint(notTakenBkpt);
+    DPRINTF(GDBAcc, "getRegs in remotegdb \n");
+
+    r.gpr[0] = context->readIntReg(INTREG_R0);
+    r.gpr[1] = context->readIntReg(INTREG_R1);
+    r.gpr[2] = context->readIntReg(INTREG_R2);
+    r.gpr[3] = context->readIntReg(INTREG_R3);
+    r.gpr[4] = context->readIntReg(INTREG_R4);
+    r.gpr[5] = context->readIntReg(INTREG_R5);
+    r.gpr[6] = context->readIntReg(INTREG_R6);
+    r.gpr[7] = context->readIntReg(INTREG_R7);
+    r.gpr[8] = context->readIntReg(INTREG_R8);
+    r.gpr[9] = context->readIntReg(INTREG_R9);
+    r.gpr[10] = context->readIntReg(INTREG_R10);
+    r.gpr[11] = context->readIntReg(INTREG_R11);
+    r.gpr[12] = context->readIntReg(INTREG_R12);
+    r.gpr[13] = context->readIntReg(INTREG_SP);
+    r.gpr[14] = context->readIntReg(INTREG_LR);
+    r.gpr[15] = context->pcState().pc();
+    r.cpsr = context->readMiscRegNoEffect(MISCREG_CPSR);
+
+    // One day somebody will implement transfer of FPRs correctly.
+    for (int i = 0; i < 32; i++)
+        r.fpr[i] = 0;
+
+    r.fpscr = context->readMiscRegNoEffect(MISCREG_FPSCR);
 }
 
 void
-RemoteGDB::setSingleStep()
+RemoteGDB::AArch32GdbRegCache::setRegs(ThreadContext *context) const
 {
-    PCState pc = context->pcState();
-    PCState bpc;
-    bool set_bt = false;
-
-    // User was stopped at pc, e.g. the instruction at pc was not
-    // executed.
-    MachInst inst = read<MachInst>(pc.pc());
-    StaticInstPtr si(inst, pc.pc());
-    if (si->hasBranchTarget(pc, context, bpc)) {
-        // Don't bother setting a breakpoint on the taken branch if it
-        // is the same as the next pc
-        if (bpc.pc() != pc.npc())
-            set_bt = true;
-    }
-
-    DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
-            takenBkpt, notTakenBkpt);
-
-    setTempBreakpoint(notTakenBkpt = pc.npc());
-
-    if (set_bt)
-        setTempBreakpoint(takenBkpt = bpc.pc());
+    DPRINTF(GDBAcc, "setRegs in remotegdb \n");
+
+    context->setIntReg(INTREG_R0, r.gpr[0]);
+    context->setIntReg(INTREG_R1, r.gpr[1]);
+    context->setIntReg(INTREG_R2, r.gpr[2]);
+    context->setIntReg(INTREG_R3, r.gpr[3]);
+    context->setIntReg(INTREG_R4, r.gpr[4]);
+    context->setIntReg(INTREG_R5, r.gpr[5]);
+    context->setIntReg(INTREG_R6, r.gpr[6]);
+    context->setIntReg(INTREG_R7, r.gpr[7]);
+    context->setIntReg(INTREG_R8, r.gpr[8]);
+    context->setIntReg(INTREG_R9, r.gpr[9]);
+    context->setIntReg(INTREG_R10, r.gpr[10]);
+    context->setIntReg(INTREG_R11, r.gpr[11]);
+    context->setIntReg(INTREG_R12, r.gpr[12]);
+    context->setIntReg(INTREG_SP, r.gpr[13]);
+    context->setIntReg(INTREG_LR, r.gpr[14]);
+    auto pc_state = context->pcState();
+    pc_state.set(r.gpr[15]);
+    context->pcState(pc_state);
+
+    // One day somebody will implement transfer of FPRs correctly.
+
+    context->setMiscReg(MISCREG_FPSCR, r.fpscr);
+    context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr);
 }
 
-// Write bytes to kernel address space for debugger.
 bool
-RemoteGDB::write(Addr vaddr, size_t size, const char *data)
+RemoteGDB::getXferFeaturesRead(const std::string &annex, std::string &output)
 {
-    return BaseRemoteGDB::write(vaddr, size, data);
+#define GDB_XML(x, s) \
+        { x, std::string(reinterpret_cast<const char *>(Blobs::s), \
+        Blobs::s ## _len) }
+    static const std::map<std::string, std::string> annexMap32{
+        GDB_XML("target.xml", gdb_xml_arm_target),
+        GDB_XML("arm-core.xml", gdb_xml_arm_core),
+        GDB_XML("arm-vfpv3.xml", gdb_xml_arm_vfpv3),
+    };
+    static const std::map<std::string, std::string> annexMap64{
+        GDB_XML("target.xml", gdb_xml_aarch64_target),
+        GDB_XML("aarch64-core.xml", gdb_xml_aarch64_core),
+        GDB_XML("aarch64-fpu.xml", gdb_xml_aarch64_fpu),
+    };
+#undef GDB_XML
+    auto& annexMap = inAArch64(context()) ? annexMap64 : annexMap32;
+    auto it = annexMap.find(annex);
+    if (it == annexMap.end())
+        return false;
+    output = it->second;
+    return true;
 }
 
+BaseGdbRegCache*
+RemoteGDB::gdbRegs()
+{
+    if (inAArch64(context()))
+        return &regCache64;
+    else
+        return &regCache32;
+}