49#include "debug/TLB.hh"
50#include "debug/TLBVerbose.hh"
52#include "params/RiscvTLB.hh"
60using namespace RiscvISA;
70 return (
static_cast<Addr>(
asid) << 48) | vpn;
74 BaseTLB(
p), size(
p.size),
tlb(size),
75 lruSeq(0), stats(this), pma(
p.pma_checker),
78 for (
size_t x = 0;
x < size;
x++) {
79 tlb[
x].trieHandle = NULL;
80 freeList.push_back(&
tlb[
x]);
100 for (
size_t i = 1;
i < size;
i++) {
101 if (
tlb[
i].lruSeq <
tlb[lru].lruSeq)
115 entry->
lruSeq = nextSeq();
117 if (
mode == BaseMMU::Write)
118 stats.writeAccesses++;
120 stats.readAccesses++;
123 if (
mode == BaseMMU::Write)
129 if (
mode == BaseMMU::Write)
135 DPRINTF(TLBVerbose,
"lookup(vpn=%#x, asid=%#x): %s ppn %#x\n",
136 vpn,
asid, entry ?
"hit" :
"miss", entry ? entry->
paddr : 0);
145 DPRINTF(
TLB,
"insert(vpn=%#x, asid=%#x): ppn=%#x pte=%#x size=%#x\n",
149 TlbEntry *newEntry = lookup(vpn, entry.
asid, BaseMMU::Read,
true);
152 newEntry->
pte = entry.
pte;
153 assert(newEntry->
vaddr == vpn);
157 if (freeList.empty())
160 newEntry = freeList.front();
161 freeList.pop_front();
165 newEntry->
lruSeq = nextSeq();
166 newEntry->
vaddr = vpn;
168 trie.insert(key, TlbEntryTrie::MaxBits - entry.
logBytes, newEntry);
173TLB::demapPage(
Addr vpn, uint64_t asid)
177 if (vpn == 0 && asid == 0)
180 DPRINTF(
TLB,
"flush(vpn=%#x, asid=%#x)\n", vpn, asid);
181 if (vpn != 0 && asid != 0) {
182 TlbEntry *newEntry = lookup(vpn, asid, BaseMMU::Read,
true);
184 remove(newEntry -
tlb.data());
187 for (
size_t i = 0;
i < size;
i++) {
188 if (tlb[i].trieHandle) {
190 if ((vpn == 0 || (vpn & mask) == tlb[i].vaddr) &&
203 for (
size_t i = 0;
i < size;
i++) {
204 if (tlb[i].trieHandle)
210TLB::remove(
size_t idx)
212 DPRINTF(
TLB,
"remove(vpn=%#x, asid=%#x): ppn=%#x pte=%#x size=%#x\n",
216 assert(
tlb[idx].trieHandle);
217 trie.remove(
tlb[idx].trieHandle);
218 tlb[idx].trieHandle = NULL;
219 freeList.push_back(&
tlb[idx]);
228 if (
mode == BaseMMU::Read && !pte.r) {
229 DPRINTF(
TLB,
"PTE has no read perm, raising PF\n");
232 else if (
mode == BaseMMU::Write && !pte.w) {
233 DPRINTF(
TLB,
"PTE has no write perm, raising PF\n");
236 else if (
mode == BaseMMU::Execute && !pte.x) {
237 DPRINTF(
TLB,
"PTE has no exec perm, raising PF\n");
243 if (pmode == PrivilegeMode::PRV_U && !pte.u) {
244 DPRINTF(
TLB,
"PTE is not user accessible, raising PF\n");
247 else if (pmode == PrivilegeMode::PRV_S && pte.u &&
status.sum == 0) {
248 DPRINTF(
TLB,
"PTE is only user accessible, raising PF\n");
260 if (
mode == BaseMMU::Read)
261 code = ExceptionCode::LOAD_PAGE;
262 else if (
mode == BaseMMU::Write)
263 code = ExceptionCode::STORE_PAGE;
265 code = ExceptionCode::INST_PAGE;
266 return std::make_shared<AddressFault>(
vaddr, code);
273 assert(
e !=
nullptr);
274 return e->paddr << PageShift | (
vaddr &
mask(
e->logBytes));
289 Fault fault = walker->start(tc, translation, req,
mode);
290 if (translation !=
nullptr || fault !=
NoFault) {
296 assert(
e !=
nullptr);
305 if (
mode == BaseMMU::Write && !
e->pte.w) {
306 DPRINTF(
TLB,
"Dirty bit not set, repeating PT walk\n");
307 fault = walker->start(tc, translation, req,
mode);
308 if (translation !=
nullptr || fault !=
NoFault) {
318 DPRINTF(TLBVerbose,
"translate(vpn=%#x, asid=%#x): %#x\n",
319 vaddr, satp.asid, paddr);
320 req->setPaddr(paddr);
330 if (
mode != BaseMMU::Execute &&
status.mprv == 1)
348 fault = pma->checkVAddrAlignment(req,
mode);
350 if (!misa.rvs || pmode == PrivilegeMode::PRV_M ||
351 satp.mode == AddrXlateMode::BARE) {
352 req->setFlags(Request::PHYSICAL);
356 if (req->getFlags() & Request::PHYSICAL) {
360 req->setPaddr(req->getVaddr());
362 fault = doTranslate(req, tc, translation,
mode, delayed);
366 if (!delayed && fault ==
NoFault) {
370 fault = pmp->pmpCheck(req,
mode, pmode, tc);
373 if (!delayed && fault ==
NoFault) {
374 fault = pma->check(req,
mode);
385 assert(req->getSize() > 0);
386 if (req->getVaddr() + req->getSize() - 1 < req->getVaddr())
387 return std::make_shared<GenericPageTableFault>(req->getVaddr());
391 Fault fault = p->pTable->translate(req);
404 return translate(req, tc,
nullptr, mode, delayed);
413 Fault fault = translate(req, tc, translation, mode, delayed);
415 translation->
finish(fault, req, tc, mode);
421TLB::translateFunctional(
const RequestPtr &req, ThreadContext *tc,
424 const Addr vaddr = req->getVaddr();
428 MMU *mmu =
static_cast<MMU *
>(tc->getMMUPtr());
430 PrivilegeMode pmode = mmu->getMemPriv(tc, mode);
431 MISA misa = tc->readMiscRegNoEffect(MISCREG_ISA);
432 SATP satp = tc->readMiscReg(MISCREG_SATP);
433 if (misa.rvs && pmode != PrivilegeMode::PRV_M &&
434 satp.mode != AddrXlateMode::BARE) {
435 Walker *walker = mmu->getDataWalker();
437 Fault fault = walker->startFunctional(
438 tc, paddr, logBytes, mode);
439 if (fault != NoFault)
442 Addr masked_addr = vaddr & mask(logBytes);
443 paddr |= masked_addr;
447 Process *process = tc->getProcessPtr();
448 const auto *pte = process->pTable->lookup(vaddr);
450 if (!pte && mode != BaseMMU::Execute) {
452 if (process->fixupFault(vaddr)) {
454 pte = process->pTable->lookup(vaddr);
459 return std::make_shared<GenericPageTableFault>(req->getVaddr());
461 paddr = pte->paddr | process->pTable->pageOffset(vaddr);
464 DPRINTF(TLB,
"Translated (functional) %#x -> %#x.\n", vaddr, paddr);
465 req->setPaddr(paddr);
470TLB::finalizePhysical(
const RequestPtr &req,
471 ThreadContext *tc, BaseMMU::Mode mode)
const
477TLB::serialize(CheckpointOut &cp)
const
480 uint32_t _size = size - freeList.size();
485 for (uint32_t x = 0;
x < size;
x++) {
486 if (tlb[x].trieHandle != NULL)
487 tlb[
x].serializeSection(cp,
csprintf(
"Entry%d", _count++));
492TLB::unserialize(CheckpointIn &cp)
498 fatal(
"TLB size less than the one in checkpoint!");
503 for (uint32_t x = 0;
x < _size;
x++) {
504 TlbEntry *newEntry = freeList.front();
505 freeList.pop_front();
509 newEntry->trieHandle = trie.insert(key,
510 TlbEntryTrie::MaxBits - newEntry->logBytes, newEntry);
515 : statistics::
Group(parent),
516 ADD_STAT(readHits, statistics::units::Count::get(),
"read hits"),
517 ADD_STAT(readMisses, statistics::units::Count::get(),
"read misses"),
518 ADD_STAT(readAccesses, statistics::units::Count::get(),
"read accesses"),
519 ADD_STAT(writeHits, statistics::units::Count::get(),
"write hits"),
520 ADD_STAT(writeMisses, statistics::units::Count::get(),
"write misses"),
521 ADD_STAT(writeAccesses, statistics::units::Count::get(),
"write accesses"),
522 ADD_STAT(hits, statistics::units::Count::get(),
523 "Total TLB (read and write) hits", readHits + writeHits),
524 ADD_STAT(misses, statistics::units::Count::get(),
525 "Total TLB (read and write) misses", readMisses + writeMisses),
526 ADD_STAT(accesses, statistics::units::Count::get(),
527 "Total TLB (read and write) accesses",
528 readAccesses + writeAccesses)
virtual void finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc, BaseMMU::Mode mode)=0
virtual void markDelayed()=0
Signal that the translation has been delayed due to a hw page table walk.
Ports are used to interface objects to each other.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual RegVal readMiscReg(RegIndex misc_reg)=0
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
virtual Process * getProcessPtr()=0
Port * getTableWalkerPort() override
Get the table walker port.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
#define fatal(...)
This implements a cprintf based fatal() function.
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Declaration of IniFile object.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
std::shared_ptr< FaultBase > Fault
static Addr buildKey(Addr vpn, uint16_t asid)
std::shared_ptr< Request > RequestPtr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
std::string csprintf(const char *format, const Args &...args)
constexpr decltype(nullptr) NoFault
Declarations of a non-full system Page Table.
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
TlbEntryTrie::Handle trieHandle