diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2007-10-07 18:18:39 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2007-10-07 18:18:39 -0700 |
commit | a19c212757b13e45f481d8612fd38f603250c853 (patch) | |
tree | cbc0abe8e8a9807fecfe6c432735bac7ac3b3fa8 /src | |
parent | cd36c69a4de51d45b82038a012a53cf58f4f3fa2 (diff) | |
download | gem5-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.cc | 56 | ||||
-rw-r--r-- | src/arch/x86/tlb.cc | 105 | ||||
-rw-r--r-- | src/arch/x86/tlb.hh | 5 |
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); |