#include "arch/x86/regs/misc.hh"
#include "arch/x86/x86_traits.hh"
#include "base/bitfield.hh"
+#include "base/logging.hh"
#include "base/output.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
{
GpuTLB::GpuTLB(const Params *p)
- : MemObject(p), configAddress(0), size(p->size),
- cleanupEvent(this, false, Event::Maximum_Pri), exitEvent(this)
+ : ClockedObject(p), configAddress(0), size(p->size),
+ cleanupEvent([this]{ cleanup(); }, name(), false,
+ Event::Maximum_Pri),
+ exitEvent([this]{ exitCallback(); }, name())
{
assoc = p->assoc;
assert(assoc <= size);
accessDistance = p->accessDistance;
clock = p->clk_domain->clockPeriod();
- tlb.assign(size, GpuTlbEntry());
+ tlb.assign(size, TlbEntry());
freeList.resize(numSets);
entryList.resize(numSets);
*/
setMask = numSets - 1;
- #if 0
- // GpuTLB doesn't yet support full system
- walker = p->walker;
- walker->setTLB(this);
- #endif
-
maxCoalescedReqs = p->maxOutstandingReqs;
// Do not allow maxCoalescedReqs to be more than the TLB associativity
assert(translationReturnEvent.empty());
}
- BaseSlavePort&
- GpuTLB::getSlavePort(const std::string &if_name, PortID idx)
+ Port &
+ GpuTLB::getPort(const std::string &if_name, PortID idx)
{
if (if_name == "slave") {
if (idx >= static_cast<PortID>(cpuSidePort.size())) {
- panic("TLBCoalescer::getSlavePort: unknown index %d\n", idx);
+ panic("TLBCoalescer::getPort: unknown index %d\n", idx);
}
return *cpuSidePort[idx];
- } else {
- panic("TLBCoalescer::getSlavePort: unknown port %s\n", if_name);
- }
- }
-
- BaseMasterPort&
- GpuTLB::getMasterPort(const std::string &if_name, PortID idx)
- {
- if (if_name == "master") {
+ } else if (if_name == "master") {
if (idx >= static_cast<PortID>(memSidePort.size())) {
- panic("TLBCoalescer::getMasterPort: unknown index %d\n", idx);
+ panic("TLBCoalescer::getPort: unknown index %d\n", idx);
}
hasMemSidePort = true;
return *memSidePort[idx];
} else {
- panic("TLBCoalescer::getMasterPort: unknown port %s\n", if_name);
+ panic("TLBCoalescer::getPort: unknown port %s\n", if_name);
}
}
- GpuTlbEntry*
- GpuTLB::insert(Addr vpn, GpuTlbEntry &entry)
+ TlbEntry*
+ GpuTLB::insert(Addr vpn, TlbEntry &entry)
{
- GpuTlbEntry *newEntry = nullptr;
+ TlbEntry *newEntry = nullptr;
/**
* vpn holds the virtual page address
return entry;
}
- GpuTlbEntry*
+ TlbEntry*
GpuTLB::lookup(Addr va, bool update_lru)
{
int set = (va >> TheISA::PageShift) & setMask;
for (int i = 0; i < numSets; ++i) {
while (!entryList[i].empty()) {
- GpuTlbEntry *entry = entryList[i].front();
+ TlbEntry *entry = entryList[i].front();
entryList[i].pop_front();
freeList[i].push_back(entry);
}
}
Fault
- GpuTLB::translateInt(RequestPtr req, ThreadContext *tc)
+ GpuTLB::translateInt(const RequestPtr &req, ThreadContext *tc)
{
DPRINTF(GPUTLB, "Addresses references internal memory.\n");
Addr vaddr = req->getVaddr();
//The index is multiplied by the size of a MiscReg so that
//any memory dependence calculations will not see these as
//overlapping.
- req->setPaddr(regNum * sizeof(MiscReg));
+ req->setPaddr(regNum * sizeof(RegVal));
return NoFault;
} else if (prefix == IntAddrPrefixIO) {
// TODO If CPL > IOPL or in virtual mode, check the I/O permission
if (IOPort == 0xCF8 && req->getSize() == 4) {
req->setFlags(Request::MMAPPED_IPR);
- req->setPaddr(MISCREG_PCI_CONFIG_ADDRESS * sizeof(MiscReg));
+ req->setPaddr(MISCREG_PCI_CONFIG_ADDRESS * sizeof(RegVal));
} else if ((IOPort & ~mask(2)) == 0xCFC) {
req->setFlags(Request::UNCACHEABLE);
* On a hit it will update the LRU stack.
*/
bool
- GpuTLB::tlbLookup(RequestPtr req, ThreadContext *tc, bool update_stats)
+ GpuTLB::tlbLookup(const RequestPtr &req,
+ ThreadContext *tc, bool update_stats)
{
bool tlb_hit = false;
#ifndef NDEBUG
if (m5Reg.paging) {
DPRINTF(GPUTLB, "Paging enabled.\n");
//update LRU stack on a hit
- GpuTlbEntry *entry = lookup(vaddr, true);
+ TlbEntry *entry = lookup(vaddr, true);
if (entry)
tlb_hit = true;
}
Fault
- GpuTLB::translate(RequestPtr req, ThreadContext *tc,
+ GpuTLB::translate(const RequestPtr &req, ThreadContext *tc,
Translation *translation, Mode mode,
bool &delayedResponse, bool timing, int &latency)
{
if (m5Reg.paging) {
DPRINTF(GPUTLB, "Paging enabled.\n");
// The vaddr already has the segment base applied.
- GpuTlbEntry *entry = lookup(vaddr);
+ TlbEntry *entry = lookup(vaddr);
localNumTLBAccesses++;
if (!entry) {
"at pc %#x.\n", vaddr, tc->instAddr());
Process *p = tc->getProcessPtr();
- GpuTlbEntry newEntry;
- bool success = p->pTable->lookup(vaddr, newEntry);
+ const EmulationPageTable::Entry *pte =
+ p->pTable->lookup(vaddr);
- if (!success && mode != BaseTLB::Execute) {
+ if (!pte && mode != BaseTLB::Execute) {
// penalize a "page fault" more
- if (timing) {
+ if (timing)
latency += missLatency2;
- }
if (p->fixupStackFault(vaddr))
- success = p->pTable->lookup(vaddr, newEntry);
+ pte = p->pTable->lookup(vaddr);
}
- if (!success) {
+ if (!pte) {
return std::make_shared<PageFault>(vaddr, true,
mode, true,
false);
} else {
- newEntry.valid = success;
Addr alignedVaddr = p->pTable->pageAlign(vaddr);
DPRINTF(GPUTLB, "Mapping %#x to %#x\n",
- alignedVaddr, newEntry.pageStart());
+ alignedVaddr, pte->paddr);
- entry = insert(alignedVaddr, newEntry);
+ TlbEntry gpuEntry(p->pid(), alignedVaddr,
+ pte->paddr, false, false);
+ entry = insert(alignedVaddr, gpuEntry);
}
DPRINTF(GPUTLB, "Miss was serviced.\n");
};
Fault
- GpuTLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode,
- int &latency)
+ GpuTLB::translateAtomic(const RequestPtr &req, ThreadContext *tc,
+ Mode mode, int &latency)
{
bool delayedResponse;
}
void
- GpuTLB::translateTiming(RequestPtr req, ThreadContext *tc,
+ GpuTLB::translateTiming(const RequestPtr &req, ThreadContext *tc,
Translation *translation, Mode mode, int &latency)
{
bool delayedResponse;
void
GpuTLB::regStats()
{
- MemObject::regStats();
+ ClockedObject::regStats();
localNumTLBAccesses
.name(name() + ".local_TLB_accesses")
}
tlbOutcome lookup_outcome = TLB_MISS;
- RequestPtr tmp_req = pkt->req;
+ const RequestPtr &tmp_req = pkt->req;
// Access the TLB and figure out if it's a hit or a miss.
bool success = tlbLookup(tmp_req, tmp_tc, update_stats);
if (success) {
lookup_outcome = TLB_HIT;
// Put the entry in SenderState
- GpuTlbEntry *entry = lookup(tmp_req->getVaddr(), false);
+ TlbEntry *entry = lookup(tmp_req->getVaddr(), false);
assert(entry);
+ auto p = sender_state->tc->getProcessPtr();
sender_state->tlbEntry =
- new GpuTlbEntry(0, entry->vaddr, entry->paddr, entry->valid);
+ new TlbEntry(p->pid(), entry->vaddr, entry->paddr,
+ false, false);
if (update_stats) {
// the reqCnt has an entry per level, so its size tells us
*/
void
GpuTLB::pagingProtectionChecks(ThreadContext *tc, PacketPtr pkt,
- GpuTlbEntry * tlb_entry, Mode mode)
+ TlbEntry * tlb_entry, Mode mode)
{
HandyM5Reg m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
uint32_t flags = pkt->req->getFlags();
if ((inUser && !tlb_entry->user) ||
(mode == BaseTLB::Write && badWrite)) {
- // The page must have been present to get into the TLB in
- // the first place. We'll assume the reserved bits are
- // fine even though we're not checking them.
- assert(false);
+ // The page must have been present to get into the TLB in
+ // the first place. We'll assume the reserved bits are
+ // fine even though we're not checking them.
+ panic("Page fault detected");
}
if (storeCheck && badWrite) {
- // This would fault if this were a write, so return a page
- // fault that reflects that happening.
- assert(false);
+ // This would fault if this were a write, so return a page
+ // fault that reflects that happening.
+ panic("Page fault detected");
}
}
ThreadContext *tc = sender_state->tc;
Mode mode = sender_state->tlbMode;
- GpuTlbEntry *local_entry, *new_entry;
+ TlbEntry *local_entry, *new_entry;
if (tlb_outcome == TLB_HIT) {
DPRINTF(GPUTLB, "Translation Done - TLB Hit for addr %#x\n", vaddr);
safe_cast<TranslationState*>(pkt->senderState);
Process *p = sender_state->tc->getProcessPtr();
- TlbEntry newEntry;
Addr vaddr = pkt->req->getVaddr();
#ifndef NDEBUG
Addr alignedVaddr = p->pTable->pageAlign(vaddr);
assert(alignedVaddr == virtPageAddr);
#endif
- bool success;
- success = p->pTable->lookup(vaddr, newEntry);
- if (!success && sender_state->tlbMode != BaseTLB::Execute) {
- if (p->fixupStackFault(vaddr)) {
- success = p->pTable->lookup(vaddr, newEntry);
- }
+ const EmulationPageTable::Entry *pte = p->pTable->lookup(vaddr);
+ if (!pte && sender_state->tlbMode != BaseTLB::Execute &&
+ p->fixupStackFault(vaddr)) {
+ pte = p->pTable->lookup(vaddr);
}
- DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
- newEntry.pageStart());
+ if (pte) {
+ DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
+ pte->paddr);
- sender_state->tlbEntry =
- new GpuTlbEntry(0, newEntry.vaddr, newEntry.paddr, success);
+ sender_state->tlbEntry =
+ new TlbEntry(p->pid(), virtPageAddr, pte->paddr, false,
+ false);
+ } else {
+ sender_state->tlbEntry = nullptr;
+ }
handleTranslationReturn(virtPageAddr, TLB_MISS, pkt);
} else if (outcome == MISS_RETURN) {
*/
handleTranslationReturn(virtPageAddr, TLB_MISS, pkt);
} else {
- assert(false);
+ panic("Unexpected TLB outcome %d", outcome);
}
}
Mode mode = sender_state->tlbMode;
Addr vaddr = pkt->req->getVaddr();
- GpuTlbEntry *local_entry, *new_entry;
+ TlbEntry *local_entry, *new_entry;
if (tlb_outcome == TLB_HIT) {
DPRINTF(GPUTLB, "Functional Translation Done - TLB hit for addr "
"while paddr was %#x.\n", local_entry->vaddr,
local_entry->paddr);
- // Do paging checks if it's a normal functional access. If it's for a
- // prefetch, then sometimes you can try to prefetch something that won't
- // pass protection. We don't actually want to fault becuase there is no
- // demand access to deem this a violation. Just put it in the TLB and
- // it will fault if indeed a future demand access touches it in
- // violation.
- if (!sender_state->prefetch && sender_state->tlbEntry->valid)
+ /**
+ * Do paging checks if it's a normal functional access. If it's for a
+ * prefetch, then sometimes you can try to prefetch something that
+ * won't pass protection. We don't actually want to fault becuase there
+ * is no demand access to deem this a violation. Just put it in the
+ * TLB and it will fault if indeed a future demand access touches it in
+ * violation.
+ *
+ * This feature could be used to explore security issues around
+ * speculative memory accesses.
+ */
+ if (!sender_state->prefetch && sender_state->tlbEntry)
pagingProtectionChecks(tc, pkt, local_entry, mode);
int page_size = local_entry->size();
virt_page_addr);
Process *p = tc->getProcessPtr();
- TlbEntry newEntry;
Addr vaddr = pkt->req->getVaddr();
#ifndef NDEBUG
assert(alignedVaddr == virt_page_addr);
#endif
- bool success = p->pTable->lookup(vaddr, newEntry);
- if (!success && sender_state->tlbMode != BaseTLB::Execute) {
- if (p->fixupStackFault(vaddr))
- success = p->pTable->lookup(vaddr, newEntry);
+ const EmulationPageTable::Entry *pte =
+ p->pTable->lookup(vaddr);
+ if (!pte && sender_state->tlbMode != BaseTLB::Execute &&
+ p->fixupStackFault(vaddr)) {
+ pte = p->pTable->lookup(vaddr);
}
if (!sender_state->prefetch) {
// no PageFaults are permitted after
// the second page table lookup
- assert(success);
+ assert(pte);
DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
- newEntry.pageStart());
+ pte->paddr);
- sender_state->tlbEntry = new GpuTlbEntry(0, newEntry.vaddr,
- newEntry.paddr,
- success);
+ sender_state->tlbEntry =
+ new TlbEntry(p->pid(), virt_page_addr,
+ pte->paddr, false, false);
} else {
// If this was a prefetch, then do the normal thing if it
// was a successful translation. Otherwise, send an empty
// TLB entry back so that it can be figured out as empty and
// handled accordingly.
- if (success) {
+ if (pte) {
DPRINTF(GPUTLB, "Mapping %#x to %#x\n", alignedVaddr,
- newEntry.pageStart());
+ pte->paddr);
- sender_state->tlbEntry = new GpuTlbEntry(0,
- newEntry.vaddr,
- newEntry.paddr,
- success);
+ sender_state->tlbEntry =
+ new TlbEntry(p->pid(), virt_page_addr,
+ pte->paddr, false, false);
} else {
DPRINTF(GPUPrefetch, "Prefetch failed %#x\n",
alignedVaddr);
- sender_state->tlbEntry = new GpuTlbEntry();
+ sender_state->tlbEntry = nullptr;
return;
}
DPRINTF(GPUPrefetch, "Functional Hit for vaddr %#x\n",
tlb->lookup(pkt->req->getVaddr()));
- GpuTlbEntry *entry = tlb->lookup(pkt->req->getVaddr(),
+ TlbEntry *entry = tlb->lookup(pkt->req->getVaddr(),
update_stats);
assert(entry);
+ auto p = sender_state->tc->getProcessPtr();
sender_state->tlbEntry =
- new GpuTlbEntry(0, entry->vaddr, entry->paddr, entry->valid);
+ new TlbEntry(p->pid(), entry->vaddr, entry->paddr,
+ false, false);
}
// This is the function that would populate pkt->req with the paddr of
// the translation. But if no translation happens (i.e Prefetch fails)
{
// The CPUSidePort never sends anything but replies. No retries
// expected.
- assert(false);
+ panic("recvReqRetry called");
}
AddrRangeList
{
// No retries should reach the TLB. The retries
// should only reach the TLBCoalescer.
- assert(false);
+ panic("recvReqRetry called");
}
void