summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2007-10-07 18:18:39 -0700
committerGabe Black <gblack@eecs.umich.edu>2007-10-07 18:18:39 -0700
commita19c212757b13e45f481d8612fd38f603250c853 (patch)
treecbc0abe8e8a9807fecfe6c432735bac7ac3b3fa8 /src
parentcd36c69a4de51d45b82038a012a53cf58f4f3fa2 (diff)
downloadgem5-a19c212757b13e45f481d8612fd38f603250c853.tar.xz
X86: Work on the x86 tlb.
--HG-- extra : convert_revision : a08a5cb049a6030ba9fd56a89383d56026238dbf
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86/process.cc56
-rw-r--r--src/arch/x86/tlb.cc105
-rw-r--r--src/arch/x86/tlb.hh5
3 files changed, 132 insertions, 34 deletions
diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc
index 79422998d..0193344e8 100644
--- a/src/arch/x86/process.cc
+++ b/src/arch/x86/process.cc
@@ -147,8 +147,60 @@ void
X86LiveProcess::startup()
{
argsInit(sizeof(IntReg), VMPageSize);
- for(int i = 0; i < NUM_SEGMENTREGS; i++)
- threadContexts[0]->setMiscRegNoEffect(MISCREG_ES_BASE + i, 0);
+
+ for (int i = 0; i < threadContexts.size(); i++) {
+ ThreadContext * tc = threadContexts[i];
+
+ SegAttr dataAttr = 0;
+ dataAttr.writable = 1;
+ dataAttr.readable = 1;
+ dataAttr.expandDown = 0;
+ dataAttr.dpl = 3;
+ dataAttr.defaultSize = 0;
+ dataAttr.longMode = 1;
+
+ //Initialize the segment registers.
+ for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
+ tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
+ tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
+ }
+
+ SegAttr csAttr = 0;
+ csAttr.writable = 0;
+ csAttr.readable = 1;
+ csAttr.expandDown = 0;
+ csAttr.dpl = 3;
+ csAttr.defaultSize = 0;
+ csAttr.longMode = 1;
+
+ tc->setMiscRegNoEffect(MISCREG_CS_ATTR, csAttr);
+
+ //Set up the registers that describe the operating mode.
+ CR0 cr0 = 0;
+ cr0.pg = 1; // Turn on paging.
+ cr0.cd = 0; // Don't disable caching.
+ cr0.nw = 0; // This is bit is defined to be ignored.
+ cr0.am = 0; // No alignment checking
+ cr0.wp = 0; // Supervisor mode can write read only pages
+ cr0.ne = 1;
+ cr0.et = 1; // This should always be 1
+ cr0.ts = 0; // We don't do task switching, so causing fp exceptions
+ // would be pointless.
+ cr0.em = 0; // Allow x87 instructions to execute natively.
+ cr0.mp = 1; // This doesn't really matter, but the manual suggests
+ // setting it to one.
+ cr0.pe = 1; // We're definitely in protected mode.
+ tc->setMiscReg(MISCREG_CR0, cr0);
+
+ Efer efer = 0;
+ efer.sce = 1; // Enable system call extensions.
+ efer.lme = 1; // Enable long mode.
+ efer.lma = 1; // Activate long mode.
+ efer.nxe = 1; // Enable nx support.
+ efer.svme = 0; // Disable svm support for now. It isn't implemented.
+ efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
+ tc->setMiscReg(MISCREG_EFER, efer);
+ }
}
void
diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc
index 6cec246d1..93df08830 100644
--- a/src/arch/x86/tlb.cc
+++ b/src/arch/x86/tlb.cc
@@ -133,55 +133,98 @@ TLB::demapPage(Addr va)
{
}
+template<class TlbFault>
Fault
-ITB::translate(RequestPtr &req, ThreadContext *tc)
-{
- Addr vaddr = req->getVaddr();
- // Check against the limit of the CS segment, and permissions.
- // The vaddr already has the segment base applied.
- TlbEntry *entry = lookup(vaddr);
- if (!entry) {
-#if FULL_SYSTEM
- return new FakeITLBFault();
-#else
- return new FakeITLBFault(vaddr);
-#endif
- } else {
- Addr paddr = entry->pageStart | (vaddr & mask(12));
- DPRINTF(TLB, "Translated %#x to %#x\n", vaddr, paddr);
- req->setPaddr(paddr);
- }
-
- return NoFault;
-}
-
-Fault
-DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
{
Addr vaddr = req->getVaddr();
+ DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
uint32_t flags = req->getFlags();
bool storeCheck = flags & StoreCheck;
+
int seg = flags & (mask(NUM_SEGMENTREGS));
//XXX Junk code to surpress the warning
if (storeCheck) seg = seg;
- // Check the limit of the segment "seg", and permissions.
- // The vaddr already has the segment base applied.
- TlbEntry *entry = lookup(vaddr);
- if (!entry) {
+ // Get cr0. This will tell us how to do translation. We'll assume it was
+ // verified to be correct and consistent when set.
+ CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0);
+
+ // If protected mode has been enabled...
+ if (cr0.pe) {
+ Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
+ SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR);
+ // If we're not in 64-bit mode, do protection/limit checks
+ if (!efer.lma || !csAttr.longMode) {
+ SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
+ if (!attr.writable && write)
+ return new GeneralProtection(0);
+ if (!attr.readable && !write && !execute)
+ return new GeneralProtection(0);
+ Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg));
+ Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg));
+ if (!attr.expandDown) {
+ // We don't have to worry about the access going around the
+ // end of memory because accesses will be broken up into
+ // pieces at boundaries aligned on sizes smaller than an
+ // entire address space. We do have to worry about the limit
+ // being less than the base.
+ if (limit < base) {
+ if (limit < vaddr + req->getSize() && vaddr < base)
+ return new GeneralProtection(0);
+ } else {
+ if (limit < vaddr + req->getSize())
+ return new GeneralProtection(0);
+ }
+ } else {
+ if (limit < base) {
+ if (vaddr <= limit || vaddr + req->getSize() >= base)
+ return new GeneralProtection(0);
+ } else {
+ if (vaddr <= limit && vaddr + req->getSize() >= base)
+ return new GeneralProtection(0);
+ }
+ }
+ }
+ // If paging is enabled, do the translation.
+ if (cr0.pg) {
+ // The vaddr already has the segment base applied.
+ TlbEntry *entry = lookup(vaddr);
+ if (!entry) {
#if FULL_SYSTEM
- return new FakeDTLBFault();
+ return new TlbFault();
#else
- return new FakeDTLBFault(vaddr);
+ return new TlbFault(vaddr);
#endif
+ } else {
+ // Do paging protection checks.
+ Addr paddr = entry->pageStart | (vaddr & mask(12));
+ req->setPaddr(paddr);
+ }
+ } else {
+ //Use the address which already has segmentation applied.
+ req->setPaddr(vaddr);
+ }
} else {
- Addr paddr = entry->pageStart | (vaddr & mask(12));
- req->setPaddr(paddr);
+ // Real mode
+ req->setPaddr(vaddr);
}
return NoFault;
};
+Fault
+DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+{
+ return TLB::translate<FakeDTLBFault>(req, tc, write, false);
+}
+
+Fault
+ITB::translate(RequestPtr &req, ThreadContext *tc)
+{
+ return TLB::translate<FakeITLBFault>(req, tc, false, true);
+}
+
#if FULL_SYSTEM
Tick
diff --git a/src/arch/x86/tlb.hh b/src/arch/x86/tlb.hh
index 720b03b98..12739379c 100644
--- a/src/arch/x86/tlb.hh
+++ b/src/arch/x86/tlb.hh
@@ -108,6 +108,10 @@ namespace X86ISA
void demapPage(Addr va);
+ template<class TlbFault>
+ Fault translate(RequestPtr &req, ThreadContext *tc,
+ bool write, bool execute);
+
public:
// Checkpointing
virtual void serialize(std::ostream &os);
@@ -134,7 +138,6 @@ namespace X86ISA
DTB(const Params *p) : TLB(p)
{
}
-
Fault translate(RequestPtr &req, ThreadContext *tc, bool write);
#if FULL_SYSTEM
Tick doMmuRegRead(ThreadContext *tc, Packet *pkt);