51#include "debug/Checkpoint.hh"
52#include "debug/Drain.hh"
53#include "debug/PageTableWalker.hh"
54#include "debug/TLB.hh"
55#include "debug/TLBVerbose.hh"
56#include "params/ArmTableWalker.hh"
76 doL2DescEvent([
this]{ doL2DescriptorWrapper(); },
name()),
77 doL0LongDescEvent([
this]{ doL0LongDescriptorWrapper(); },
name()),
78 doL1LongDescEvent([
this]{ doL1LongDescriptorWrapper(); },
name()),
79 doL2LongDescEvent([
this]{ doL2LongDescriptorWrapper(); },
name()),
80 doL3LongDescEvent([
this]{ doL3LongDescriptorWrapper(); },
name()),
81 LongDescEventByLevel { &doL0LongDescEvent, &doL1LongDescEvent,
82 &doL2LongDescEvent, &doL3LongDescEvent },
83 doProcessEvent([
this]{ processWalkWrapper(); },
name()),
90 ArmSystem *arm_sys =
dynamic_cast<ArmSystem *
>(
p.sys);
92 _physAddrRange = arm_sys->physAddrRange();
93 _haveLargeAsid64 = arm_sys->haveLargeAsid64();
95 _haveLargeAsid64 =
false;
115 if (if_name ==
"port") {
163 state->delay = delay;
207 assert(pkt->
req->isUncacheable() ||
250 DPRINTF(Drain,
"TableWalker done draining, processing drain event\n");
258 bool state_queues_not_empty =
false;
260 for (
int i = 0;
i < LookupLevel::Num_ArmLookupLevel; ++
i) {
262 state_queues_not_empty =
true;
268 DPRINTF(Drain,
"TableWalker not drained\n");
271 DPRINTF(Drain,
"TableWalker free, no need to drain\n");
289 bool disable_cacheability =
isStage2 ?
292 return disable_cacheability ||
currState->isUncacheable;
301 bool _stage2Req,
const TlbEntry *walk_entry)
303 assert(!(_functional && _timing));
312 DPRINTF(PageTableWalker,
"creating new instance of WalkerState\n");
316 }
else if (_functional) {
321 "creating functional instance of WalkerState\n");
325 }
else if (_timing) {
332 if (
currState->vaddr_tainted == _req->getVaddr()) {
333 ++
stats.squashedBefore;
334 return std::make_shared<ReExec>();
403 assert(
release->has(ArmExtension::VIRTUALIZATION));
408 assert(
release->has(ArmExtension::SECURITY));
413 panic(
"Invalid translation regime");
440 if (long_desc_format) {
444 currState->longDescData->userTable =
true;
445 currState->longDescData->xnTable =
false;
446 currState->longDescData->pxnTable =
false;
447 ++
stats.walksLongDescriptor;
450 ++
stats.walksShortDescriptor;
467 }
else if (long_desc_format) {
489 currState->longDesc.lookupLevel : LookupLevel::L1;
521 if (!
currState->transState->squashed() && (!
te ||
te->partial)) {
529 if (
te &&
te->partial) {
535 }
else if (long_desc_format) {
552 currState->longDesc.lookupLevel : LookupLevel::L1;
562 unsigned num_squashed = 0;
566 (
te && !
te->partial))) {
569 stats.squashedBefore++;
571 DPRINTF(
TLB,
"Squashing table walk for address %#x\n",
577 std::make_shared<UnimpFault>(
"Squashed Inst"),
619 const auto irgn0_mask = 0x1;
620 const auto irgn1_mask = 0x40;
621 currState->isUncacheable = (ttbr1 & (irgn0_mask | irgn1_mask)) == 0;
625 const bool is_atomic =
currState->req->isAtomic();
626 const bool have_security =
release->has(ArmExtension::SECURITY);
628 DPRINTF(
TLB,
"Beginning table walk for address %#x, TTBCR: %#x, bits:%#x\n",
638 if (have_security &&
currState->ttbcr.pd0) {
640 return std::make_shared<PrefetchAbort>(
646 return std::make_shared<DataAbort>(
659 if (have_security &&
currState->ttbcr.pd1) {
661 return std::make_shared<PrefetchAbort>(
667 return std::make_shared<DataAbort>(
680 DPRINTF(
TLB,
" - Descriptor at address %#x (%s)\n", l1desc_addr,
694 sizeof(uint32_t), flag, LookupLevel::L1,
704 Addr ttbr, ttbr0_max, ttbr1_min, desc_addr;
708 DPRINTF(
TLB,
"Beginning table walk for address %#x, TTBCR: %#x\n",
720 DPRINTF(
TLB,
" - Selecting VTTBR (long-desc.)\n");
723 start_lookup_level =
currState->vtcr.sl0 ?
724 LookupLevel::L1 : LookupLevel::L2;
727 DPRINTF(
TLB,
" - Selecting HTTBR (long-desc.)\n");
736 ttbr0_max = (1ULL << (32 -
currState->ttbcr.t0sz)) - 1;
738 ttbr0_max = (1ULL << 32) -
739 (1ULL << (32 -
currState->ttbcr.t1sz)) - 1;
741 ttbr0_max = (1ULL << 32) - 1;
743 ttbr1_min = (1ULL << 32) - (1ULL << (32 -
currState->ttbcr.t1sz));
745 ttbr1_min = (1ULL << (32 -
currState->ttbcr.t0sz));
747 const bool is_atomic =
currState->req->isAtomic();
754 DPRINTF(
TLB,
" - Selecting TTBR0 (long-desc.)\n");
758 return std::make_shared<PrefetchAbort>(
764 return std::make_shared<DataAbort>(
777 if (ttbr0_max < (1ULL << 30))
778 start_lookup_level = LookupLevel::L2;
779 }
else if (
currState->vaddr >= ttbr1_min) {
780 DPRINTF(
TLB,
" - Selecting TTBR1 (long-desc.)\n");
784 return std::make_shared<PrefetchAbort>(
790 return std::make_shared<DataAbort>(
804 if (ttbr1_min >= (1ULL << 31) + (1ULL << 30))
805 start_lookup_level = LookupLevel::L2;
809 return std::make_shared<PrefetchAbort>(
815 return std::make_shared<DataAbort>(
826 if (start_lookup_level == LookupLevel::L1) {
828 desc_addr =
mbits(ttbr, 39,
n) |
830 DPRINTF(
TLB,
" - Descriptor at address %#x (%s) (long-desc.)\n",
835 n = (tsz >= 2 ? 14 - tsz : 12);
836 desc_addr =
mbits(ttbr, 39,
n) |
838 DPRINTF(
TLB,
" - Descriptor at address %#x (%s) (long-desc.)\n",
847 currState->longDesc.lookupLevel = start_lookup_level;
854 sizeof(uint64_t), flag, start_lookup_level,
902 return tsz > max_txsz || tsz < min_txsz;
925 DPRINTF(
TLB,
"Beginning table walk for address %#llx, TCR: %#llx\n",
942 bool vaddr_fault =
false;
949 DPRINTF(
TLB,
" - Selecting VSTTBR_EL2 (AArch64 stage 2)\n");
954 DPRINTF(
TLB,
" - Selecting VTTBR_EL2 (AArch64 stage 2)\n");
970 DPRINTF(
TLB,
" - Selecting TTBR0_EL1 (AArch64)\n");
985 DPRINTF(
TLB,
" - Selecting TTBR1_EL1 (AArch64)\n");
1010 DPRINTF(
TLB,
" - Selecting TTBR0_EL2 (AArch64)\n");
1027 DPRINTF(
TLB,
" - Selecting TTBR1_EL2 (AArch64)\n");
1051 DPRINTF(
TLB,
" - Selecting TTBR0_EL3 (AArch64)\n");
1076 const bool is_atomic =
currState->req->isAtomic();
1080 return std::make_shared<PrefetchAbort>(
1085 return std::make_shared<DataAbort>(
1095 warn_once(
"Reserved granule size requested; gem5's IMPLEMENTATION "
1096 "DEFINED behavior takes this to mean 4KB granules\n");
1108 auto [table_addr, desc_addr, start_lookup_level] =
walkAddresses(
1109 ttbr, tg, tsz, pa_range);
1114 DPRINTF(
TLB,
"Address size fault before any lookup\n");
1116 return std::make_shared<PrefetchAbort>(
1122 return std::make_shared<DataAbort>(
1140 currState->longDesc.lookupLevel = start_lookup_level;
1146 assert(start_lookup_level < LookupLevel::Num_ArmLookupLevel);
1149 sizeof(uint64_t), flag, start_lookup_level,
1156std::tuple<Addr, Addr, TableWalker::LookupLevel>
1161 LookupLevel first_level = LookupLevel::Num_ArmLookupLevel;
1162 Addr table_addr = 0;
1169 "Walk Cache hit: va=%#x, level=%d, table address=%#x\n",
1172 if (
currState->longDescData.has_value()) {
1179 table_addr = entry->
pfn;
1184 ptops->firstS2Level(
currState->vtcr.sl0) :
1185 ptops->firstLevel(64 - tsz);
1186 panic_if(first_level == LookupLevel::Num_ArmLookupLevel,
1187 "Table walker couldn't find lookup level\n");
1190 int base_addr_lo = 3 + tsz -
stride * (3 - first_level) - tg;
1192 if (pa_range == 52) {
1193 int z = (base_addr_lo < 6) ? 6 : base_addr_lo;
1194 table_addr =
mbits(ttbr, 47,
z);
1195 table_addr |= (
bits(ttbr, 5, 2) << 48);
1197 table_addr =
mbits(ttbr, 47, base_addr_lo);
1201 desc_addr = table_addr + ptops->index(
currState->vaddr, first_level, tsz);
1203 return std::make_tuple(table_addr, desc_addr, first_level);
1208 uint8_t texcb,
bool s)
1212 DPRINTF(TLBVerbose,
"memAttrs texcb:%d s:%d\n", texcb,
s);
1213 te.shareable =
false;
1214 te.nonCacheable =
false;
1215 te.outerShareable =
false;
1219 te.nonCacheable =
true;
1221 te.shareable =
true;
1226 te.nonCacheable =
true;
1228 te.shareable =
true;
1236 te.outerAttrs =
bits(texcb, 1, 0);
1242 te.outerAttrs =
bits(texcb, 1, 0);
1245 te.nonCacheable =
true;
1249 te.outerAttrs =
bits(texcb, 1, 0);
1252 panic(
"Reserved texcb value!\n");
1255 panic(
"Implementation-defined texcb value!\n");
1264 te.nonCacheable =
true;
1266 te.shareable =
false;
1271 panic(
"Reserved texcb value!\n");
1276 if (
bits(texcb, 1,0) == 0 ||
bits(texcb, 3,2) == 0)
1277 te.nonCacheable =
true;
1278 te.innerAttrs =
bits(texcb, 1, 0);
1279 te.outerAttrs =
bits(texcb, 3, 2);
1282 panic(
"More than 32 states for 5 bits?\n");
1290 DPRINTF(TLBVerbose,
"memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
1291 uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0;
1292 switch(
bits(texcb, 2,0)) {
1297 te.outerShareable = (prrr.nos0 == 0);
1303 te.outerShareable = (prrr.nos1 == 0);
1309 te.outerShareable = (prrr.nos2 == 0);
1315 te.outerShareable = (prrr.nos3 == 0);
1321 te.outerShareable = (prrr.nos4 == 0);
1327 te.outerShareable = (prrr.nos5 == 0);
1330 panic(
"Imp defined type\n");
1335 te.outerShareable = (prrr.nos7 == 0);
1341 DPRINTF(TLBVerbose,
"StronglyOrdered\n");
1343 te.nonCacheable =
true;
1346 te.shareable =
true;
1349 DPRINTF(TLBVerbose,
"Device ds1:%d ds0:%d s:%d\n",
1350 prrr.ds1, prrr.ds0,
s);
1352 te.nonCacheable =
true;
1356 te.shareable =
true;
1358 te.shareable =
true;
1361 DPRINTF(TLBVerbose,
"Normal ns1:%d ns0:%d s:%d\n",
1362 prrr.ns1, prrr.ns0,
s);
1365 te.shareable =
true;
1367 te.shareable =
true;
1370 panic(
"Reserved type");
1376 te.nonCacheable =
true;
1392 te.nonCacheable =
true;
1407 DPRINTF(TLBVerbose,
"memAttrs: shareable: %d, innerAttrs: %d, "
1409 te.shareable,
te.innerAttrs,
te.outerAttrs);
1410 te.setAttributes(
false);
1417 assert(
release->has(ArmExtension::LPAE));
1420 uint8_t
sh = l_descriptor.
sh();
1425 uint8_t attr_3_2 = (
attr >> 2) & 0x3;
1426 uint8_t attr_1_0 =
attr & 0x3;
1428 DPRINTF(TLBVerbose,
"memAttrsLPAE MemAttr:%#x sh:%#x\n",
attr,
sh);
1430 if (attr_3_2 == 0) {
1434 te.innerAttrs = attr_1_0 == 0 ? 1 : 3;
1435 te.nonCacheable =
true;
1438 te.outerAttrs = attr_3_2 == 1 ? 0 :
1439 attr_3_2 == 2 ? 2 : 1;
1440 te.innerAttrs = attr_1_0 == 1 ? 0 :
1441 attr_1_0 == 2 ? 6 : 5;
1442 te.nonCacheable = (attr_3_2 == 1) || (attr_1_0 == 1);
1445 uint8_t attrIndx = l_descriptor.
attrIndx();
1452 uint32_t mair =
currState->tc->readMiscReg(reg_as_int);
1453 attr = (mair >> (8 * (attrIndx % 4))) & 0xff;
1454 uint8_t attr_7_4 =
bits(
attr, 7, 4);
1455 uint8_t attr_3_0 =
bits(
attr, 3, 0);
1456 DPRINTF(TLBVerbose,
"memAttrsLPAE AttrIndx:%#x sh:%#x, attr %#x\n", attrIndx,
sh,
attr);
1461 te.nonCacheable =
false;
1466 if (attr_3_0 == 0x0)
1468 else if (attr_3_0 == 0x4)
1471 panic(
"Unpredictable behavior\n");
1472 te.nonCacheable =
true;
1479 if (attr_3_0 == 0x4)
1481 te.nonCacheable =
true;
1482 else if (attr_3_0 < 0x8)
1483 panic(
"Unpredictable behavior\n");
1493 if (attr_7_4 & 0x4) {
1494 te.outerAttrs = (attr_7_4 & 1) ? 1 : 3;
1496 te.outerAttrs = 0x2;
1500 if (attr_3_0 != 0x4 && attr_3_0 < 0x8)
1501 panic(
"Unpredictable behavior\n");
1504 panic(
"Unpredictable behavior\n");
1510 te.innerAttrs = 0x1;
1513 te.innerAttrs = attr_7_4 == 0 ? 0x3 : 0;
1525 te.innerAttrs = attr_3_0 & 1 ? 0x5 : 0x7;
1528 panic(
"Unpredictable behavior\n");
1533 te.outerShareable =
sh == 2;
1534 te.shareable = (
sh & 0x2) ?
true :
false;
1535 te.setAttributes(
true);
1536 te.attributes |= (uint64_t)
attr << 56;
1542 return !
bits(attrs, 2) ||
1553 uint8_t
sh = l_descriptor.
sh();
1557 uint8_t attr_hi = (
attr >> 2) & 0x3;
1558 uint8_t attr_lo =
attr & 0x3;
1560 DPRINTF(TLBVerbose,
"memAttrsAArch64 MemAttr:%#x sh:%#x\n",
attr,
sh);
1566 te.innerAttrs = attr_lo == 0 ? 1 : 3;
1567 te.nonCacheable =
true;
1570 te.outerAttrs = attr_hi == 1 ? 0 :
1571 attr_hi == 2 ? 2 : 1;
1572 te.innerAttrs = attr_lo == 1 ? 0 :
1573 attr_lo == 2 ? 6 : 5;
1576 te.nonCacheable = (attr_hi == 1) || (attr_hi == 2) ||
1577 (attr_lo == 1) || (attr_lo == 2);
1580 te.xs = !l_descriptor.
fnxs();
1583 uint8_t attrIndx = l_descriptor.
attrIndx();
1585 DPRINTF(TLBVerbose,
"memAttrsAArch64 AttrIndx:%#x sh:%#x\n", attrIndx,
sh);
1601 panic(
"Invalid exception level");
1606 attr =
bits(mair, 8 * attrIndx + 7, 8 * attrIndx);
1613 case 0b00000000 ... 0b00001111:
1615 te.nonCacheable =
true;
1620 te.nonCacheable =
true;
1625 te.nonCacheable =
true;
1633 te.xs =
te.nonCacheable;
1637 te.shareable =
sh == 2;
1638 te.outerShareable = (
sh & 0x2) ?
true :
false;
1640 te.attributes = ((uint64_t)
attr << 56) |
1655 te.nonCacheable =
true;
1660 te.nonCacheable = (
te.outerAttrs == 0 ||
te.outerAttrs == 2) &&
1661 (
te.innerAttrs == 0 ||
te.innerAttrs == 2);
1665 te.xs =
te.nonCacheable;
1678 DPRINTF(
TLB,
"L1 descriptor for %#x is %#x\n",
1682 const bool is_atomic =
currState->req->isAtomic();
1691 DPRINTF(
TLB,
"L1 Descriptor Reserved/Ignore, causing fault\n");
1694 std::make_shared<PrefetchAbort>(
1701 std::make_shared<DataAbort>(
1715 currState->fault = std::make_shared<DataAbort>(
1724 panic(
"Haven't implemented supersections\n");
1731 l2desc_addr =
currState->l1Desc.l2Addr() |
1733 DPRINTF(
TLB,
"L1 descriptor points to page table at: %#x (%s)\n",
1748 sizeof(uint32_t), flag, LookupLevel::L2,
1757 panic(
"A new type in a 2 bit field?\n");
1765 return std::make_shared<PrefetchAbort>(
1771 return std::make_shared<DataAbort>(
1791 DPRINTF(
TLB,
"L%d descriptor for %#llx is %#llx (%s)\n",
1794 currState->aarch64 ?
"AArch64" :
"long-desc.");
1798 DPRINTF(PageTableWalker,
"Analyzing L%d descriptor: %#llx, pxn: %d, "
1799 "xn: %d, ap: %d, piindex: %d, af: %d, type: %d\n",
1809 DPRINTF(PageTableWalker,
"Analyzing L%d descriptor: %#llx, type: %d\n",
1819 DPRINTF(
TLB,
"L%d descriptor Invalid, causing fault type %d\n",
1838 DPRINTF(
TLB,
"L%d descriptor causing Address Size Fault\n",
1843 }
else if (
currState->longDesc.af() == 0) {
1845 DPRINTF(
TLB,
"L%d descriptor causing Access Fault\n",
1881 DPRINTF(
TLB,
"L%d descriptor points to L%d descriptor at: %#x (%s)\n",
1889 next_desc_addr,
currState->physAddrRange)) {
1890 DPRINTF(
TLB,
"L%d descriptor causing Address Size Fault\n",
1898 if (
mmu->hasWalkCache()) {
1912 Event *
event = NULL;
1914 case LookupLevel::L1:
1917 case LookupLevel::L2:
1918 case LookupLevel::L3:
1922 panic(
"Wrong lookup level in table walk\n");
1928 sizeof(uint64_t), flag,
L,
event,
1935 panic(
"A new type in a 2 bit field?\n");
1949 DPRINTF(
TLB,
"L2 descriptor for %#x is %#x\n",
1953 const bool is_atomic =
currState->req->isAtomic();
1956 DPRINTF(
TLB,
"L2 descriptor invalid, causing fault\n");
1962 currState->fault = std::make_shared<PrefetchAbort>(
1968 currState->fault = std::make_shared<DataAbort>(
1981 DPRINTF(
TLB,
"Generating access fault at L2, afe: %d, ap: %d\n",
1984 currState->fault = std::make_shared<DataAbort>(
2007 DPRINTF(PageTableWalker,
"L1 Desc object host addr: %p\n",
2009 DPRINTF(PageTableWalker,
"L1 Desc object data: %08x\n",
2012 DPRINTF(PageTableWalker,
"calling doL1Descriptor for vaddr:%#x\n",
2021 stats.walksShortTerminatedAtLevel[0]++;
2035 DPRINTF(PageTableWalker,
"calling translateTiming again\n");
2041 stats.walksShortTerminatedAtLevel[0]++;
2068 DPRINTF(PageTableWalker,
"calling doL2Descriptor for vaddr:%#x\n",
2076 stats.walksShortTerminatedAtLevel[1]++;
2079 DPRINTF(PageTableWalker,
"calling translateTiming again\n");
2085 stats.walksShortTerminatedAtLevel[1]++;
2129 assert(curr_lookup_level ==
currState->longDesc.lookupLevel);
2138 DPRINTF(PageTableWalker,
"calling doLongDescriptor for vaddr:%#x\n",
2158 DPRINTF(PageTableWalker,
"calling translateTiming again\n");
2165 stats.walksLongTerminatedAtLevel[(unsigned) curr_lookup_level]++;
2175 if (curr_lookup_level >= LookupLevel::Num_ArmLookupLevel - 1)
2176 panic(
"Max. number of lookups already reached in table walk\n");
2202 "Fetching descriptor at address: 0x%x stage2Req: %d\n",
2217 fault = tran->fault;
2233 (this->*doDescriptor)();
2256 currState->tc->getCpuPtr()->clockPeriod());
2258 (this->*doDescriptor)();
2260 port->sendFunctionalReq(req,
data);
2261 (this->*doDescriptor)();
2269 DPRINTF(PageTableWalker,
"Adding to walker fifo: "
2270 "queue size before adding: %d\n",
2279 const bool have_security =
release->has(ArmExtension::SECURITY);
2284 te.longDescFormat =
true;
2294 te.size = (1ULL <<
te.N) - 1;
2301 te.type = TypeTLB::unified;
2314 DPRINTF(
TLB,
" - N:%d pfn:%#x size:%#x global:%d valid:%d\n",
2316 DPRINTF(
TLB,
" - vpn:%#x xn:%d pxn:%d ap:%d domain:%d asid:%d "
2317 "vmid:%d nc:%d ns:%d\n",
te.vpn,
te.xn,
te.pxn,
2318 te.ap,
static_cast<uint8_t
>(
te.domain),
te.asid,
te.vmid,
2319 te.nonCacheable,
te.ns);
2320 DPRINTF(
TLB,
" - domain from L%d desc:%d data:%#x\n",
2331 const bool have_security =
release->has(ArmExtension::SECURITY);
2336 te.longDescFormat = long_descriptor;
2341 te.size = (1<<
te.N) - 1;
2342 te.pfn = descriptor.
pfn();
2348 te.xn = descriptor.
xn();
2350 TypeTLB::instruction : TypeTLB::data;
2360 if (long_descriptor) {
2366 te.pxn =
currState->longDescData->pxnTable || l_descriptor.
pxn();
2370 te.hap = l_descriptor.
ap();
2373 descriptor.
ap() >> 1) << 1) |
2374 (
currState->longDescData->userTable && (descriptor.
ap() & 0x1));
2383 te.ap = descriptor.
ap();
2390 DPRINTF(
TLB,
" - N:%d pfn:%#x size:%#x global:%d valid:%d\n",
2392 DPRINTF(
TLB,
" - vpn:%#x xn:%d pxn:%d ap:%d piindex:%d domain:%d asid:%d "
2393 "vmid:%d nc:%d ns:%d\n",
te.vpn,
te.xn,
te.pxn,
2395 static_cast<uint8_t
>(
te.domain),
te.asid,
te.vmid,
2396 te.nonCacheable,
te.ns);
2397 DPRINTF(
TLB,
" - domain from L%d desc:%d data:%#x\n",
2412 switch (lookup_level_as_int) {
2413 case LookupLevel::L1:
2414 return LookupLevel::L1;
2415 case LookupLevel::L2:
2416 return LookupLevel::L2;
2417 case LookupLevel::L3:
2418 return LookupLevel::L3;
2420 panic(
"Invalid lookup level conversion");
2478 panic(
"unknown page size");
2491 auto req = std::make_shared<Request>();
2508 port->sendFunctional(&pkt);
2510 port->sendAtomic(&pkt);
2548 req = std::make_shared<Request>();
2585 "Table walker walks requested"),
2587 "Table walker walks initiated with short descriptors"),
2589 "Table walker walks initiated with long descriptors"),
2591 "Level at which table walker walks with short descriptors "
2594 "Level at which table walker walks with long descriptors "
2597 "Table walks squashed before starting"),
2599 "Table walks squashed after completion"),
2601 "Table walker wait (enqueue to first request) latency"),
2603 "Table walker service (enqueue to completion) latency"),
2605 "Table walker pending requests distribution"),
2607 "Table walker page sizes translated"),
2609 "Table walker requests started/completed, data/inst")
FaultSource
Generic fault source enums used to index into {short/long/aarch64}DescFaultSources[] to get the actua...
virtual void annotate(AnnotationIDs id, uint64_t val)
static ExceptionLevel tranTypeEL(CPSR cpsr, SCR scr, ArmTranslationType type)
Determine the EL to use for the purpose of a translation given a specific translation type.
virtual bool global(WalkerState *currState) const =0
virtual bool xn() const =0
virtual uint8_t * getRawPtr()=0
virtual uint64_t getRawData() const =0
virtual DomainType domain() const =0
virtual uint8_t texcb() const
virtual std::string dbgHeader() const =0
virtual uint8_t ap() const =0
virtual bool shareable() const
virtual uint8_t offsetBits() const =0
virtual Addr pfn() const =0
LookupLevel lookupLevel
Current lookup level for this descriptor.
virtual bool secure(bool have_security, WalkerState *currState) const =0
Long-descriptor format (LPAE)
uint8_t sh() const
2-bit shareability field
uint8_t memAttr() const
Memory attributes, only used by stage 2 translations.
uint8_t offsetBits() const override
Return the bit width of the page/block offset.
bool pxn() const
Is privileged execution allowed on this mapping?
DomainType domain() const override
uint8_t piindex() const
Stage 1 Indirect permissions.
bool secure(bool have_security, WalkerState *currState) const override
Returns true if this entry targets the secure physical address map.
std::string dbgHeader() const override
Addr nextTableAddr() const
Return the address of the next page table.
GrainSize grainSize
Width of the granule size in bits.
uint8_t attrIndx() const
Attribute index.
uint8_t ap() const override
2-bit access protection flags
bool fnxs() const
FNXS for FEAT_XS only.
uint64_t getRawData() const override
SnoopRespPacketQueue snoopRespQueue
Packet queue used to store outgoing snoop responses.
ReqPacketQueue reqQueue
Packet queue used to store outgoing requests.
Port(TableWalker &_walker)
void sendAtomicReq(const RequestPtr &req, uint8_t *data, Tick delay)
void handleResp(TableWalkerState *state, Addr addr, Addr size, Tick delay=0)
void sendFunctionalReq(const RequestPtr &req, uint8_t *data)
void handleRespPacket(PacketPtr pkt, Tick delay=0)
void sendTimingReq(const RequestPtr &req, uint8_t *data, Tick delay, Event *event)
PacketPtr createPacket(const RequestPtr &req, uint8_t *data, Tick delay, Event *event)
bool recvTimingResp(PacketPtr pkt) override
Receive a timing response from the peer.
This translation class is used to trigger the data fetch once a timing translation returns the transl...
void finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc, BaseMMU::Mode mode)
void setVirt(Addr vaddr, int size, Request::Flags flags, int requestorId)
MMU::ArmTranslationType tranType
Stage2Walk(TableWalker &_parent, uint8_t *_data, Event *_event, Addr vaddr, BaseMMU::Mode mode, MMU::ArmTranslationType tran_type)
void translateTiming(ThreadContext *tc)
bool isWrite
If the access is a write.
CPSR cpsr
Cached copy of the cpsr as it existed when translation began.
Addr vaddr_tainted
The virtual address that is being translated.
RequestPtr req
Request that is currently being serviced.
VTCR_t vtcr
Cached copy of the vtcr as it existed when translation began.
HCR hcr
Cached copy of the htcr as it existed when translation began.
Addr vaddr
The virtual address that is being translated with tagging removed.
bool functional
If the atomic mode should be functional.
bool isUncacheable
True if table walks are uncacheable (for table descriptors)
ThreadContext * tc
Thread context that we're doing the walk for.
bool hpd
Hierarchical access permission disable.
BaseMMU::Translation * transState
Translation state for delayed requests.
SecurityState ss
Security State of the access.
std::optional< LongDescData > longDescData
BaseMMU::Mode mode
Save mode for use in delayed response.
HTCR htcr
Cached copy of the htcr as it existed when translation began.
SCR scr
Cached copy of the scr as it existed when translation began.
MMU::ArmTranslationType tranType
The translation type that has been requested.
SCTLR sctlr
Cached copy of the sctlr as it existed when translation began.
TableWalker * tableWalker
bool isFetch
If the access is a fetch (for execution, and no-exec) must be checked?
bool stage2Req
Flag indicating if a second stage of lookup is required.
TranslationRegime regime
Current translation regime.
bool timing
If the mode is timing or atomic.
int physAddrRange
Current physical address range in bits.
bool delayed
Whether the response is delayed in timing mode due to additional lookups.
uint16_t asid
ASID that we're servicing the request under.
L1Descriptor l1Desc
Short-format descriptors.
bool aarch64
If the access is performed in AArch64 state.
BaseMMU::Translation * stage2Tran
A pointer to the stage 2 translation that's in progress.
void doL2DescriptorWrapper()
static LookupLevel toLookupLevel(uint8_t lookup_level_as_int)
enums::ArmLookupLevel LookupLevel
void doL2LongDescriptorWrapper()
void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, uint8_t texcb, bool s)
void doL3LongDescriptorWrapper()
const ArmRelease * release
Cached copies of system-level properties.
void doL1DescriptorWrapper()
bool checkVAOutOfRange(Addr addr, int top_bit, int tsz, bool low_range)
Fault generateLongDescFault(ArmFault::FaultSource src)
EventFunctionWrapper doL1DescEvent
EventFunctionWrapper doProcessEvent
static const unsigned REQUESTED
static const unsigned COMPLETED
bool uncacheableWalk() const
Returns true if the table walk should be uncacheable.
Event * LongDescEventByLevel[4]
void memAttrsAArch64(ThreadContext *tc, TlbEntry &te, LongDescriptor &lDescriptor)
void insertPartialTableEntry(LongDescriptor &descriptor)
void doL1LongDescriptorWrapper()
void fetchDescriptor(Addr desc_addr, DescriptorBase &descriptor, int num_bytes, Request::Flags flags, LookupLevel lookup_lvl, Event *event, void(TableWalker::*doDescriptor)())
void drainResume() override
Resume execution after a successful drain.
void doLongDescriptorWrapper(LookupLevel curr_lookup_level)
void doL0LongDescriptorWrapper()
bool pending
If a timing translation is currently in progress.
Port * port
Port shared by the two table walkers.
Fault testWalk(const RequestPtr &walk_req, DomainType domain, LookupLevel lookup_level)
Addr s1MinTxSz(GrainSize tg) const
std::tuple< Addr, Addr, LookupLevel > walkAddresses(Addr ttbr, GrainSize tg, int tsz, int pa_range)
Returns a tuple made of: 1) The address of the first page table 2) The address of the first descripto...
Fault readDataUntimed(ThreadContext *tc, Addr vaddr, Addr desc_addr, uint8_t *data, int num_bytes, Request::Flags flags, BaseMMU::Mode mode, MMU::ArmTranslationType tran_type, bool functional)
TableWalker(const Params &p)
void nextWalk(ThreadContext *tc)
void readDataTimed(ThreadContext *tc, Addr desc_addr, Stage2Walk *translation, int num_bytes, Request::Flags flags)
EventFunctionWrapper doL2DescEvent
gem5::Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
std::list< WalkerState * > pendingQueue
Queue of requests that have passed are waiting because the walker is currently busy.
bool s1TxSzFault(GrainSize tg, int tsz) const
MMU * mmu
The MMU to forward second stage look upts to.
RequestorID requestorId
Requestor id assigned by the MMU.
gem5::ArmISA::TableWalker::TableWalkerStats stats
Port & getTableWalkerPort()
Fault walk(const RequestPtr &req, ThreadContext *tc, uint16_t asid, vmid_t _vmid, BaseMMU::Mode mode, BaseMMU::Translation *_trans, bool timing, bool functional, SecurityState ss, PASpace ipaspace, MMU::ArmTranslationType tran_type, bool stage2, const TlbEntry *walk_entry)
Fault processWalkAArch64()
const bool isStage2
Indicates whether this table walker is part of the stage 2 mmu.
bool uncacheableFromAttrs(uint8_t attrs)
bool checkAddrSizeFaultAArch64(Addr addr, int pa_range)
Returns true if the address exceeds the range permitted by the system-wide setting or by the TCR_ELx ...
void mpamTagTableWalk(RequestPtr &req) const
static uint8_t pageSizeNtoStatBin(uint8_t N)
void completeDrain()
Checks if all state is cleared and if so, completes drain.
void insertTableEntry(DescriptorBase &descriptor, bool longDescriptor)
DrainState drain() override
Provide a default implementation of the drain interface for objects that don't need draining.
std::list< WalkerState * > stateQueues[LookupLevel::Num_ArmLookupLevel]
Queues of requests for all the different lookup levels.
unsigned numSquashable
The number of walks belonging to squashed instructions that can be removed from the pendingQueue per ...
TLB * tlb
TLB that is initiating these table walks.
void memAttrsLPAE(ThreadContext *tc, TlbEntry &te, LongDescriptor &lDescriptor)
void setTestInterface(TlbTestInterface *ti)
void processWalkWrapper()
void memAttrsWalkAArch64(TlbEntry &te)
Addr maxTxSz(GrainSize tg) const
SCTLR sctlr
Cached copy of the sctlr as it existed when translation began.
void stashCurrState(int queue_idx)
Timing mode: saves the currState into the stateQueues.
ClockedObject(const ClockedObjectParams &p)
ClockedObjectParams Params
Parameters of ClockedObject.
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Cycles is a wrapper class for representing cycle counts, i.e.
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void dataStatic(T *p)
Set the data pointer to the following value that should not be freed.
SenderState * senderState
This packet's sender state.
RequestPtr req
A pointer to the original request.
bool cacheResponding() const
Ports are used to interface objects to each other.
const std::string name() const
Return port name (for DPRINTF).
QueuedRequestPort(const std::string &name, ReqPacketQueue &req_queue, SnoopRespPacketQueue &snoop_resp_queue, PortID id=InvalidPortID)
Create a QueuedPort with a given name, and a supplied implementation of two packet queues.
void schedTimingReq(PacketPtr pkt, Tick when)
Schedule the sending of a timing request.
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
void sendFunctional(PacketPtr pkt) const
Send a functional request packet, where the data is instantly updated everywhere in the memory system...
@ PT_WALK
The request is a page table walk.
@ SECURE
The request targets the secure memory space.
@ UNCACHEABLE
The request is to an uncacheable address.
@ NO_ACCESS
The request should not cause a memory access.
gem5::Flags< FlagsType > Flags
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual RegVal readMiscReg(RegIndex misc_reg)=0
virtual BaseCPU * getCpuPtr()=0
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
constexpr uint64_t sext(uint64_t val)
Sign-extend an N-bit value to 64 bits.
void signalDrainDone() const
Signal that an object is drained.
DrainState drainState() const
Return the current drain state of an object.
DrainState
Object drain/handover states.
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
void schedule(Event &event, Tick when)
void set(Type mask)
Set all flag's bits matching the given mask.
#define panic(...)
This implements a cprintf based panic() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
const Params & params() const
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
void tagRequest(ThreadContext *tc, const RequestPtr &req, bool ind)
Tag a memory request with MPAM information.
ByteOrder byteOrder(const ThreadContext *tc)
const PageTableOps * getPageTableOps(GrainSize trans_granule)
Bitfield< 21, 20 > stride
bool longDescFormatInUse(ThreadContext *tc)
bool ELIs64(ThreadContext *tc, ExceptionLevel el)
const GrainSize GrainMap_tg1[]
TranslationRegime translationRegime(ThreadContext *tc, ExceptionLevel el)
ExceptionLevel translationEl(TranslationRegime regime)
SecurityState
Security State.
int computeAddrTop(ThreadContext *tc, bool selbit, bool is_instr, TCR tcr, ExceptionLevel el)
int decodePhysAddrRange64(uint8_t pa_enc)
Returns the n.
const GrainSize GrainMap_tg0[]
int snsBankedIndex(MiscRegIndex reg, ThreadContext *tc)
PASpace
Physical Address Space.
bool HaveExt(ThreadContext *tc, ArmExtension ext)
Returns true if the provided ThreadContext supports the ArmExtension passed as a second argument.
Addr purifyTaggedAddr(Addr addr, ThreadContext *tc, ExceptionLevel el, TCR tcr, bool is_instr)
Removes the tag from tagged addresses if that mode is enabled.
const FlagsType pdf
Print the percent of the total that this entry represents.
const FlagsType nonan
Don't print if this is NAN.
const FlagsType nozero
Don't print if this is zero.
const FlagsType total
Print the total.
const FlagsType dist
Print the distribution.
Copyright (c) 2024 Arm Limited All rights reserved.
std::shared_ptr< FaultBase > Fault
std::shared_ptr< Request > RequestPtr
Tick curTick()
The universal simulation clock.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
uint64_t Tick
Tick count type.
T htog(T value, ByteOrder guest_byte_order)
constexpr decltype(nullptr) NoFault
Overload hash function for BasicBlockRange type.
statistics::Scalar squashedBefore
statistics::Vector2d requestOrigin
TableWalkerStats(statistics::Group *parent)
statistics::Scalar walksLongDescriptor
statistics::Scalar walksShortDescriptor
statistics::Histogram walkWaitTime
statistics::Vector walksShortTerminatedAtLevel
statistics::Vector pageSizes
statistics::Vector walksLongTerminatedAtLevel
statistics::Histogram walkServiceTime
statistics::Histogram pendingWalks
statistics::Scalar squashedAfter
Helper variables used to implement hierarchical access permissions when the long-desc.
TLBTypes::KeyType KeyType
const std::string & name()