From 69e59e98ebd84779e2cc007084d9bafc31c8a8d9 Mon Sep 17 00:00:00 2001 From: Pratik Rajesh Sampat Date: Wed, 12 Jun 2019 11:42:39 +0530 Subject: [PATCH] arch-power: Add support for G500 platform 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 --- configs/common/FSConfig.py | 7 ++- src/arch/power/faults.hh | 8 ++- src/arch/power/radixwalk.hh | 2 +- src/arch/power/remote_gdb.cc | 35 ++++++------ src/arch/power/remote_gdb.hh | 16 ++++-- src/arch/power/tlb.cc | 103 ++++++++++++++++++++++++++++++++++- src/arch/power/tlb.hh | 2 +- src/dev/power/G500.py | 17 ++++++ src/dev/power/SConscript | 6 ++ src/dev/power/g500.cc | 71 ++++++++++++++++++++++++ src/dev/power/g500.hh | 67 +++++++++++++++++++++++ src/dev/serial/uart8250.cc | 5 +- src/mem/request.hh | 4 +- src/systemc/core/time.hh | 15 +++++ 14 files changed, 325 insertions(+), 33 deletions(-) create mode 100644 src/dev/power/G500.py create mode 100644 src/dev/power/SConscript create mode 100644 src/dev/power/g500.cc create mode 100644 src/dev/power/g500.hh diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index e892adb16..aa1da38e5 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -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') diff --git a/src/arch/power/faults.hh b/src/arch/power/faults.hh index 24cfea7ec..f73432696 100644 --- a/src/arch/power/faults.hh +++ b/src/arch/power/faults.hh @@ -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 diff --git a/src/arch/power/radixwalk.hh b/src/arch/power/radixwalk.hh index f0ba79ff6..6135d9bd0 100644 --- a/src/arch/power/radixwalk.hh +++ b/src/arch/power/radixwalk.hh @@ -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) diff --git a/src/arch/power/remote_gdb.cc b/src/arch/power/remote_gdb.cc index 661c4310e..30aab3f21 100644 --- a/src/arch/power/remote_gdb.cc +++ b/src/arch/power/remote_gdb.cc @@ -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* diff --git a/src/arch/power/remote_gdb.hh b/src/arch/power/remote_gdb.hh index 3bb726e52..534bad9f3 100644 --- a/src/arch/power/remote_gdb.hh +++ b/src/arch/power/remote_gdb.hh @@ -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); } diff --git a/src/arch/power/tlb.cc b/src/arch/power/tlb.cc index ae25e7d1c..91d080e32 100644 --- a/src/arch/power/tlb.cc +++ b/src/arch/power/tlb.cc @@ -53,8 +53,27 @@ 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(":") != 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; ireadPhysMem(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; ireadPhysMem((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; ireadPhysMem((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{ diff --git a/src/arch/power/tlb.hh b/src/arch/power/tlb.hh index 293e01e26..463843403 100644 --- a/src/arch/power/tlb.hh +++ b/src/arch/power/tlb.hh @@ -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 index 000000000..ae26f7e7a --- /dev/null +++ b/src/dev/power/G500.py @@ -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 index 000000000..329a03dc2 --- /dev/null +++ b/src/dev/power/SConscript @@ -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 index 000000000..418b368c0 --- /dev/null +++ b/src/dev/power/g500.cc @@ -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 index 000000000..bf2f7414d --- /dev/null +++ b/src/dev/power/g500.hh @@ -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 diff --git a/src/dev/serial/uart8250.cc b/src/dev/serial/uart8250.cc index 0b6f07a91..1ef4346eb 100644 --- a/src/dev/serial/uart8250.cc +++ b/src/dev/serial/uart8250.cc @@ -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(); - if (UART_IER_THRI & IER) + if (UART_IER_THRI & IER & 0) { DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); diff --git a/src/mem/request.hh b/src/mem/request.hh index 43f54e64a..3607225c2 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -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. diff --git a/src/systemc/core/time.hh b/src/systemc/core/time.hh index 7744a41b9..ac5eb58fc 100644 --- a/src/systemc/core/time.hh +++ b/src/systemc/core/time.hh @@ -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(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__ -- 2.30.2