ARM: Added support for Access Flag and some CP15 regs (V2PCWPR, V2PCWPW, V2PCWUR, V2PCWUW,...)

This commit is contained in:
Dam Sunwoo
2010-06-02 12:58:18 -05:00
parent 85ba2a3243
commit 6c8dd32fa4
7 changed files with 414 additions and 49 deletions

View File

@@ -117,6 +117,38 @@ ISA::clear()
miscRegs[MISCREG_MPIDR] = 0;
// Reset values of PRRR and NMRR are implementation dependent
miscRegs[MISCREG_PRRR] =
(1 << 19) | // 19
(0 << 18) | // 18
(0 << 17) | // 17
(1 << 16) | // 16
(2 << 14) | // 15:14
(0 << 12) | // 13:12
(2 << 10) | // 11:10
(2 << 8) | // 9:8
(2 << 6) | // 7:6
(2 << 4) | // 5:4
(1 << 2) | // 3:2
0; // 1:0
miscRegs[MISCREG_NMRR] =
(1 << 30) | // 31:30
(0 << 26) | // 27:26
(0 << 24) | // 25:24
(3 << 22) | // 23:22
(2 << 20) | // 21:20
(0 << 18) | // 19:18
(0 << 16) | // 17:16
(1 << 14) | // 15:14
(0 << 12) | // 13:12
(2 << 10) | // 11:10
(0 << 8) | // 9:8
(3 << 6) | // 7:6
(2 << 4) | // 5:4
(0 << 2) | // 3:2
0; // 1:0
//XXX We need to initialize the rest of the state.
}
@@ -362,6 +394,63 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
case MISCREG_DTLBIASID:
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_V2PCWPR:
case MISCREG_V2PCWPW:
case MISCREG_V2PCWUR:
case MISCREG_V2PCWUW:
case MISCREG_V2POWPR:
case MISCREG_V2POWPW:
case MISCREG_V2POWUR:
case MISCREG_V2POWUW:
{
RequestPtr req = new Request;
unsigned flags;
BaseTLB::Mode mode;
Fault fault;
switch(misc_reg) {
case MISCREG_V2PCWPR:
flags = TLB::MustBeOne;
mode = BaseTLB::Read;
break;
case MISCREG_V2PCWPW:
flags = TLB::MustBeOne;
mode = BaseTLB::Write;
break;
case MISCREG_V2PCWUR:
flags = TLB::MustBeOne | TLB::UserMode;
mode = BaseTLB::Read;
break;
case MISCREG_V2PCWUW:
flags = TLB::MustBeOne | TLB::UserMode;
mode = BaseTLB::Write;
break;
case MISCREG_V2POWPR:
case MISCREG_V2POWPW:
case MISCREG_V2POWUR:
case MISCREG_V2POWUW:
panic("Security Extensions not implemented!");
}
req->setVirt(0, val, 1, flags, tc->readPC());
fault = tc->getDTBPtr()->translateAtomic(req, tc, mode);
if (fault == NoFault) {
miscRegs[MISCREG_PAR] =
(req->getPaddr() & 0xfffff000) |
(tc->getDTBPtr()->getAttr() );
DPRINTF(MiscRegs,
"MISCREG: Translated addr 0x%08x: PAR: 0x%08x\n",
val, miscRegs[MISCREG_PAR]);
}
else {
// Set fault bit and FSR
FSR fsr = miscRegs[MISCREG_DFSR];
miscRegs[MISCREG_PAR] =
(fsr.ext << 6) |
(fsr.fsHigh << 5) |
(fsr.fsLow << 1) |
0x1; // F bit
}
return;
}
}
}
setMiscRegNoEffect(misc_reg, newVal);

View File

@@ -138,6 +138,15 @@ namespace ArmISA
MISCREG_CTR,
MISCREG_SCR,
MISCREG_SDER,
MISCREG_PAR,
MISCREG_V2PCWPR,
MISCREG_V2PCWPW,
MISCREG_V2PCWUR,
MISCREG_V2PCWUW,
MISCREG_V2POWPR,
MISCREG_V2POWPW,
MISCREG_V2POWUR,
MISCREG_V2POWUW,
MISCREG_CP15_UNIMP_START,
MISCREG_TCMTR = MISCREG_CP15_UNIMP_START,
MISCREG_ID_PFR1,
@@ -153,7 +162,6 @@ namespace ArmISA
MISCREG_ID_ISAR3,
MISCREG_ID_ISAR4,
MISCREG_ID_ISAR5,
MISCREG_PAR,
MISCREG_AIDR,
MISCREG_ACTLR,
MISCREG_ADFSR,
@@ -163,14 +171,6 @@ namespace ArmISA
MISCREG_MCCSW,
MISCREG_DCCMVAU,
MISCREG_NSACR,
MISCREG_V2PCWPR,
MISCREG_V2PCWPW,
MISCREG_V2PCWUR,
MISCREG_V2PCWUW,
MISCREG_V2POWPR,
MISCREG_V2POWPW,
MISCREG_V2POWUR,
MISCREG_V2POWUW,
MISCREG_VBAR,
MISCREG_MVBAR,
MISCREG_ISR,
@@ -206,20 +206,20 @@ namespace ArmISA
"dtlbiall", "dtlbimva", "dtlbiasid",
"tlbiall", "tlbimva", "tlbiasid", "tlbimvaa",
"dfsr", "ifsr", "dfar", "ifar", "mpidr",
"prrr", "nmrr", "ttbcr", "id_pfr0", "ctr"
"scr", "sder"
"prrr", "nmrr", "ttbcr", "id_pfr0", "ctr",
"scr", "sder", "par",
"v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
"v2powpr", "v2powpw", "v2powur", "v2powuw",
// Unimplemented below
"tcmtr",
"id_pfr1", "id_dfr0", "id_afr0",
"id_mmfr0", "id_mmfr1", "id_mmfr2", "id_mmfr3",
"id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5",
"par", "aidr", "actlr",
"aidr", "actlr",
"adfsr", "aifsr",
"dcimvac", "dcisw", "mccsw",
"dccmvau",
"nsacr",
"v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
"v2powpr", "v2powpw", "v2powur", "v2powuw",
"vbar", "mvbar", "isr", "fceidr",
"nop", "raz"
};

View File

@@ -133,6 +133,14 @@ struct TlbEntry
bool nonCacheable; // Can we wrap this in mtype?
bool sNp; // Section descriptor
// Memory Attributes
MemoryType mtype;
uint8_t innerAttrs;
uint8_t outerAttrs;
bool shareable;
uint32_t attributes; // Memory attributes formatted for PAR
// Access permissions
bool xn; // Execute Never
uint8_t ap:3; // Access permissions bits

View File

@@ -96,8 +96,8 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode m
contextId = _cid;
timing = _timing;
// XXX These should be cached or grabbed from cached copies in
// the TLB, all these miscreg reads are expensive
/** @todo These should be cached or grabbed from cached copies in
the TLB, all these miscreg reads are expensive */
vaddr = req->getVaddr() & ~PcModeMask;
sctlr = tc->readMiscReg(MISCREG_SCTLR);
cpsr = tc->readMiscReg(MISCREG_CPSR);
@@ -149,58 +149,224 @@ TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode m
}
void
TableWalker::memAttrs(TlbEntry &te, uint8_t texcb)
TableWalker::memAttrs(TlbEntry &te, uint8_t texcb, bool s)
{
DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
te.shareable = false; // default value
bool outer_shareable = false;
if (sctlr.tre == 0) {
switch(texcb) {
case 0:
case 1:
case 4:
case 8:
case 0: // Stongly-ordered
te.nonCacheable = true;
te.mtype = TlbEntry::StronglyOrdered;
te.shareable = true;
te.innerAttrs = 1;
te.outerAttrs = 0;
break;
case 16:
case 1: // Shareable Device
te.nonCacheable = true;
te.mtype = TlbEntry::Device;
te.shareable = true;
te.innerAttrs = 3;
te.outerAttrs = 0;
break;
case 2: // Outer and Inner Write-Through, no Write-Allocate
te.mtype = TlbEntry::Normal;
te.shareable = s;
te.innerAttrs = 6;
te.outerAttrs = bits(texcb, 1, 0);
break;
case 3: // Outer and Inner Write-Back, no Write-Allocate
te.mtype = TlbEntry::Normal;
te.shareable = s;
te.innerAttrs = 7;
te.outerAttrs = bits(texcb, 1, 0);
break;
case 4: // Outer and Inner Non-cacheable
te.nonCacheable = true;
te.mtype = TlbEntry::Normal;
te.shareable = s;
te.innerAttrs = 0;
te.outerAttrs = bits(texcb, 1, 0);
break;
case 5: // Reserved
break;
case 6: // Implementation Defined
break;
case 7: // Outer and Inner Write-Back, Write-Allocate
te.mtype = TlbEntry::Normal;
te.shareable = s;
te.innerAttrs = 5;
te.outerAttrs = 1;
break;
case 8: // Non-shareable Device
te.nonCacheable = true;
te.mtype = TlbEntry::Device;
te.shareable = false;
te.innerAttrs = 3;
te.outerAttrs = 0;
break;
case 9 ... 15: // Reserved
break;
case 16 ... 31: // Cacheable Memory
te.mtype = TlbEntry::Normal;
te.shareable = s;
if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
te.nonCacheable = true;
te.innerAttrs = bits(texcb, 1, 0);
te.outerAttrs = bits(texcb, 3, 2);
break;
default:
panic("More than 32 states for 5 bits?\n");
}
} else {
PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
uint8_t curr_tr, curr_ir, curr_or;
switch(bits(texcb, 2,0)) {
case 0:
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr0;
curr_ir = nmrr.ir0;
curr_or = nmrr.or0;
outer_shareable = (prrr.nos0 == 0);
break;
case 1:
if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr1;
curr_ir = nmrr.ir1;
curr_or = nmrr.or1;
outer_shareable = (prrr.nos1 == 0);
break;
case 2:
if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr2;
curr_ir = nmrr.ir2;
curr_or = nmrr.or2;
outer_shareable = (prrr.nos2 == 0);
break;
case 3:
if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr3;
curr_ir = nmrr.ir3;
curr_or = nmrr.or3;
outer_shareable = (prrr.nos3 == 0);
break;
case 4:
if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr4;
curr_ir = nmrr.ir4;
curr_or = nmrr.or4;
outer_shareable = (prrr.nos4 == 0);
break;
case 5:
if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr5;
curr_ir = nmrr.ir5;
curr_or = nmrr.or5;
outer_shareable = (prrr.nos5 == 0);
break;
case 6:
panic("Imp defined type\n");
case 7:
if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2)
te.nonCacheable = true;
curr_tr = prrr.tr7;
curr_ir = nmrr.ir7;
curr_or = nmrr.or7;
outer_shareable = (prrr.nos7 == 0);
break;
}
switch(curr_tr) {
case 0:
DPRINTF(TLBVerbose, "StronglyOrdered\n");
te.mtype = TlbEntry::StronglyOrdered;
te.nonCacheable = true;
te.innerAttrs = 1;
te.outerAttrs = 0;
te.shareable = true;
break;
case 1:
DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
prrr.ds1, prrr.ds0, s);
te.mtype = TlbEntry::Device;
te.nonCacheable = true;
te.innerAttrs = 3;
te.outerAttrs = 0;
if (prrr.ds1 && s)
te.shareable = true;
if (prrr.ds0 && !s)
te.shareable = true;
break;
case 2:
DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
prrr.ns1, prrr.ns0, s);
te.mtype = TlbEntry::Normal;
if (prrr.ns1 && s)
te.shareable = true;
if (prrr.ns0 && !s)
te.shareable = true;
//te.shareable = outer_shareable;
break;
case 3:
panic("Reserved type");
}
if (te.mtype == TlbEntry::Normal){
switch(curr_ir) {
case 0:
te.nonCacheable = true;
te.innerAttrs = 0;
break;
case 1:
te.innerAttrs = 5;
break;
case 2:
te.innerAttrs = 6;
break;
case 3:
te.innerAttrs = 7;
break;
}
switch(curr_or) {
case 0:
te.nonCacheable = true;
te.outerAttrs = 0;
break;
case 1:
te.outerAttrs = 1;
break;
case 2:
te.outerAttrs = 2;
break;
case 3:
te.outerAttrs = 3;
break;
}
}
}
/** Formatting for Physical Address Register (PAR)
* Only including lower bits (TLB info here)
* PAR:
* PA [31:12]
* Reserved [11]
* TLB info [10:1]
* NOS [10] (Not Outer Sharable)
* NS [9] (Non-Secure)
* -- [8] (Implementation Defined)
* SH [7] (Sharable)
* Inner[6:4](Inner memory attributes)
* Outer[3:2](Outer memory attributes)
* SS [1] (SuperSection)
* F [0] (Fault, Fault Status in [6:1] if faulted)
*/
te.attributes = (
((outer_shareable ? 0:1) << 10) |
// TODO: NS Bit
((te.shareable ? 1:0) << 7) |
(te.innerAttrs << 4) |
(te.outerAttrs << 2)
// TODO: Supersection bit
// TODO: Fault bit
);
}
void
@@ -218,11 +384,19 @@ TableWalker::doL1Descriptor()
if (isFetch)
fault = new PrefetchAbort(vaddr, ArmFault::Translation0);
else
fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0);
fault = new DataAbort(vaddr, NULL, isWrite,
ArmFault::Translation0);
return;
case L1Descriptor::Section:
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
panic("Haven't implemented AFE\n");
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) {
/** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
* enabled if set, do l1.Desc.setAp0() instead of generating
* AccessFlag0
*/
fault = new DataAbort(vaddr, NULL, isWrite,
ArmFault::AccessFlag0);
}
if (l1Desc.supersection()) {
panic("Haven't implemented supersections\n");
@@ -238,7 +412,7 @@ TableWalker::doL1Descriptor()
te.ap = l1Desc.ap();
te.domain = l1Desc.domain();
te.asid = contextId;
memAttrs(te, l1Desc.texcb());
memAttrs(te, l1Desc.texcb(), l1Desc.shareable());
DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n",
@@ -256,7 +430,8 @@ TableWalker::doL1Descriptor()
case L1Descriptor::PageTable:
Addr l2desc_addr;
l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr);
DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
l2desc_addr);
// Trickbox address check
fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
@@ -288,9 +463,6 @@ TableWalker::doL2Descriptor()
DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data);
TlbEntry te;
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
panic("Haven't implemented AFE\n");
if (l2Desc.invalid()) {
DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
tc = NULL;
@@ -298,10 +470,19 @@ TableWalker::doL2Descriptor()
if (isFetch)
fault = new PrefetchAbort(vaddr, ArmFault::Translation1);
else
fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1);
fault = new DataAbort(vaddr, l1Desc.domain(), isWrite,
ArmFault::Translation1);
return;
}
if (sctlr.afe && bits(l2Desc.ap(), 0) == 0) {
/** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
* if set, do l2.Desc.setAp0() instead of generating AccessFlag0
*/
fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::AccessFlag1);
}
if (l2Desc.large()) {
te.N = 16;
te.pfn = l2Desc.pfn();
@@ -319,7 +500,7 @@ TableWalker::doL2Descriptor()
te.xn = l2Desc.xn();
te.ap = l2Desc.ap();
te.domain = l1Desc.domain();
memAttrs(te, l2Desc.texcb());
memAttrs(te, l2Desc.texcb(), l2Desc.shareable());
tc = NULL;
req = NULL;

View File

@@ -68,8 +68,13 @@ class TableWalker : public MemObject
Reserved
};
/** The raw bits of the entry */
uint32_t data;
/** This entry has been modified (access flag set) and needs to be
* written back to memory */
bool _dirty;
EntryType type() const
{
return (EntryType)(data & 0x3);
@@ -127,19 +132,48 @@ class TableWalker : public MemObject
return mbits(data, 31,10);
}
/** Memory region attributes: ARM DDI 0406B: B3-32 */
/** Memory region attributes: ARM DDI 0406B: B3-32.
* These bits are largly ignored by M5 and only used to
* provide the illusion that the memory system cares about
* anything but cachable vs. uncachable.
*/
uint8_t texcb() const
{
return bits(data, 2) | bits(data,3) << 1 | bits(data, 14, 12) << 2;
}
/** If the section is shareable. See texcb() comment. */
bool shareable() const
{
return bits(data, 16);
}
/** Set access flag that this entry has been touched. Mark
* the entry as requiring a writeback, in the future.
*/
void setAp0()
{
data |= 1 << 10;
_dirty = true;
}
/** This entry needs to be written back to memory */
bool dirty() const
{
return _dirty;
}
};
/** Level 2 page table descriptor */
struct L2Descriptor {
/** The raw bits of the entry. */
uint32_t data;
/** This entry has been modified (access flag set) and needs to be
* written back to memory */
bool _dirty;
/** Is the entry invalid */
bool invalid() const
{
@@ -184,6 +218,27 @@ class TableWalker : public MemObject
return large() ? bits(data, 31, 16) : bits(data, 31, 12);
}
/** If the section is shareable. See texcb() comment. */
bool shareable() const
{
return bits(data, 10);
}
/** Set access flag that this entry has been touched. Mark
* the entry as requiring a writeback, in the future.
*/
void setAp0()
{
data |= 1 << 4;
_dirty = true;
}
/** This entry needs to be written back to memory */
bool dirty() const
{
return _dirty;
}
};
/** Port to issue translation requests from */
@@ -252,9 +307,9 @@ class TableWalker : public MemObject
TLB::Translation *_trans, bool timing);
void setTlb(TLB *_tlb) { tlb = _tlb; }
void memAttrs(TlbEntry &te, uint8_t texcb, bool s);
private:
void memAttrs(TlbEntry &te, uint8_t texcb);
void doL1Descriptor();
EventWrapper<TableWalker, &TableWalker::doL1Descriptor> doL1DescEvent;

View File

@@ -384,6 +384,16 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
req->setFlags(Request::UNCACHEABLE);
}
// Set memory attributes
TlbEntry temp_te;
tableWalker->memAttrs(temp_te, 0, 1);
temp_te.shareable = true;
DPRINTF(TLBVerbose, "(No MMU) setting memory attributes: shareable:\
%d, innerAttrs: %d, outerAttrs: %d\n", temp_te.shareable,
temp_te.innerAttrs, temp_te.outerAttrs);
setAttr(temp_te.attributes);
return trickBoxCheck(req, mode, 0, false);
}
@@ -409,6 +419,13 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
assert(te);
}
// Set memory attributes
DPRINTF(TLBVerbose,
"Setting memory attributes: shareable: %d, innerAttrs: %d, \
outerAttrs: %d\n",
te->shareable, te->innerAttrs, te->outerAttrs);
setAttr(te->attributes);
uint32_t dacr = tc->readMiscReg(MISCREG_DACR);
switch ( (dacr >> (te->domain * 2)) & 0x3) {
case 0:

View File

@@ -88,6 +88,8 @@ class TLB : public BaseTLB
int size; // TLB Size
int nlu; // not last used entry (for replacement)
uint32_t _attr; // Memory attributes for last accessed TLB entry
#if FULL_SYSTEM
TableWalker *tableWalker;
#endif
@@ -151,6 +153,19 @@ class TLB : public BaseTLB
static bool validVirtualAddress(Addr vaddr);
/** Accessor functions for memory attributes for last accessed TLB entry
*/
void
setAttr(uint32_t attr)
{
_attr = attr;
}
uint32_t
getAttr() const
{
return _attr;
}
#if FULL_SYSTEM
Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing);