From bd367d4825e26ab3f8e01f3b4bdb914bb0ef756a Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Sun, 18 Feb 2007 19:57:46 -0500 Subject: [PATCH] implement vtophys and 32bit gdb support src/arch/alpha/vtophys.cc: src/arch/alpha/vtophys.hh: src/arch/sparc/arguments.hh: move Copy* to vport since it's generic for all the ISAs src/arch/sparc/isa_traits.hh: the Solaris kernel sets up a virtual-> real mapping for all memory starting at SegKPMBase src/arch/sparc/pagetable.hh: add a class for getting bits out of the TteTag src/arch/sparc/remote_gdb.cc: add 32bit support kinda.... If its 32 bit src/arch/sparc/remote_gdb.hh: Add 32bit register offsets too. src/arch/sparc/tlb.cc: cleanup generation of tsb pointers src/arch/sparc/tlb.hh: add function to return tsb pointers for an address make lookup public so vtophys can use it src/arch/sparc/vtophys.cc: src/arch/sparc/vtophys.hh: write vtophys for sparc src/base/bitfield.hh: return a mask of bits first->last src/mem/vport.cc: src/mem/vport.hh: move Copy* here since it's ISA generic --HG-- extra : convert_revision : c42c331e396c0d51a2789029d8e232fe66995d0f --- src/arch/alpha/vtophys.cc | 51 ------------ src/arch/alpha/vtophys.hh | 5 -- src/arch/sparc/arguments.hh | 2 +- src/arch/sparc/isa_traits.hh | 5 ++ src/arch/sparc/pagetable.hh | 21 ++++- src/arch/sparc/remote_gdb.cc | 44 ++++++---- src/arch/sparc/remote_gdb.hh | 4 +- src/arch/sparc/tlb.cc | 153 +++++++++++++++++++++-------------- src/arch/sparc/tlb.hh | 19 ++++- src/arch/sparc/vtophys.cc | 94 +++++++++++++++------ src/arch/sparc/vtophys.hh | 5 -- src/base/bitfield.hh | 7 ++ src/mem/vport.cc | 51 ++++++++++++ src/mem/vport.hh | 7 ++ 14 files changed, 300 insertions(+), 168 deletions(-) diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc index fd8f781e4..1a3147bcc 100644 --- a/src/arch/alpha/vtophys.cc +++ b/src/arch/alpha/vtophys.cc @@ -113,54 +113,3 @@ AlphaISA::vtophys(ThreadContext *tc, Addr addr) return paddr; } - -void -AlphaISA::CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen) -{ - uint8_t *dst = (uint8_t *)dest; - VirtualPort *vp = tc->getVirtPort(tc); - - vp->readBlob(src, dst, cplen); - - tc->delVirtPort(vp); - -} - -void -AlphaISA::CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen) -{ - uint8_t *src = (uint8_t *)source; - VirtualPort *vp = tc->getVirtPort(tc); - - vp->writeBlob(dest, src, cplen); - - tc->delVirtPort(vp); -} - -void -AlphaISA::CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen) -{ - int len = 0; - char *start = dst; - VirtualPort *vp = tc->getVirtPort(tc); - - do { - vp->readBlob(vaddr++, (uint8_t*)dst++, 1); - } while (len < maxlen && start[len++] != 0 ); - - tc->delVirtPort(vp); - dst[len] = 0; -} - -void -AlphaISA::CopyStringIn(ThreadContext *tc, char *src, Addr vaddr) -{ - VirtualPort *vp = tc->getVirtPort(tc); - for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done(); - gen.next()) - { - vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); - src += gen.size(); - } - tc->delVirtPort(vp); -} diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh index 32b999c37..bd2ee8468 100644 --- a/src/arch/alpha/vtophys.hh +++ b/src/arch/alpha/vtophys.hh @@ -47,11 +47,6 @@ namespace AlphaISA { Addr vtophys(Addr vaddr); Addr vtophys(ThreadContext *tc, Addr vaddr); - void CopyOut(ThreadContext *tc, void *dst, Addr src, size_t len); - void CopyIn(ThreadContext *tc, Addr dst, void *src, size_t len); - void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen); - void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr); - }; #endif // __ARCH_ALPHA_VTOPHYS_H__ diff --git a/src/arch/sparc/arguments.hh b/src/arch/sparc/arguments.hh index 8f925dd25..5596f7408 100644 --- a/src/arch/sparc/arguments.hh +++ b/src/arch/sparc/arguments.hh @@ -33,9 +33,9 @@ #include -#include "arch/sparc/vtophys.hh" #include "base/refcnt.hh" #include "sim/host.hh" +#include "mem/vport.hh" class ThreadContext; diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh index 64ae6abd8..1fbdd160d 100644 --- a/src/arch/sparc/isa_traits.hh +++ b/src/arch/sparc/isa_traits.hh @@ -87,6 +87,11 @@ namespace SparcISA const int LogVMPageSize = 13; const int VMPageSize = (1 << LogVMPageSize); + // real address virtual mapping + // sort of like alpha super page, but less frequently used + const Addr SegKPMEnd = ULL(0xfffffffc00000000); + const Addr SegKPMBase = ULL(0xfffffac000000000); + //Why does both the previous set of constants and this one exist? const int PageShift = 13; const int PageBytes = 1ULL << PageShift; diff --git a/src/arch/sparc/pagetable.hh b/src/arch/sparc/pagetable.hh index fc01e82da..980225052 100644 --- a/src/arch/sparc/pagetable.hh +++ b/src/arch/sparc/pagetable.hh @@ -45,6 +45,22 @@ struct VAddr VAddr(Addr a) { panic("not implemented yet."); } }; +class TteTag +{ + private: + uint64_t entry; + bool populated; + + public: + TteTag() : entry(0), populated(false) {} + TteTag(uint64_t e) : entry(e), populated(true) {} + const TteTag &operator=(uint64_t e) { populated = true; + entry = e; return *this; } + bool valid() const {assert(populated); return !bits(entry,62,62); } + Addr va() const {assert(populated); return bits(entry,41,0); } +}; + + class PageTableEntry { public: @@ -110,13 +126,14 @@ class PageTableEntry entry4u = e; return *this; } const PageTableEntry &operator=(const PageTableEntry &e) - { populated = true; entry4u = e.entry4u; return *this; } + { populated = true; entry4u = e.entry4u; type = e.type; return *this; } bool valid() const { return bits(entry4u,63,63) && populated; } uint8_t _size() const { assert(populated); return bits(entry4u, 62,61) | bits(entry4u, 48,48) << 2; } Addr size() const { assert(_size() < 6); return pageSizes[_size()]; } + Addr sizeMask() const { assert(_size() < 6); return pageSizes[_size()]-1;} bool ie() const { return bits(entry4u, 59,59); } Addr pfn() const { assert(populated); return bits(entry4u,39,13); } Addr paddr() const { assert(populated); return mbits(entry4u, 39,13);} @@ -127,6 +144,8 @@ class PageTableEntry bool writable() const { assert(populated); return bits(entry4u,1,1); } bool nofault() const { assert(populated); return bits(entry4u,60,60); } bool sideffect() const { assert(populated); return bits(entry4u,3,3); } + Addr paddrMask() const { assert(populated); + return mbits(entry4u, 39,13) & ~sizeMask(); } }; struct TlbRange { diff --git a/src/arch/sparc/remote_gdb.cc b/src/arch/sparc/remote_gdb.cc index 2221576a3..e2ea7a84d 100644 --- a/src/arch/sparc/remote_gdb.cc +++ b/src/arch/sparc/remote_gdb.cc @@ -152,7 +152,9 @@ RemoteGDB::acc(Addr va, size_t len) //@Todo In NetBSD, this function checks if all addresses //from va to va + len have valid page mape entries. Not //sure how this will work for other OSes or in general. - return true; + if (va) + return true; + return false; } /////////////////////////////////////////////////////////// @@ -166,23 +168,33 @@ RemoteGDB::getregs() memset(gdbregs.regs, 0, gdbregs.size); if (context->readMiscRegWithEffect(MISCREG_PSTATE) & - PSTATE::am) - panic("In 32bit mode\n"); + PSTATE::am) { + uint32_t *regs; + regs = (uint32_t*)gdbregs.regs; + regs[Reg32Pc] = htobe((uint32_t)context->readPC()); + regs[Reg32Npc] = htobe((uint32_t)context->readNextPC()); + for(int x = RegG0; x <= RegI0 + 7; x++) + regs[x] = htobe((uint32_t)context->readIntReg(x - RegG0)); - gdbregs.regs[RegPc] = htobe(context->readPC()); - gdbregs.regs[RegNpc] = htobe(context->readNextPC()); - for(int x = RegG0; x <= RegI0 + 7; x++) - gdbregs.regs[x] = htobe(context->readIntReg(x - RegG0)); - - gdbregs.regs[RegFsr] = htobe(context->readMiscRegWithEffect(MISCREG_FSR)); - gdbregs.regs[RegFprs] = htobe(context->readMiscRegWithEffect(MISCREG_FPRS)); - gdbregs.regs[RegY] = htobe(context->readIntReg(NumIntArchRegs + 1)); - gdbregs.regs[RegState] = htobe( - context->readMiscRegWithEffect(MISCREG_CWP) | - context->readMiscRegWithEffect(MISCREG_PSTATE) << 8 | - context->readMiscRegWithEffect(MISCREG_ASI) << 24 | - context->readIntReg(NumIntArchRegs + 2) << 32); + regs[Reg32Y] = htobe((uint32_t)context->readIntReg(NumIntArchRegs + 1)); + regs[Reg32Psr] = htobe((uint32_t)context->readMiscRegWithEffect(MISCREG_PSTATE)); + regs[Reg32Fsr] = htobe((uint32_t)context->readMiscRegWithEffect(MISCREG_FSR)); + regs[Reg32Csr] = htobe((uint32_t)context->readIntReg(NumIntArchRegs + 2)); + } else { + gdbregs.regs[RegPc] = htobe(context->readPC()); + gdbregs.regs[RegNpc] = htobe(context->readNextPC()); + for(int x = RegG0; x <= RegI0 + 7; x++) + gdbregs.regs[x] = htobe(context->readIntReg(x - RegG0)); + gdbregs.regs[RegFsr] = htobe(context->readMiscRegWithEffect(MISCREG_FSR)); + gdbregs.regs[RegFprs] = htobe(context->readMiscRegWithEffect(MISCREG_FPRS)); + gdbregs.regs[RegY] = htobe(context->readIntReg(NumIntArchRegs + 1)); + gdbregs.regs[RegState] = htobe( + context->readMiscRegWithEffect(MISCREG_CWP) | + context->readMiscRegWithEffect(MISCREG_PSTATE) << 8 | + context->readMiscRegWithEffect(MISCREG_ASI) << 24 | + context->readIntReg(NumIntArchRegs + 2) << 32); + } DPRINTF(GDBRead, "PC=%#x\n", gdbregs.regs[RegPc]); diff --git a/src/arch/sparc/remote_gdb.hh b/src/arch/sparc/remote_gdb.hh index 17ad7a8e6..b97961a34 100644 --- a/src/arch/sparc/remote_gdb.hh +++ b/src/arch/sparc/remote_gdb.hh @@ -53,7 +53,9 @@ namespace SparcISA RegF0 = 32, RegPc = 64, RegNpc, RegState, RegFsr, RegFprs, RegY, /*RegState contains data in same format as tstate */ - NumGDBRegs + Reg32Y = 64, Reg32Psr = 65, Reg32Tbr = 66, Reg32Pc = 67, + Reg32Npc = 68, Reg32Fsr = 69, Reg32Csr = 70, + NumGDBRegs = RegY }; public: diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc index 293f667d6..82b1ed175 100644 --- a/src/arch/sparc/tlb.cc +++ b/src/arch/sparc/tlb.cc @@ -204,7 +204,8 @@ insertAllLocked: TlbEntry* -TLB::lookup(Addr va, int partition_id, bool real, int context_id) +TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool + update_used) { MapIter i; TlbRange tr; @@ -230,7 +231,10 @@ TLB::lookup(Addr va, int partition_id, bool real, int context_id) t = i->second; DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(), t->pte.size()); - if (!t->used) { + + // Update the used bits only if this is a real access (not a fake one from + // virttophys() + if (!t->used && update_used) { t->used = true; usedEntries++; if (usedEntries == size) { @@ -797,13 +801,11 @@ handleQueueRegAccess: handleSparcErrorRegAccess: if (!hpriv) { - if (priv) { - writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + if (priv) return new DataAccessException; - } else { - writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); + else return new PrivilegedAction; - } } goto regAccessOk; @@ -821,8 +823,7 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) { Addr va = pkt->getAddr(); ASI asi = (ASI)pkt->req->getAsi(); - uint64_t temp, data; - uint64_t tsbtemp, cnftemp; + uint64_t temp; DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n", (uint32_t)pkt->req->getAsi(), pkt->getAddr()); @@ -942,64 +943,36 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) } break; case ASI_DMMU_TSB_PS0_PTR_REG: - temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); - if (bits(temp,12,0) == 0) { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG); - } else { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG); - } - data = mbits(tsbtemp,63,13); - data |= temp >> (9 + bits(cnftemp,2,0) * 3) & - mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); - pkt->set(data); + pkt->set(MakeTsbPtr(Ps0, + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG))); break; case ASI_DMMU_TSB_PS1_PTR_REG: - temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); - if (bits(temp,12,0) == 0) { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG); - } else { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG); - } - data = mbits(tsbtemp,63,13); - if (bits(tsbtemp,12,12)) - data |= ULL(1) << (13+bits(tsbtemp,3,0)); - data |= temp >> (9 + bits(cnftemp,10,8) * 3) & - mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); - pkt->set(data); + pkt->set(MakeTsbPtr(Ps1, + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG))); break; case ASI_IMMU_TSB_PS0_PTR_REG: - temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); - if (bits(temp,12,0) == 0) { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG); - } else { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG); - } - data = mbits(tsbtemp,63,13); - data |= temp >> (9 + bits(cnftemp,2,0) * 3) & - mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); - pkt->set(data); + pkt->set(MakeTsbPtr(Ps0, + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG))); break; case ASI_IMMU_TSB_PS1_PTR_REG: - temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); - if (bits(temp,12,0) == 0) { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG); - } else { - tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1); - cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG); - } - data = mbits(tsbtemp,63,13); - if (bits(tsbtemp,12,12)) - data |= ULL(1) << (13+bits(tsbtemp,3,0)); - data |= temp >> (9 + bits(cnftemp,10,8) * 3) & - mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); - pkt->set(data); + pkt->set(MakeTsbPtr(Ps1, + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG))); break; default: @@ -1244,6 +1217,64 @@ doMmuWriteError: return tc->getCpuPtr()->cycles(1); } +void +DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs) +{ + uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0); + ptrs[0] = MakeTsbPtr(Ps0, tag_access, + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG)); + ptrs[1] = MakeTsbPtr(Ps1, tag_access, + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG)); + ptrs[2] = MakeTsbPtr(Ps0, tag_access, + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG)); + ptrs[3] = MakeTsbPtr(Ps1, tag_access, + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1), + tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG)); +} + + + + + +uint64_t +DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb, + uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config) +{ + uint64_t tsb; + uint64_t config; + + if (bits(tag_access, 12,0) == 0) { + tsb = c0_tsb; + config = c0_config; + } else { + tsb = cX_tsb; + config = cX_config; + } + + uint64_t ptr = mbits(tsb,63,13); + bool split = bits(tsb,12,12); + int tsb_size = bits(tsb,3,0); + int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8); + + if (ps == Ps1 && split) + ptr |= ULL(1) << (13 + tsb_size); + ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4); + + return ptr; +} + + void TLB::serialize(std::ostream &os) { diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh index 34e5f5feb..b5f02c62e 100644 --- a/src/arch/sparc/tlb.hh +++ b/src/arch/sparc/tlb.hh @@ -78,17 +78,25 @@ class TLB : public SimObject Nucleus = 2 }; - + enum TsbPageSize { + Ps0, + Ps1 + }; + public: /** lookup an entry in the TLB based on the partition id, and real bit if * real is true or the partition id, and context id if real is false. * @param va the virtual address not shifted (e.g. bottom 13 bits are 0) * @param paritition_id partition this entry is for * @param real is this a real->phys or virt->phys translation * @param context_id if this is virt->phys what context + * @param update_used should ew update the used bits in the entries on not + * useful if we are trying to do a va->pa without mucking with any state for + * a debug read for example. * @return A pointer to a tlb entry */ - TlbEntry *lookup(Addr va, int partition_id, bool real, int context_id = 0); - + TlbEntry *lookup(Addr va, int partition_id, bool real, int context_id = 0, + bool update_used = true); + protected: /** Insert a PTE into the TLB. */ void insert(Addr vpn, int partition_id, int context_id, bool real, const PageTableEntry& PTE, int entry = -1); @@ -163,12 +171,17 @@ class DTB : public TLB Fault translate(RequestPtr &req, ThreadContext *tc, bool write); Tick doMmuRegRead(ThreadContext *tc, Packet *pkt); Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt); + void GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs); private: void writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct, bool se, FaultTypes ft, int asi); void writeTagAccess(ThreadContext *tc, Addr va, int context); + uint64_t MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb, + uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config); + + TlbEntry *cacheEntry[2]; ASI cacheAsi[2]; }; diff --git a/src/arch/sparc/vtophys.cc b/src/arch/sparc/vtophys.cc index 429126b70..cb545185a 100644 --- a/src/arch/sparc/vtophys.cc +++ b/src/arch/sparc/vtophys.cc @@ -25,14 +25,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Authors: Nathan Binkert - * Steve Reinhardt - * Ali Saidi + * Authors: Ali Saidi */ #include #include "arch/sparc/vtophys.hh" +#include "arch/sparc/tlb.hh" +#include "base/compiler.hh" #include "base/chunk_generator.hh" #include "base/trace.hh" #include "cpu/thread_context.hh" @@ -42,37 +42,83 @@ using namespace std; namespace SparcISA { - PageTableEntry kernel_pte_lookup(FunctionalPort *mem, - Addr ptbr, VAddr vaddr) - { - PageTableEntry pte(4); - return pte; - } - Addr vtophys(Addr vaddr) { - return vaddr; + // In SPARC it's almost always impossible to turn a VA->PA w/o a context + // The only times we can kinda do it are if we have a SegKPM mapping + // and can find the real address in the tlb or we have a physical + // adddress already (beacuse we are looking at the hypervisor) + // Either case is rare, so we'll just panic. + + panic("vtophys() without context on SPARC largly worthless\n"); + M5_DUMMY_RETURN } Addr vtophys(ThreadContext *tc, Addr addr) { - return addr; - } + // Here we have many options and are really implementing something like + // a fill handler to find the address since there isn't a multilevel + // table for us to walk around. + // + // 1. We are currently hyperpriv, return the address unmodified + // 2. The mmu is off return(ra->pa) + // 3. We are currently priv, use ctx0* tsbs to find the page + // 4. We are not priv, use ctxN0* tsbs to find the page + // For all accesses we check the tlbs first since it's possible that + // long standing pages (e.g. locked kernel mappings) won't be in the tsb + uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA); + bool hpriv = bits(tlbdata,0,0); + //bool priv = bits(tlbdata,2,2); + bool addr_mask = bits(tlbdata,3,3); + bool data_real = !bits(tlbdata,5,5); + bool inst_real = !bits(tlbdata,4,4); + bool ctx_zero = bits(tlbdata,18,16) > 0; + int part_id = bits(tlbdata,15,8); + int pri_context = bits(tlbdata,47,32); + //int sec_context = bits(tlbdata,63,48); - void CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen) - { - } + FunctionalPort *mem = tc->getPhysPort(); + ITB* itb = tc->getITBPtr(); + DTB* dtb = tc->getDTBPtr(); + TlbEntry* tbe; + PageTableEntry pte; + Addr tsbs[4]; + Addr va_tag; + TteTag ttetag; - void CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen) - { - } + if (hpriv) + return addr; - void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen) - { - } + if (addr_mask) + addr = addr & VAddrAMask; - void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr) - { + tbe = dtb->lookup(addr, part_id, data_real, ctx_zero ? 0 : pri_context , false); + if (tbe) goto foundtbe; + + tbe = itb->lookup(addr, part_id, inst_real, ctx_zero ? 0 : pri_context, false); + if (tbe) goto foundtbe; + + // We didn't find it in the tlbs, so lets look at the TSBs + dtb->GetTsbPtr(tc, addr, ctx_zero ? 0 : pri_context, tsbs); + va_tag = bits(addr, 63, 22); + for (int x = 0; x < 4; x++) { + ttetag = betoh(mem->read(tsbs[x])); + if (ttetag.valid() && ttetag.va() == va_tag) { + pte.populate(betoh(mem->read(tsbs[x]) + sizeof(uint64_t)), + PageTableEntry::sun4v); // I think it's sun4v at least! + DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TTE\n", addr, + pte.paddrMask() | addr & pte.sizeMask()); + goto foundpte; + } + } + panic("couldn't translate %#x\n", addr); + +foundtbe: + pte = tbe->pte; + DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TLB\n", addr, + pte.paddrMask() | addr & pte.sizeMask()); +foundpte: + return pte.paddrMask() | addr & pte.sizeMask(); } } diff --git a/src/arch/sparc/vtophys.hh b/src/arch/sparc/vtophys.hh index 66679a565..f55967b53 100644 --- a/src/arch/sparc/vtophys.hh +++ b/src/arch/sparc/vtophys.hh @@ -46,11 +46,6 @@ kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, SparcISA::VAddr vaddr); Addr vtophys(Addr vaddr); Addr vtophys(ThreadContext *tc, Addr vaddr); -void CopyOut(ThreadContext *tc, void *dst, Addr src, size_t len); -void CopyIn(ThreadContext *tc, Addr dst, void *src, size_t len); -void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen); -void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr); - }; #endif // __ARCH_SPARC_VTOPHYS_H__ diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh index 1fc0bad5d..0f1233677 100644 --- a/src/base/bitfield.hh +++ b/src/base/bitfield.hh @@ -44,6 +44,7 @@ mask(int nbits) } + /** * Extract the bitfield from position 'first' to 'last' (inclusive) * from 'val' and right justify it. MSB is numbered 63, LSB is 0. @@ -69,6 +70,12 @@ mbits(T val, int first, int last) return val & (mask(first+1) & ~mask(last)); } +inline uint64_t +mask(int first, int last) +{ + return mbits((uint64_t)-1LL, first, last); +} + /** * Sign-extend an N-bit value to 64 bits. */ diff --git a/src/mem/vport.cc b/src/mem/vport.cc index 8030c5a15..6cc4d9ca9 100644 --- a/src/mem/vport.cc +++ b/src/mem/vport.cc @@ -34,6 +34,7 @@ */ #include "base/chunk_generator.hh" +#include "cpu/thread_context.hh" #include "mem/vport.hh" void @@ -70,3 +71,53 @@ VirtualPort::writeBlob(Addr addr, uint8_t *p, int size) } } +void +CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen) +{ + uint8_t *dst = (uint8_t *)dest; + VirtualPort *vp = tc->getVirtPort(tc); + + vp->readBlob(src, dst, cplen); + + tc->delVirtPort(vp); + +} + +void +CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen) +{ + uint8_t *src = (uint8_t *)source; + VirtualPort *vp = tc->getVirtPort(tc); + + vp->writeBlob(dest, src, cplen); + + tc->delVirtPort(vp); +} + +void +CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen) +{ + int len = 0; + char *start = dst; + VirtualPort *vp = tc->getVirtPort(tc); + + do { + vp->readBlob(vaddr++, (uint8_t*)dst++, 1); + } while (len < maxlen && start[len++] != 0 ); + + tc->delVirtPort(vp); + dst[len] = 0; +} + +void +CopyStringIn(ThreadContext *tc, char *src, Addr vaddr) +{ + VirtualPort *vp = tc->getVirtPort(tc); + for (ChunkGenerator gen(vaddr, strlen(src), TheISA::PageBytes); !gen.done(); + gen.next()) + { + vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size()); + src += gen.size(); + } + tc->delVirtPort(vp); +} diff --git a/src/mem/vport.hh b/src/mem/vport.hh index c83836258..a8ceaa9fc 100644 --- a/src/mem/vport.hh +++ b/src/mem/vport.hh @@ -49,6 +49,7 @@ * simple address masking operation (such as alpha super page accesses). */ + class VirtualPort : public FunctionalPort { private: @@ -75,5 +76,11 @@ class VirtualPort : public FunctionalPort virtual void writeBlob(Addr addr, uint8_t *p, int size); }; + +void CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen); +void CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen); +void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen); +void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr); + #endif //__MEM_VPORT_HH__