X86: Work on the x86 tlb.
authorGabe Black <gblack@eecs.umich.edu>
Mon, 8 Oct 2007 01:18:39 +0000 (18:18 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Mon, 8 Oct 2007 01:18:39 +0000 (18:18 -0700)
--HG--
extra : convert_revision : a08a5cb049a6030ba9fd56a89383d56026238dbf

src/arch/x86/process.cc
src/arch/x86/tlb.cc
src/arch/x86/tlb.hh

index 79422998dfb2c47a914af0876ba6247b6913ba56..0193344e8c312b15e3aafa06baa898fadad6ebef 100644 (file)
@@ -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
index 6cec246d1079a93aaae73654cc4d9190d41435d5..93df088307a7b5a9b97e5047ce768390eaf94dd6 100644 (file)
@@ -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
index 720b03b981243b1fef53c8c8e6afc8053ae13bf3..12739379c1c2bc814276a929b75ca71e39ee4ca7 100644 (file)
@@ -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);