diff options
Diffstat (limited to 'src/arch/x86/system.cc')
-rw-r--r-- | src/arch/x86/system.cc | 161 |
1 files changed, 160 insertions, 1 deletions
diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc index 0b770fc83..e0ef5dec0 100644 --- a/src/arch/x86/system.cc +++ b/src/arch/x86/system.cc @@ -55,24 +55,183 @@ * Authors: Gabe Black */ +#include "arch/x86/miscregs.hh" #include "arch/x86/system.hh" #include "arch/vtophys.hh" #include "base/remote_gdb.hh" #include "base/loader/object_file.hh" #include "base/loader/symtab.hh" #include "base/trace.hh" +#include "cpu/thread_context.hh" #include "mem/physical.hh" #include "params/X86System.hh" #include "sim/byteswap.hh" -using namespace BigEndianGuest; +using namespace LittleEndianGuest; +using namespace X86ISA; X86System::X86System(Params *p) : System(p) { } +void +X86System::startup() +{ + System::startup(); + // This is the boot strap processor (BSP). Initialize it to look like + // the boot loader has just turned control over to the 64 bit OS. We + // won't actually set up real mode or legacy protected mode descriptor + // tables because we aren't executing any code that would require + // them. We do, however toggle the control bits in the correct order + // while allowing consistency checks and the underlying mechansims + // just to be safe. + + const int NumPDTs = 4; + + const Addr PageMapLevel4 = 0x70000; + const Addr PageDirPtrTable = 0x71000; + const Addr PageDirTable[NumPDTs] = + {0x72000, 0x73000, 0x74000, 0x75000}; + const Addr GDTBase = 0x76000; + + const int PML4Bits = 9; + const int PDPTBits = 9; + const int PDTBits = 9; + + // Get a port to write the page tables and descriptor tables. + FunctionalPort * physPort = threadContexts[0]->getPhysPort(); + + /* + * Set up the gdt. + */ + // Place holder at selector 0 + uint64_t nullDescriptor = 0; + physPort->writeBlob(GDTBase, (uint8_t *)(&nullDescriptor), 8); + + //64 bit code segment + SegDescriptor csDesc = 0; + csDesc.type.c = 0; // Not conforming + csDesc.dpl = 0; // Privelege level 0 + csDesc.p = 1; // Present + csDesc.l = 1; // 64 bit + csDesc.d = 0; // default operand size + //Because we're dealing with a pointer and I don't think it's + //guaranteed that there isn't anything in a nonvirtual class between + //it's beginning in memory and it's actual data, we'll use an + //intermediary. + uint64_t csDescVal = csDesc; + physPort->writeBlob(GDTBase, (uint8_t *)(&csDescVal), 8); + + threadContexts[0]->setMiscReg(MISCREG_TSG_BASE, GDTBase); + threadContexts[0]->setMiscReg(MISCREG_TSG_LIMIT, 0xF); + + /* + * Identity map the first 4GB of memory. In order to map this region + * of memory in long mode, there needs to be one actual page map level + * 4 entry which points to one page directory pointer table which + * points to 4 different page directory tables which are full of two + * megabyte pages. All of the other entries in valid tables are set + * to indicate that they don't pertain to anything valid and will + * cause a fault if used. + */ + + // Put valid values in all of the various table entries which indicate + // that those entries don't point to further tables or pages. Then + // set the values of those entries which are needed. + + // Page Map Level 4 + + // read/write, user, not present + uint64_t pml4e = X86ISA::htog(0x6); + for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { + physPort->writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); + } + // Point to the only PDPT + pml4e = X86ISA::htog(0x7 | PageDirPtrTable); + physPort->writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); + + // Page Directory Pointer Table + + // read/write, user, not present + uint64_t pdpe = X86ISA::htog(0x6); + for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { + physPort->writeBlob(PageDirPtrTable + offset, + (uint8_t *)(&pdpe), 8); + } + // Point to the PDTs + for (int table = 0; table < NumPDTs; table++) { + pdpe = X86ISA::htog(0x7 | PageDirTable[table]); + physPort->writeBlob(PageDirPtrTable + table * 8, + (uint8_t *)(&pdpe), 8); + } + + // Page Directory Tables + + Addr base = 0; + const Addr pageSize = 2 << 20; + for (int table = 0; table < NumPDTs; table++) { + for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { + // read/write, user, present, 4MB + uint64_t pdte = X86ISA::htog(0x87 | base); + physPort->writeBlob(PageDirTable[table] + offset, + (uint8_t *)(&pdte), 8); + base += pageSize; + } + } + + /* + * Transition from real mode all the way up to Long mode + */ + CR0 cr0 = threadContexts[0]->readMiscRegNoEffect(MISCREG_CR0); + //Turn off paging. + cr0.pg = 0; + threadContexts[0]->setMiscReg(MISCREG_CR0, cr0); + //Turn on protected mode. + cr0.pe = 1; + threadContexts[0]->setMiscReg(MISCREG_CR0, cr0); + + CR4 cr4 = threadContexts[0]->readMiscRegNoEffect(MISCREG_CR4); + //Turn on pae. + cr4.pae = 1; + threadContexts[0]->setMiscReg(MISCREG_CR4, cr4); + + //Point to the page tables. + threadContexts[0]->setMiscReg(MISCREG_CR3, PageMapLevel4); + + Efer efer = threadContexts[0]->readMiscRegNoEffect(MISCREG_EFER); + //Enable long mode. + efer.lme = 1; + threadContexts[0]->setMiscReg(MISCREG_EFER, efer); + + //Activate long mode. + cr0.pg = 1; + threadContexts[0]->setMiscReg(MISCREG_CR0, cr0); + + /* + * Far jump into 64 bit mode. + */ + // Set the selector + threadContexts[0]->setMiscReg(MISCREG_CS, 1); + // Manually set up the segment attributes. In the future when there's + // other existing functionality to do this, that could be used + // instead. + SegAttr csAttr = 0; + csAttr.writable = 0; + csAttr.readable = 1; + csAttr.expandDown = 0; + csAttr.dpl = 0; + csAttr.defaultSize = 0; + csAttr.longMode = 1; + threadContexts[0]->setMiscReg(MISCREG_CS_ATTR, csAttr); + + threadContexts[0]->setPC(threadContexts[0]->getSystemPtr()->kernelEntry); + threadContexts[0]->setNextPC(threadContexts[0]->readPC()); + + // We should now be in long mode. Yay! +} + X86System::~X86System() { } |