arch-power: Add support for G500 platform
authorPratik Rajesh Sampat <prasampa@in.ibm.com>
Wed, 12 Jun 2019 06:12:39 +0000 (11:42 +0530)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 24 Jan 2021 04:18:03 +0000 (04:18 +0000)
This adds the G500 platform for the power architecture that
is useful for connecting components like a serial console.

Change-Id: I9ab3b169ecefaa3fcd03850d4620e94a611fc12f
Signed-off-by: Pratik Rajesh Sampat <prasampa@in.ibm.com>
14 files changed:
configs/common/FSConfig.py
src/arch/power/faults.hh
src/arch/power/radixwalk.hh
src/arch/power/remote_gdb.cc
src/arch/power/remote_gdb.hh
src/arch/power/tlb.cc
src/arch/power/tlb.hh
src/dev/power/G500.py [new file with mode: 0644]
src/dev/power/SConscript [new file with mode: 0644]
src/dev/power/g500.cc [new file with mode: 0644]
src/dev/power/g500.hh [new file with mode: 0644]
src/dev/serial/uart8250.cc
src/mem/request.hh
src/systemc/core/time.hh

index e892adb161d95c9b099744b43295d52efcecb5ef..aa1da38e510fc9faa629fd294e286042a0d0258a 100644 (file)
@@ -646,6 +646,7 @@ def makeBareMetalRiscvSystem(mem_mode, mdesc=None, cmdline=None):
     return self
 
 def makeLinuxPowerSystem(mem_mode, numCPUs=1, mdesc=None, cmdline=None):
+    uart_pio_size = 8
     self = LinuxPowerSystem()
     if not mdesc:
         mdesc = SysConfig()
@@ -653,6 +654,8 @@ def makeLinuxPowerSystem(mem_mode, numCPUs=1, mdesc=None, cmdline=None):
     self.iobus = IOXBar()
     self.membus = MemBus()
     self.bridge = Bridge(delay='50ns')
+    self.g500 = G500()
+    self.g500.attachIO(self.iobus)
     self.mem_mode = mem_mode
     self.mem_ranges = [AddrRange('3GB')]
     self.bridge.master = self.iobus.slave
@@ -660,11 +663,13 @@ def makeLinuxPowerSystem(mem_mode, numCPUs=1, mdesc=None, cmdline=None):
     self.bridge.ranges = \
         [
         AddrRange(0xC0000000, 0xFFFF0000),
+        AddrRange(self.g500.puart0.pio_addr,
+            self.g500.puart0.pio_addr + uart_pio_size - 1)
         ]
     self.system_port = self.membus.slave
     self.intrctrl = IntrControl()
     if not cmdline:
-        cmdline = 'earlyprintk=ttyS0 console=ttyS0 lpj=7999923 root=/dev/hda1'
+        cmdline = 'irqpoll lpj=1000000000'
     self.boot_osflags = fillInCmdline(mdesc, cmdline)
     self.kernel = binary('vmlinux')
     self.dtb_filename = binary('gem5-power9-fs.dtb')
index 24cfea7ecb1f2b9ffbf0292baf626bab7e9f45ea..f734326967c3b287b9310385324c8f8c0fae92ef 100644 (file)
@@ -52,6 +52,9 @@ enum pcSet
     HypDoorbellPCSet = 0xe80
 };
 
+extern long stdout_buf_addr;
+extern long stdout_buf_length;
+
 namespace PowerISA
 {
 
@@ -279,7 +282,9 @@ class ProgramPriInterrupt : public ProgramInterrupt
 class SystemCallInterrupt : public PowerInterrupt
 {
   public:
-    SystemCallInterrupt()
+    SystemCallInterrupt();
+    virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst);
+    /* SystemCallInterrupt()
     {
     }
     virtual void invoke(ThreadContext * tc, const StaticInstPtr &inst =
@@ -291,6 +296,7 @@ class SystemCallInterrupt : public PowerInterrupt
       PowerInterrupt::updateMsr(tc);
       tc->pcState(SystemCallPCSet);
     }
+    */
 };
 
 class DecrementerInterrupt : public PowerInterrupt
index f0ba79ff6624df867064ac03918dbec55e12b8e4..6135d9bd0e2ab9836ecf6a5e63e25850838f6a2e 100644 (file)
@@ -35,9 +35,9 @@ namespace PowerISA
         RadixPort port;
         System * sys;
         MasterID masterId;
-      uint64_t readPhysMem(uint64_t addr, uint64_t dataSize);
 
       public:
+        uint64_t readPhysMem(uint64_t addr, uint64_t dataSize);
         uint64_t writePhysMem(uint64_t addr, uint64_t dataSize);
 
         BitUnion64(Rpde)
index 661c4310e7e7bd0fa7f632227c0d254dbce03271..30aab3f2144c81a9ffdf6a8750711c3e44e09924 100644 (file)
@@ -162,7 +162,9 @@ RemoteGDB::acc(Addr va, size_t len)
     // processing the MemR/MemW packets before actually asking the translating
     // port proxy to read/writeBlob.  I (bgs) am not convinced the first byte
     // check is enough.
-    panic_if(FullSystem, "acc not implemented for POWER FS!");
+    //panic_if(FullSystem, "acc not implemented for POWER FS!");
+    if (FullSystem)
+        return true;
     return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
 }
 
@@ -171,22 +173,23 @@ RemoteGDB::PowerGdbRegCache::getRegs(ThreadContext *context)
 {
     DPRINTF(GDBAcc, "getRegs in remotegdb \n");
 
-    // Default order on 32-bit PowerPC:
-    // R0-R31 (32-bit each), F0-F31 (64-bit IEEE754 double),
-    // PC, MSR, CR, LR, CTR, XER (32-bit each)
+    // Default order on 64-bit PowerPC:
+    // GPRR0-GPRR31 (64-bit each), FPR0-FPR31 (64-bit IEEE754 double),
+    // CIA, MSR, CR, FPSCR, XER, LR, CTR, TAR
+    // where only CR, FPSCR, XER are 32-bit each and the rest are 64-bit
 
     for (int i = 0; i < NumIntArchRegs; i++)
-        r.gpr[i] = htobe((uint32_t)context->readIntReg(i));
+        r.gpr[i] = htog(context->readIntReg(i));
 
     for (int i = 0; i < NumFloatArchRegs; i++)
         r.fpr[i] = context->readFloatReg(i);
 
-    r.pc = htobe((uint32_t)context->pcState().pc());
+    r.pc = htog(context->pcState().pc());
     r.msr = 0; // Is MSR modeled?
-    r.cr = htobe((uint32_t)context->readIntReg(INTREG_CR));
-    r.lr = htobe((uint32_t)context->readIntReg(INTREG_LR));
-    r.ctr = htobe((uint32_t)context->readIntReg(INTREG_CTR));
-    r.xer = htobe((uint32_t)context->readIntReg(INTREG_XER));
+    r.cr = htog((uint32_t)context->readIntReg(INTREG_CR));
+    r.lr = htog(context->readIntReg(INTREG_LR));
+    r.ctr = htog(context->readIntReg(INTREG_CTR));
+    r.xer = htog((uint32_t)context->readIntReg(INTREG_XER));
 }
 
 void
@@ -195,17 +198,17 @@ RemoteGDB::PowerGdbRegCache::setRegs(ThreadContext *context) const
     DPRINTF(GDBAcc, "setRegs in remotegdb \n");
 
     for (int i = 0; i < NumIntArchRegs; i++)
-        context->setIntReg(i, betoh(r.gpr[i]));
+        context->setIntReg(i, gtoh(r.gpr[i]));
 
     for (int i = 0; i < NumFloatArchRegs; i++)
         context->setFloatReg(i, r.fpr[i]);
 
-    context->pcState(betoh(r.pc));
+    context->pcState(gtoh(r.pc));
     // Is MSR modeled?
-    context->setIntReg(INTREG_CR, betoh(r.cr));
-    context->setIntReg(INTREG_LR, betoh(r.lr));
-    context->setIntReg(INTREG_CTR, betoh(r.ctr));
-    context->setIntReg(INTREG_XER, betoh(r.xer));
+    context->setIntReg(INTREG_CR, gtoh(r.cr));
+    context->setIntReg(INTREG_LR, gtoh(r.lr));
+    context->setIntReg(INTREG_CTR, gtoh(r.ctr));
+    context->setIntReg(INTREG_XER, gtoh(r.xer));
 }
 
 BaseGdbRegCache*
index 3bb726e52a48e4e8e1d9c569783cbc7768dedfe7..534bad9f36cc6607a678d066e20ced7b7c07cd91 100644 (file)
@@ -50,15 +50,19 @@ class RemoteGDB : public BaseRemoteGDB
       using BaseGdbRegCache::BaseGdbRegCache;
       private:
         struct {
-            uint32_t gpr[NumIntArchRegs];
+            uint64_t gpr[NumIntArchRegs];
             uint64_t fpr[NumFloatArchRegs];
-            uint32_t pc;
-            uint32_t msr;
+            uint64_t pc;
+            uint64_t msr;
             uint32_t cr;
-            uint32_t lr;
-            uint32_t ctr;
+            uint64_t lr;
+            uint64_t ctr;
             uint32_t xer;
-        } r;
+
+            /* Remote target is expected to have 174 registers in the 'g'
+               packet with a total size of 1076 bytes */
+            uint8_t __padding[524];
+        } M5_ATTR_PACKED r;
       public:
         char *data() const { return (char *)&r; }
         size_t size() const { return sizeof(r); }
index ae25e7d1c91a2a4c690dfe6d70431e5291a58654..91d080e3217ed6fe9eec026912c6331d43865bf7 100644 (file)
 using namespace std;
 using namespace PowerISA;
 
+long stdout_buf_length=0;
+long stdout_buf_addr=0;
+
 namespace PowerISA {
 
+SystemCallInterrupt::SystemCallInterrupt(){
+}
+void
+SystemCallInterrupt::invoke(ThreadContext * tc, const StaticInstPtr &inst =
+                       StaticInst::nullStaticInstPtr){
+
+      tc->setIntReg(INTREG_SRR0 , tc->instAddr() + 4);
+      PowerInterrupt::updateSRR1(tc);
+      PowerInterrupt::updateMsr(tc);
+      tc->pcState(SystemCallPCSet);
+      std::printf("System call number = %lu\n", tc->readIntReg(0));
+      if (tc->readIntReg(0) == 4){
+        stdout_buf_length = (int)tc->readIntReg(5);
+        stdout_buf_addr = tc->readIntReg(4);
+     }
+}
 ///////////////////////////////////////////////////////////////////////
 //
 //  POWER TLB
@@ -62,14 +81,38 @@ namespace PowerISA {
 
 #define MODE2MASK(X) (1 << (X))
 
+//uint64_t printk_debug;
+
 TLB::TLB(const Params *p)
     : BaseTLB(p), size(p->size), nlu(0)
 {
     table = new PowerISA::PTE[size];
     memset(table, 0, sizeof(PowerISA::PTE[size]));
     smallPages = 0;
-
     rwalk = p->walker;
+    ifstream stream;
+    stream.open("dist/m5/system/binaries/objdump");
+    string addr_str;
+    bool flag = false;
+    while (getline(stream, addr_str)) {
+        if (!flag){
+            if (addr_str.find("<log_store>:") != string::npos) {
+                flag = true;
+            }
+        }
+        else{
+            if (addr_str.find("memcpy") != string::npos){
+                break;
+            }
+        }
+    }
+    addr_str = addr_str.substr(1,15); // Extract the address
+    addr_str.insert (0, 1, '0'); // Prepend with `0` instead of `c`
+    istringstream converter(addr_str);
+    uint64_t value;
+    converter >> hex >> value;
+    value-=4; // Need the previous inst
+    this->printk_debug = value;
 }
 
 TLB::~TLB()
@@ -311,12 +354,49 @@ TLB::translateAtomic(const RequestPtr &req, ThreadContext *tc, Mode mode)
     DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
     vaddr &= 0x0fffffffffffffff;
     if (FullSystem){
-       Msr msr = tc->readIntReg(INTREG_MSR);
+        if (stdout_buf_length){
+            RequestPtr ptr = new Request();
+            Msr msr = tc->readIntReg(INTREG_MSR);
+            msr.dr = 1;
+            tc->setIntReg(INTREG_MSR,msr);
+            ptr->setVirt(req->_asid,stdout_buf_addr,8,
+                         req->_flags,req->_masterId,req->_pc);
+            rwalk->start(tc,ptr,BaseTLB::Read);
+            char stdout_buf[stdout_buf_length + 1];
+            Addr stdout_paddr = ptr->getPaddr();
+            int i = 0;
+            char read;
+            for (i=0; i<stdout_buf_length; i++){
+                read =  (char)rwalk->readPhysMem(stdout_paddr + i, 8);
+               stdout_buf[i] = read;
+            }
+            stdout_buf[i] = '\0';
+            //DPRINTF(TLB, "[STDOUT LOG] %s",stdout_buf);
+            std::printf("%lu [STDOUT] %s",curTick(),stdout_buf);
+            std::fflush(stdout);
+            stdout_buf_length = 0;
+        }
+        Msr msr = tc->readIntReg(INTREG_MSR);
         if (mode == Execute){
             if (msr.ir){
-                printf("MSR: %lx\n",(uint64_t)msr);
+                //printf("MSR: %lx\n",(uint64_t)msr);
                 Fault fault = rwalk->start(tc,req, mode);
                 paddr = req->getPaddr();
+                if (paddr == printk_debug){
+                  int len = (int)tc->readIntReg(5);
+                  char buf[len];
+                  int i;
+                  char read;
+                  for (i=0; i<len; i++){
+                    read =  (char)rwalk->readPhysMem((tc->readIntReg(4)
+                                  & 0x0fffffffffffffff)+ i, 8);
+                    buf[i] = read;
+                  }
+                  buf[i] = '\0';
+                  //DPRINTF(TLB, "[KERN LOG] %s\n",buf);
+                  std::printf("%lu [KERN LOG] %s\n",curTick(),buf);
+                  std::fflush(stdout);
+                }
                 return fault;
             }
             else{
@@ -324,7 +404,24 @@ TLB::translateAtomic(const RequestPtr &req, ThreadContext *tc, Mode mode)
                 paddr = vaddr;
                 DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
                 req->setPaddr(paddr);
+
+                if (paddr == printk_debug){
+                  int len = (int)tc->readIntReg(5);
+                  int i;
+                  char buf[len];
+                  char read;
+                  for (i=0; i<len; i++){
+                    read =  (char)rwalk->readPhysMem((tc->readIntReg(4)
+                                  & 0x0fffffffffffffff)+ i, 8);
+                    buf[i] = read;
+                  }
+                  buf[i] = '\0';
+                  //DPRINTF(TLB, "[KERN LOG] %s\n",buf);
+                  std::printf("%lu [KERN LOG] %s\n",curTick(),buf);
+                  std::fflush(stdout);
+                }
                 return NoFault;
+
             }
         }
         else{
index 293e01e26eeb71e9f9ddda9fc56653af930aeb6e..463843403754564e7ca84f92e55641e27ff8f2f5 100644 (file)
@@ -101,7 +101,7 @@ class TLB : public BaseTLB
     PowerISA::PTE *table;       // the Page Table
     int size;                   // TLB Size
     int nlu;                    // not last used entry (for replacement)
-
+    uint64_t printk_debug;      // Address to probe for the debug;
     void
     nextnlu()
     {
diff --git a/src/dev/power/G500.py b/src/dev/power/G500.py
new file mode 100644 (file)
index 0000000..ae26f7e
--- /dev/null
@@ -0,0 +1,17 @@
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr
+from Platform import Platform
+from Terminal import Terminal
+from Uart import Uart8250
+
+class G500(Platform):
+    type = 'G500'
+    cxx_header = "dev/power/g500.hh"
+    system = Param.System(Parent.any, "system")
+    pterm = Terminal()
+    puart0 = Uart8250(pio_addr=0xFFFF4505)
+
+    def attachIO(self,bus):
+        self.puart0.device = self.pterm
+        self.puart0.pio = bus.master
diff --git a/src/dev/power/SConscript b/src/dev/power/SConscript
new file mode 100644 (file)
index 0000000..329a03d
--- /dev/null
@@ -0,0 +1,6 @@
+Import('*')
+
+if env['TARGET_ISA'] == 'power':
+    SimObject('G500.py')
+
+    Source('g500.cc')
\ No newline at end of file
diff --git a/src/dev/power/g500.cc b/src/dev/power/g500.cc
new file mode 100644 (file)
index 0000000..418b368
--- /dev/null
@@ -0,0 +1,71 @@
+#include "dev/power/g500.hh"
+
+#include "cpu/intr_control.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+G500::G500(const Params *p)
+    : Platform(p), system(p->system)
+{}
+
+void
+G500::postConsoleInt()
+{
+    warn_once("Don't know what interrupt to post for console.\n");
+    //panic("Need implementation\n");
+}
+
+void
+G500::clearConsoleInt()
+{
+    warn_once("Don't know what interrupt to clear for console.\n");
+    //panic("Need implementation\n");
+}
+
+void
+G500::postPciInt(int line)
+{
+    panic("Need implementation\n");
+}
+
+void
+G500::clearPciInt(int line)
+{
+    panic("Need implementation\n");
+}
+
+Addr
+G500::pciToDma(Addr pciAddr) const
+{
+    panic("Need implementation\n");
+    M5_DUMMY_RETURN
+}
+
+
+Addr
+G500::calcPciConfigAddr(int bus, int dev, int func)
+{
+    panic("Need implementation\n");
+    M5_DUMMY_RETURN
+}
+
+Addr
+G500::calcPciIOAddr(Addr addr)
+{
+    panic("Need implementation\n");
+    M5_DUMMY_RETURN
+}
+
+Addr
+G500::calcPciMemAddr(Addr addr)
+{
+    panic("Need implementation\n");
+    M5_DUMMY_RETURN
+}
+
+G500 *
+G500Params::create()
+{
+    return new G500(this);
+}
\ No newline at end of file
diff --git a/src/dev/power/g500.hh b/src/dev/power/g500.hh
new file mode 100644 (file)
index 0000000..bf2f741
--- /dev/null
@@ -0,0 +1,67 @@
+ /**
+ * @file
+ * Declaration of top level class for the Gem5-power9. This class just
+ * retains pointers to all its children so the children can communicate.
+ *
+ * Inspired from the SPARCH T1000 system.
+ */
+
+#ifndef __DEV_G500_HH__
+#define __DEV_G500_HH__
+
+#include "dev/platform.hh"
+#include "params/G500.hh"
+
+class IdeController;
+class System;
+
+class G500 : public Platform
+{
+    public:
+    /** Pointer to the system */
+    System *system;
+
+    public:
+      typedef G500Params Params;
+
+    G500(const Params *p);
+     /**
+     * Cause the cpu to post a serial interrupt to the CPU.
+     */
+    virtual void postConsoleInt();
+
+    /**
+     * Clear a posted CPU interrupt
+     */
+    virtual void clearConsoleInt();
+
+    /**
+     * Cause the chipset to post a cpi interrupt to the CPU.
+     */
+    virtual void postPciInt(int line);
+
+    /**
+     * Clear a posted PCI->CPU interrupt
+     */
+    virtual void clearPciInt(int line);
+
+
+    virtual Addr pciToDma(Addr pciAddr) const;
+
+    /**
+     * Calculate the configuration address given a bus/dev/func.
+     */
+    virtual Addr calcPciConfigAddr(int bus, int dev, int func);
+
+    /**
+     * Calculate the address for an IO location on the PCI bus.
+     */
+    virtual Addr calcPciIOAddr(Addr addr);
+
+    /**
+     * Calculate the address for a memory location on the PCI bus.
+     */
+    virtual Addr calcPciMemAddr(Addr addr);
+};
+
+#endif
index 0b6f07a919959c430812fb1ce38762e8bea58b1a..1ef4346eb5c0c6775505a2274da99069dd03f3d4 100644 (file)
@@ -109,6 +109,7 @@ Uart8250::read(PacketPtr pkt)
                     pkt->setRaw((uint8_t)0);
                     // A limited amount of these are ok.
                     DPRINTF(Uart, "empty read of RX register\n");
+                    printf("empty read of Rx register\n");
                 }
                 status &= ~RX_INT;
                 platform->clearConsoleInt();
@@ -128,7 +129,7 @@ Uart8250::read(PacketPtr pkt)
             break;
         case 0x2: // Intr Identification Register (IIR)
             DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
-
+            printf("IIR Read, status = %#x\n", (uint32_t)status);
             if (status & RX_INT) /* Rx data interrupt has a higher priority */
                 pkt->setRaw(IIR_RXID);
             else if (status & TX_INT) {
@@ -198,7 +199,7 @@ Uart8250::write(PacketPtr pkt)
         case 0x1:
             if (!(LCR & 0x80)) { // Intr Enable Register(IER)
                 IER = pkt->getRaw<uint8_t>();
-                if (UART_IER_THRI & IER)
+                if (UART_IER_THRI & IER & 0)
                 {
                     DPRINTF(Uart,
                             "IER: IER_THRI set, scheduling TX intrrupt\n");
index 43f54e64a853a878c596c088808f23433fef5f89..3607225c23b4913bf940fab571bef6d77a670e09 100644 (file)
@@ -326,8 +326,8 @@ class Request
         STICKY_PRIVATE_FLAGS = VALID_CONTEXT_ID
     };
 
-  private:
-
+  //private:
+  public:
     /**
      * The physical address of the request. Valid only if validPaddr
      * is set.
index 7744a41b99f644acbb4caab84d48f19f03d3e97f..ac5eb58fc5c35c044b30709e19cb2272cf7a913f 100644 (file)
@@ -27,6 +27,8 @@
 
 #ifndef __SYSTEMC_CORE_TIME_HH__
 #define __SYSTEMC_CORE_TIME_HH__
+#include "arch/power/vtophys.hh"
+#include "arch/power/radixwalk.hh"
 
 #include "base/types.hh"
 
@@ -39,5 +41,18 @@ extern double TimeUnitScale[];
 extern Tick TimeUnitFrequency[];
 
 } // namespace sc_gem5
+Addr
+PowerISA::vtophys(ThreadContext *tc, Addr addr)
+{
+   // fatal("vtophys: Unimplemented on POWER\n");
+    RadixWalk *rwalk = dynamic_cast<TLB *>(tc->getDTBPtr())->getWalker();
+    RequestPtr ptr = new Request();
+    ptr->setVirt(0,addr,8,
+        256,6,43384);
+    // Have to set a bogus request even though just the virtual addr
+    // is needed by the whole code path.
+    rwalk->start(tc,ptr,BaseTLB::Read);
+    return ptr->getPaddr();
+}
 
 #endif // __SYSTEMC_CORE_TIME_HH__