summaryrefslogtreecommitdiff
path: root/src/arch/arm/table_walker.cc
diff options
context:
space:
mode:
authorDylan Johnson <Dylan.Johnson@ARM.com>2016-08-02 10:38:02 +0100
committerDylan Johnson <Dylan.Johnson@ARM.com>2016-08-02 10:38:02 +0100
commitc53a57f74f31c2593665bae716c5c3679aab5595 (patch)
tree292e4929f35d05d7fac170dacaccd720007269cf /src/arch/arm/table_walker.cc
parent49538a71186d98f5440c5db646e23507fc2e38d1 (diff)
downloadgem5-c53a57f74f31c2593665bae716c5c3679aab5595.tar.xz
arm: add stage2 translation support
Change-Id: I8f7c09c7ec3a97149ebebf4b21471b244e6cecc1
Diffstat (limited to 'src/arch/arm/table_walker.cc')
-rw-r--r--src/arch/arm/table_walker.cc57
1 files changed, 42 insertions, 15 deletions
diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index 1f0bdeb8e..4eb57c59a 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -249,7 +249,10 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
currState->vaddr = currState->vaddr_tainted;
if (currState->aarch64) {
- switch (currState->el) {
+ if (isStage2) {
+ currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1);
+ currState->vtcr = currState->tc->readMiscReg(MISCREG_VTCR_EL2);
+ } else switch (currState->el) {
case EL0:
case EL1:
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1);
@@ -269,6 +272,7 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
panic("Invalid exception level");
break;
}
+ currState->hcr = currState->tc->readMiscReg(MISCREG_HCR_EL2);
} else {
currState->sctlr = currState->tc->readMiscReg(flattenMiscRegNsBanked(
MISCREG_SCTLR, currState->tc, !currState->isSecure));
@@ -289,9 +293,8 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
// hyp mode, the second stage MMU is enabled, and this table walker
// instance is the first stage.
currState->doingStage2 = false;
- // @todo: for now disable this in AArch64 (HCR is not set)
- currState->stage2Req = !currState->aarch64 && currState->hcr.vm &&
- !isStage2 && !currState->isSecure && !currState->isHyp;
+ currState->stage2Req = currState->hcr.vm && !isStage2 &&
+ !currState->isSecure && !currState->isHyp;
bool long_desc_format = currState->aarch64 || _isHyp || isStage2 ||
longDescFormatInUse(currState->tc);
@@ -743,10 +746,32 @@ TableWalker::processWalkAArch64()
int tsz = 0, ps = 0;
GrainSize tg = Grain4KB; // grain size computed from tg* field
bool fault = false;
+
+ LookupLevel start_lookup_level = MAX_LOOKUP_LEVELS;
+
switch (currState->el) {
case EL0:
case EL1:
- switch (bits(currState->vaddr, 63,48)) {
+ if (isStage2) {
+ DPRINTF(TLB, " - Selecting VTTBR0 (AArch64 stage 2)\n");
+ ttbr = currState->tc->readMiscReg(MISCREG_VTTBR_EL2);
+ tsz = 64 - currState->vtcr.t0sz64;
+ tg = GrainMapDefault[currState->vtcr.tg0];
+ // ARM DDI 0487A.f D7-2148
+ // The starting level of stage 2 translation depends on
+ // VTCR_EL2.SL0 and VTCR_EL2.TG0
+ LookupLevel __ = MAX_LOOKUP_LEVELS; // invalid level
+ uint8_t sl_tg = (currState->vtcr.sl0 << 2) | currState->vtcr.tg0;
+ static const LookupLevel SLL[] = {
+ L2, L3, L3, __, // sl0 == 0
+ L1, L2, L2, __, // sl0 == 1, etc.
+ L0, L1, L1, __,
+ __, __, __, __
+ };
+ start_lookup_level = SLL[sl_tg];
+ panic_if(start_lookup_level == MAX_LOOKUP_LEVELS,
+ "Cannot discern lookup level from vtcr.{sl0,tg0}");
+ } else switch (bits(currState->vaddr, 63,48)) {
case 0:
DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL1);
@@ -824,16 +849,13 @@ TableWalker::processWalkAArch64()
tg = Grain4KB;
}
- int stride = tg - 3;
- LookupLevel start_lookup_level = MAX_LOOKUP_LEVELS;
-
// Determine starting lookup level
// See aarch64/translation/walk in Appendix G: ARMv8 Pseudocode Library
// in ARM DDI 0487A. These table values correspond to the cascading tests
// to compute the lookup level and are of the form
// (grain_size + N*stride), for N = {1, 2, 3}.
// A value of 64 will never succeed and a value of 0 will always succeed.
- {
+ if (start_lookup_level == MAX_LOOKUP_LEVELS) {
struct GrainMap {
GrainSize grain_size;
unsigned lookup_level_cutoff[MAX_LOOKUP_LEVELS];
@@ -864,6 +886,8 @@ TableWalker::processWalkAArch64()
"Table walker couldn't find lookup level\n");
}
+ int stride = tg - 3;
+
// Determine table base address
int base_addr_lo = 3 + tsz - stride * (3 - start_lookup_level) - tg;
Addr base_addr = mbits(ttbr, 47, base_addr_lo);
@@ -969,10 +993,9 @@ TableWalker::processWalkAArch64()
stateQueues[start_lookup_level].push_back(currState);
currState = NULL;
} else if (!currState->functional) {
- port->dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t),
- NULL, (uint8_t*) &currState->longDesc.data,
- currState->tc->getCpuPtr()->clockPeriod(), flag);
- doLongDescriptor();
+ fetchDescriptor(desc_addr, (uint8_t*)&currState->longDesc.data,
+ sizeof(uint64_t), flag, -1, NULL,
+ &TableWalker::doLongDescriptor);
f = currState->fault;
} else {
RequestPtr req = new Request(desc_addr, sizeof(uint64_t), flag,
@@ -1913,8 +1936,12 @@ TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
{
bool isTiming = currState->timing;
- // do the requests for the page table descriptors have to go through the
- // second stage MMU
+ DPRINTF(TLBVerbose, "Fetching descriptor at address: 0x%x stage2Req: %d\n",
+ descAddr, currState->stage2Req);
+
+ // If this translation has a stage 2 then we know descAddr is an IPA and
+ // needs to be translated before we can access the page table. Do that
+ // check here.
if (currState->stage2Req) {
Fault fault;
flags = flags | TLB::MustBeOne;