arm: support 16kb vm granules
This commit is contained in:
parent
0756406739
commit
12210ada54
3 changed files with 139 additions and 68 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2013 ARM Limited
|
* Copyright (c) 2010-2014 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -1715,6 +1715,30 @@ namespace ArmISA
|
||||||
Bitfield<20> tbi;
|
Bitfield<20> tbi;
|
||||||
EndBitUnion(TTBCR)
|
EndBitUnion(TTBCR)
|
||||||
|
|
||||||
|
// Fields of TCR_EL{1,2,3} (mostly overlapping)
|
||||||
|
// TCR_EL1 is natively 64 bits, the others are 32 bits
|
||||||
|
BitUnion64(TCR)
|
||||||
|
Bitfield<5, 0> t0sz;
|
||||||
|
Bitfield<7> epd0; // EL1
|
||||||
|
Bitfield<9, 8> irgn0;
|
||||||
|
Bitfield<11, 10> orgn0;
|
||||||
|
Bitfield<13, 12> sh0;
|
||||||
|
Bitfield<15, 14> tg0;
|
||||||
|
Bitfield<18, 16> ps;
|
||||||
|
Bitfield<20> tbi; // EL2/EL3
|
||||||
|
Bitfield<21, 16> t1sz; // EL1
|
||||||
|
Bitfield<22> a1; // EL1
|
||||||
|
Bitfield<23> epd1; // EL1
|
||||||
|
Bitfield<25, 24> irgn1; // EL1
|
||||||
|
Bitfield<27, 26> orgn1; // EL1
|
||||||
|
Bitfield<29, 28> sh1; // EL1
|
||||||
|
Bitfield<31, 30> tg1; // EL1
|
||||||
|
Bitfield<34, 32> ips; // EL1
|
||||||
|
Bitfield<36> as; // EL1
|
||||||
|
Bitfield<37> tbi0; // EL1
|
||||||
|
Bitfield<38> tbi1; // EL1
|
||||||
|
EndBitUnion(TCR)
|
||||||
|
|
||||||
BitUnion32(HTCR)
|
BitUnion32(HTCR)
|
||||||
Bitfield<2, 0> t0sz;
|
Bitfield<2, 0> t0sz;
|
||||||
Bitfield<9, 8> irgn0;
|
Bitfield<9, 8> irgn0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, 2012-2013 ARM Limited
|
* Copyright (c) 2010, 2012-2014 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -220,18 +220,18 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
|
||||||
case EL0:
|
case EL0:
|
||||||
case EL1:
|
case EL1:
|
||||||
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1);
|
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL1);
|
||||||
currState->ttbcr = currState->tc->readMiscReg(MISCREG_TCR_EL1);
|
currState->tcr = currState->tc->readMiscReg(MISCREG_TCR_EL1);
|
||||||
break;
|
break;
|
||||||
// @todo: uncomment this to enable Virtualization
|
// @todo: uncomment this to enable Virtualization
|
||||||
// case EL2:
|
// case EL2:
|
||||||
// assert(haveVirtualization);
|
// assert(haveVirtualization);
|
||||||
// currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL2);
|
// currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL2);
|
||||||
// currState->ttbcr = currState->tc->readMiscReg(MISCREG_TCR_EL2);
|
// currState->tcr = currState->tc->readMiscReg(MISCREG_TCR_EL2);
|
||||||
// break;
|
// break;
|
||||||
case EL3:
|
case EL3:
|
||||||
assert(haveSecurity);
|
assert(haveSecurity);
|
||||||
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL3);
|
currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR_EL3);
|
||||||
currState->ttbcr = currState->tc->readMiscReg(MISCREG_TCR_EL3);
|
currState->tcr = currState->tc->readMiscReg(MISCREG_TCR_EL3);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Invalid exception level");
|
panic("Invalid exception level");
|
||||||
|
@ -625,8 +625,7 @@ TableWalker::processWalkLPAE()
|
||||||
|
|
||||||
currState->longDesc.lookupLevel = start_lookup_level;
|
currState->longDesc.lookupLevel = start_lookup_level;
|
||||||
currState->longDesc.aarch64 = false;
|
currState->longDesc.aarch64 = false;
|
||||||
currState->longDesc.largeGrain = false;
|
currState->longDesc.grainSize = Grain4KB;
|
||||||
currState->longDesc.grainSize = 12;
|
|
||||||
|
|
||||||
Event *event = start_lookup_level == L1 ? (Event *) &doL1LongDescEvent
|
Event *event = start_lookup_level == L1 ? (Event *) &doL1LongDescEvent
|
||||||
: (Event *) &doL2LongDescEvent;
|
: (Event *) &doL2LongDescEvent;
|
||||||
|
@ -663,13 +662,18 @@ TableWalker::processWalkAArch64()
|
||||||
{
|
{
|
||||||
assert(currState->aarch64);
|
assert(currState->aarch64);
|
||||||
|
|
||||||
DPRINTF(TLB, "Beginning table walk for address %#llx, TTBCR: %#llx\n",
|
DPRINTF(TLB, "Beginning table walk for address %#llx, TCR: %#llx\n",
|
||||||
currState->vaddr_tainted, currState->ttbcr);
|
currState->vaddr_tainted, currState->tcr);
|
||||||
|
|
||||||
|
static const GrainSize GrainMapDefault[] =
|
||||||
|
{ Grain4KB, Grain64KB, Grain16KB, ReservedGrain };
|
||||||
|
static const GrainSize GrainMap_EL1_tg1[] =
|
||||||
|
{ ReservedGrain, Grain16KB, Grain4KB, Grain64KB };
|
||||||
|
|
||||||
// Determine TTBR, table size, granule size and phys. address range
|
// Determine TTBR, table size, granule size and phys. address range
|
||||||
Addr ttbr = 0;
|
Addr ttbr = 0;
|
||||||
int tsz = 0, ps = 0;
|
int tsz = 0, ps = 0;
|
||||||
bool large_grain = false;
|
GrainSize tg = Grain4KB; // grain size computed from tg* field
|
||||||
bool fault = false;
|
bool fault = false;
|
||||||
switch (currState->el) {
|
switch (currState->el) {
|
||||||
case EL0:
|
case EL0:
|
||||||
|
@ -678,44 +682,44 @@ TableWalker::processWalkAArch64()
|
||||||
case 0:
|
case 0:
|
||||||
DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
|
DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
|
||||||
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL1);
|
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL1);
|
||||||
tsz = adjustTableSizeAArch64(64 - currState->ttbcr.t0sz);
|
tsz = adjustTableSizeAArch64(64 - currState->tcr.t0sz);
|
||||||
large_grain = currState->ttbcr.tg0;
|
tg = GrainMapDefault[currState->tcr.tg0];
|
||||||
if (bits(currState->vaddr, 63, tsz) != 0x0 ||
|
if (bits(currState->vaddr, 63, tsz) != 0x0 ||
|
||||||
currState->ttbcr.epd0)
|
currState->tcr.epd0)
|
||||||
fault = true;
|
fault = true;
|
||||||
break;
|
break;
|
||||||
case 0xffff:
|
case 0xffff:
|
||||||
DPRINTF(TLB, " - Selecting TTBR1 (AArch64)\n");
|
DPRINTF(TLB, " - Selecting TTBR1 (AArch64)\n");
|
||||||
ttbr = currState->tc->readMiscReg(MISCREG_TTBR1_EL1);
|
ttbr = currState->tc->readMiscReg(MISCREG_TTBR1_EL1);
|
||||||
tsz = adjustTableSizeAArch64(64 - currState->ttbcr.t1sz);
|
tsz = adjustTableSizeAArch64(64 - currState->tcr.t1sz);
|
||||||
large_grain = currState->ttbcr.tg1;
|
tg = GrainMap_EL1_tg1[currState->tcr.tg1];
|
||||||
if (bits(currState->vaddr, 63, tsz) != mask(64-tsz) ||
|
if (bits(currState->vaddr, 63, tsz) != mask(64-tsz) ||
|
||||||
currState->ttbcr.epd1)
|
currState->tcr.epd1)
|
||||||
fault = true;
|
fault = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// top two bytes must be all 0s or all 1s, else invalid addr
|
// top two bytes must be all 0s or all 1s, else invalid addr
|
||||||
fault = true;
|
fault = true;
|
||||||
}
|
}
|
||||||
ps = currState->ttbcr.ips;
|
ps = currState->tcr.ips;
|
||||||
break;
|
break;
|
||||||
case EL2:
|
case EL2:
|
||||||
case EL3:
|
case EL3:
|
||||||
switch(bits(currState->vaddr, 63,48)) {
|
switch(bits(currState->vaddr, 63,48)) {
|
||||||
case 0:
|
case 0:
|
||||||
DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
|
DPRINTF(TLB, " - Selecting TTBR0 (AArch64)\n");
|
||||||
if (currState->el == EL2)
|
if (currState->el == EL2)
|
||||||
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL2);
|
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL2);
|
||||||
else
|
else
|
||||||
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL3);
|
ttbr = currState->tc->readMiscReg(MISCREG_TTBR0_EL3);
|
||||||
tsz = adjustTableSizeAArch64(64 - currState->ttbcr.t0sz);
|
tsz = adjustTableSizeAArch64(64 - currState->tcr.t0sz);
|
||||||
large_grain = currState->ttbcr.tg0;
|
tg = GrainMapDefault[currState->tcr.tg0];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// invalid addr if top two bytes are not all 0s
|
// invalid addr if top two bytes are not all 0s
|
||||||
fault = true;
|
fault = true;
|
||||||
}
|
}
|
||||||
ps = currState->ttbcr.ps;
|
ps = currState->tcr.ips;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -744,32 +748,54 @@ TableWalker::processWalkAArch64()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tg == ReservedGrain) {
|
||||||
|
warn_once("Reserved granule size requested; gem5's IMPLEMENTATION "
|
||||||
|
"DEFINED behavior takes this to mean 4KB granules\n");
|
||||||
|
tg = Grain4KB;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stride = tg - 3;
|
||||||
|
LookupLevel start_lookup_level = MAX_LOOKUP_LEVELS;
|
||||||
|
|
||||||
// Determine starting lookup level
|
// Determine starting lookup level
|
||||||
LookupLevel start_lookup_level;
|
// See aarch64/translation/walk in Appendix G: ARMv8 Pseudocode Library
|
||||||
int grain_size, stride;
|
// in ARM DDI 0487A. These table values correspond to the cascading tests
|
||||||
if (large_grain) { // 64 KB granule
|
// to compute the lookup level and are of the form
|
||||||
grain_size = 16;
|
// (grain_size + N*stride), for N = {1, 2, 3}.
|
||||||
stride = grain_size - 3;
|
// A value of 64 will never succeed and a value of 0 will always succeed.
|
||||||
if (tsz > grain_size + 2 * stride)
|
{
|
||||||
start_lookup_level = L1;
|
struct GrainMap {
|
||||||
else if (tsz > grain_size + stride)
|
GrainSize grain_size;
|
||||||
start_lookup_level = L2;
|
unsigned lookup_level_cutoff[MAX_LOOKUP_LEVELS];
|
||||||
else
|
};
|
||||||
start_lookup_level = L3;
|
static const GrainMap GM[] = {
|
||||||
} else { // 4 KB granule
|
{ Grain4KB, { 39, 30, 0, 0 } },
|
||||||
grain_size = 12;
|
{ Grain16KB, { 47, 36, 25, 0 } },
|
||||||
stride = grain_size - 3;
|
{ Grain64KB, { 64, 42, 29, 0 } }
|
||||||
if (tsz > grain_size + 3 * stride)
|
};
|
||||||
start_lookup_level = L0;
|
|
||||||
else if (tsz > grain_size + 2 * stride)
|
const unsigned *lookup = NULL; // points to a lookup_level_cutoff
|
||||||
start_lookup_level = L1;
|
|
||||||
else
|
for (unsigned i = 0; i < 3; ++i) { // choose entry of GM[]
|
||||||
start_lookup_level = L2;
|
if (tg == GM[i].grain_size) {
|
||||||
|
lookup = GM[i].lookup_level_cutoff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(lookup);
|
||||||
|
|
||||||
|
for (int L = L0; L != MAX_LOOKUP_LEVELS; ++L) {
|
||||||
|
if (tsz > lookup[L]) {
|
||||||
|
start_lookup_level = (LookupLevel) L;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic_if(start_lookup_level == MAX_LOOKUP_LEVELS,
|
||||||
|
"Table walker couldn't find lookup level\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine table base address
|
// Determine table base address
|
||||||
int base_addr_lo = 3 + tsz - stride * (3 - start_lookup_level) -
|
int base_addr_lo = 3 + tsz - stride * (3 - start_lookup_level) - tg;
|
||||||
grain_size;
|
|
||||||
Addr base_addr = mbits(ttbr, 47, base_addr_lo);
|
Addr base_addr = mbits(ttbr, 47, base_addr_lo);
|
||||||
|
|
||||||
// Determine physical address size and raise an Address Size Fault if
|
// Determine physical address size and raise an Address Size Fault if
|
||||||
|
@ -812,7 +838,7 @@ TableWalker::processWalkAArch64()
|
||||||
// Determine descriptor address
|
// Determine descriptor address
|
||||||
Addr desc_addr = base_addr |
|
Addr desc_addr = base_addr |
|
||||||
(bits(currState->vaddr, tsz - 1,
|
(bits(currState->vaddr, tsz - 1,
|
||||||
stride * (3 - start_lookup_level) + grain_size) << 3);
|
stride * (3 - start_lookup_level) + tg) << 3);
|
||||||
|
|
||||||
// Trickbox address check
|
// Trickbox address check
|
||||||
Fault f = tlb->walkTrickBoxCheck(desc_addr, currState->isSecure,
|
Fault f = tlb->walkTrickBoxCheck(desc_addr, currState->isSecure,
|
||||||
|
@ -839,8 +865,7 @@ TableWalker::processWalkAArch64()
|
||||||
|
|
||||||
currState->longDesc.lookupLevel = start_lookup_level;
|
currState->longDesc.lookupLevel = start_lookup_level;
|
||||||
currState->longDesc.aarch64 = true;
|
currState->longDesc.aarch64 = true;
|
||||||
currState->longDesc.largeGrain = large_grain;
|
currState->longDesc.grainSize = tg;
|
||||||
currState->longDesc.grainSize = grain_size;
|
|
||||||
|
|
||||||
if (currState->timing) {
|
if (currState->timing) {
|
||||||
Event *event;
|
Event *event;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2013 ARM Limited
|
* Copyright (c) 2010-2014 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -362,6 +362,14 @@ class TableWalker : public MemObject
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Granule sizes for AArch64 long descriptors
|
||||||
|
enum GrainSize {
|
||||||
|
Grain4KB = 12,
|
||||||
|
Grain16KB = 14,
|
||||||
|
Grain64KB = 16,
|
||||||
|
ReservedGrain = 0
|
||||||
|
};
|
||||||
|
|
||||||
/** Long-descriptor format (LPAE) */
|
/** Long-descriptor format (LPAE) */
|
||||||
class LongDescriptor : public DescriptorBase {
|
class LongDescriptor : public DescriptorBase {
|
||||||
public:
|
public:
|
||||||
|
@ -409,11 +417,8 @@ class TableWalker : public MemObject
|
||||||
/** True if the current lookup is performed in AArch64 state */
|
/** True if the current lookup is performed in AArch64 state */
|
||||||
bool aarch64;
|
bool aarch64;
|
||||||
|
|
||||||
/** True if the granule size is 64 KB (AArch64 only) */
|
|
||||||
bool largeGrain;
|
|
||||||
|
|
||||||
/** Width of the granule size in bits */
|
/** Width of the granule size in bits */
|
||||||
int grainSize;
|
GrainSize grainSize;
|
||||||
|
|
||||||
/** Return the descriptor type */
|
/** Return the descriptor type */
|
||||||
EntryType type() const
|
EntryType type() const
|
||||||
|
@ -421,8 +426,8 @@ class TableWalker : public MemObject
|
||||||
switch (bits(data, 1, 0)) {
|
switch (bits(data, 1, 0)) {
|
||||||
case 0x1:
|
case 0x1:
|
||||||
// In AArch64 blocks are not allowed at L0 for the 4 KB granule
|
// In AArch64 blocks are not allowed at L0 for the 4 KB granule
|
||||||
// and at L1 for the 64 KB granule
|
// and at L1 for 16/64 KB granules
|
||||||
if (largeGrain)
|
if (grainSize > Grain4KB)
|
||||||
return lookupLevel == L2 ? Block : Invalid;
|
return lookupLevel == L2 ? Block : Invalid;
|
||||||
return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block;
|
return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
|
@ -435,15 +440,29 @@ class TableWalker : public MemObject
|
||||||
/** Return the bit width of the page/block offset */
|
/** Return the bit width of the page/block offset */
|
||||||
uint8_t offsetBits() const
|
uint8_t offsetBits() const
|
||||||
{
|
{
|
||||||
assert(type() == Block || type() == Page);
|
if (type() == Block) {
|
||||||
if (largeGrain) {
|
switch (grainSize) {
|
||||||
if (type() == Block)
|
case Grain4KB:
|
||||||
return 29 /* 512 MB */;
|
return lookupLevel == L1 ? 30 /* 1 GB */
|
||||||
return 16 /* 64 KB */; // type() == Page
|
: 21 /* 2 MB */;
|
||||||
|
case Grain16KB:
|
||||||
|
return 25 /* 32 MB */;
|
||||||
|
case Grain64KB:
|
||||||
|
return 29 /* 512 MB */;
|
||||||
|
default:
|
||||||
|
panic("Invalid AArch64 VM granule size\n");
|
||||||
|
}
|
||||||
|
} else if (type() == Page) {
|
||||||
|
switch (grainSize) {
|
||||||
|
case Grain4KB:
|
||||||
|
case Grain16KB:
|
||||||
|
case Grain64KB:
|
||||||
|
return grainSize; /* enum -> uint okay */
|
||||||
|
default:
|
||||||
|
panic("Invalid AArch64 VM granule size\n");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (type() == Block)
|
panic("AArch64 page table entry must be block or page\n");
|
||||||
return lookupLevel == L1 ? 30 /* 1 GB */ : 21 /* 2 MB */;
|
|
||||||
return 12 /* 4 KB */; // type() == Page
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,8 +726,11 @@ class TableWalker : public MemObject
|
||||||
/** Cached copy of the cpsr as it existed when translation began */
|
/** Cached copy of the cpsr as it existed when translation began */
|
||||||
CPSR cpsr;
|
CPSR cpsr;
|
||||||
|
|
||||||
/** Cached copy of the ttbcr as it existed when translation began. */
|
/** Cached copy of ttbcr/tcr as it existed when translation began */
|
||||||
TTBCR ttbcr;
|
union {
|
||||||
|
TTBCR ttbcr; // AArch32 translations
|
||||||
|
TCR tcr; // AArch64 translations
|
||||||
|
};
|
||||||
|
|
||||||
/** Cached copy of the htcr as it existed when translation began. */
|
/** Cached copy of the htcr as it existed when translation began. */
|
||||||
HTCR htcr;
|
HTCR htcr;
|
||||||
|
|
Loading…
Reference in a new issue