From 43ecce5fda625e057724d10e087180b02d027ca0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 26 Feb 2008 23:39:53 -0500 Subject: [PATCH] X86: Put in initial implementation of the local APIC. --HG-- extra : convert_revision : 1708a93d96b819e64ed456c75dbb5325ac8114a8 --- src/arch/x86/miscregfile.cc | 164 +++++++++++++++++++++++++++++++++++ src/arch/x86/miscregs.hh | 63 ++++++++++++++ src/arch/x86/mmaped_ipr.hh | 14 ++- src/arch/x86/tlb.cc | 167 ++++++++++++++++++++++++++++++++++-- src/arch/x86/tlb.hh | 7 +- src/arch/x86/utility.cc | 10 +++ 6 files changed, 416 insertions(+), 9 deletions(-) diff --git a/src/arch/x86/miscregfile.cc b/src/arch/x86/miscregfile.cc index 153610e44..3b4dc3407 100644 --- a/src/arch/x86/miscregfile.cc +++ b/src/arch/x86/miscregfile.cc @@ -123,6 +123,84 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg) MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc) { + if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) { + if (miscReg >= MISCREG_APIC_IN_SERVICE(0) && + miscReg <= MISCREG_APIC_IN_SERVICE(15)) { + panic("Local APIC In-Service registers are unimplemented.\n"); + } + if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) && + miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) { + panic("Local APIC Trigger Mode registers are unimplemented.\n"); + } + if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) && + miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) { + panic("Local APIC Interrupt Request registers " + "are unimplemented.\n"); + } + switch (miscReg) { + case MISCREG_APIC_TASK_PRIORITY: + panic("Local APIC Task Priority register unimplemented.\n"); + break; + case MISCREG_APIC_ARBITRATION_PRIORITY: + panic("Local APIC Arbitration Priority register unimplemented.\n"); + break; + case MISCREG_APIC_PROCESSOR_PRIORITY: + panic("Local APIC Processor Priority register unimplemented.\n"); + break; + case MISCREG_APIC_EOI: + panic("Local APIC EOI register unimplemented.\n"); + break; + case MISCREG_APIC_LOGICAL_DESTINATION: + panic("Local APIC Logical Destination register unimplemented.\n"); + break; + case MISCREG_APIC_DESTINATION_FORMAT: + panic("Local APIC Destination Format register unimplemented.\n"); + break; + case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR: + panic("Local APIC Spurious Interrupt Vector" + " register unimplemented.\n"); + break; + case MISCREG_APIC_ERROR_STATUS: + panic("Local APIC Error Status register unimplemented.\n"); + break; + case MISCREG_APIC_INTERRUPT_COMMAND_LOW: + panic("Local APIC Interrupt Command low" + " register unimplemented.\n"); + break; + case MISCREG_APIC_INTERRUPT_COMMAND_HIGH: + panic("Local APIC Interrupt Command high" + " register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_TIMER: + panic("Local APIC LVT Timer register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_THERMAL_SENSOR: + panic("Local APIC LVT Thermal Sensor register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: + panic("Local APIC LVT Performance Monitoring Counters" + " register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_LINT0: + panic("Local APIC LVT LINT0 register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_LINT1: + panic("Local APIC LVT LINT1 register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_ERROR: + panic("Local APIC LVT Error register unimplemented.\n"); + break; + case MISCREG_APIC_INITIAL_COUNT: + panic("Local APIC Initial Count register unimplemented.\n"); + break; + case MISCREG_APIC_CURRENT_COUNT: + panic("Local APIC Current Count register unimplemented.\n"); + break; + case MISCREG_APIC_DIVIDE_COUNT: + panic("Local APIC Divide Count register unimplemented.\n"); + break; + } + } return readRegNoEffect(miscReg); } @@ -143,6 +221,92 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val, ThreadContext * tc) { MiscReg newVal = val; + if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) { + if (miscReg >= MISCREG_APIC_IN_SERVICE(0) && + miscReg <= MISCREG_APIC_IN_SERVICE(15)) { + panic("Local APIC In-Service registers are unimplemented.\n"); + } + if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) && + miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) { + panic("Local APIC Trigger Mode registers are unimplemented.\n"); + } + if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) && + miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) { + panic("Local APIC Interrupt Request registers " + "are unimplemented.\n"); + } + switch (miscReg) { + case MISCREG_APIC_ID: + panic("Local APIC ID register unimplemented.\n"); + break; + case MISCREG_APIC_VERSION: + panic("Local APIC Version register is read only.\n"); + break; + case MISCREG_APIC_TASK_PRIORITY: + panic("Local APIC Task Priority register unimplemented.\n"); + break; + case MISCREG_APIC_ARBITRATION_PRIORITY: + panic("Local APIC Arbitration Priority register unimplemented.\n"); + break; + case MISCREG_APIC_PROCESSOR_PRIORITY: + panic("Local APIC Processor Priority register unimplemented.\n"); + break; + case MISCREG_APIC_EOI: + panic("Local APIC EOI register unimplemented.\n"); + break; + case MISCREG_APIC_LOGICAL_DESTINATION: + panic("Local APIC Logical Destination register unimplemented.\n"); + break; + case MISCREG_APIC_DESTINATION_FORMAT: + panic("Local APIC Destination Format register unimplemented.\n"); + break; + case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR: + panic("Local APIC Spurious Interrupt Vector" + " register unimplemented.\n"); + break; + case MISCREG_APIC_ERROR_STATUS: + panic("Local APIC Error Status register unimplemented.\n"); + break; + case MISCREG_APIC_INTERRUPT_COMMAND_LOW: + panic("Local APIC Interrupt Command low" + " register unimplemented.\n"); + break; + case MISCREG_APIC_INTERRUPT_COMMAND_HIGH: + panic("Local APIC Interrupt Command high" + " register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_TIMER: + panic("Local APIC LVT Timer register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_THERMAL_SENSOR: + panic("Local APIC LVT Thermal Sensor register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: + panic("Local APIC LVT Performance Monitoring Counters" + " register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_LINT0: + panic("Local APIC LVT LINT0 register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_LINT1: + panic("Local APIC LVT LINT1 register unimplemented.\n"); + break; + case MISCREG_APIC_LVT_ERROR: + panic("Local APIC LVT Error register unimplemented.\n"); + break; + case MISCREG_APIC_INITIAL_COUNT: + panic("Local APIC Initial Count register unimplemented.\n"); + break; + case MISCREG_APIC_CURRENT_COUNT: + panic("Local APIC Current Count register unimplemented.\n"); + break; + case MISCREG_APIC_DIVIDE_COUNT: + panic("Local APIC Divide Count register unimplemented.\n"); + break; + } + setRegNoEffect(miscReg, newVal); + return; + } switch(miscReg) { case MISCREG_CR0: diff --git a/src/arch/x86/miscregs.hh b/src/arch/x86/miscregs.hh index 2bf647150..d1016d2a9 100644 --- a/src/arch/x86/miscregs.hh +++ b/src/arch/x86/miscregs.hh @@ -339,6 +339,41 @@ namespace X86ISA //XXX Add "Model-Specific Registers" + MISCREG_APIC_BASE, + + MISCREG_APIC_START, + MISCREG_APIC_ID = MISCREG_APIC_START, + MISCREG_APIC_VERSION, + MISCREG_APIC_TASK_PRIORITY, + MISCREG_APIC_ARBITRATION_PRIORITY, + MISCREG_APIC_PROCESSOR_PRIORITY, + MISCREG_APIC_EOI, + MISCREG_APIC_LOGICAL_DESTINATION, + MISCREG_APIC_DESTINATION_FORMAT, + MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR, + + MISCREG_APIC_IN_SERVICE_BASE, + + MISCREG_APIC_TRIGGER_MODE_BASE = MISCREG_APIC_IN_SERVICE_BASE + 16, + + MISCREG_APIC_INTERRUPT_REQUEST_BASE = + MISCREG_APIC_TRIGGER_MODE_BASE + 16, + + MISCREG_APIC_ERROR_STATUS = MISCREG_APIC_INTERRUPT_REQUEST_BASE + 16, + MISCREG_APIC_INTERRUPT_COMMAND_LOW, + MISCREG_APIC_INTERRUPT_COMMAND_HIGH, + MISCREG_APIC_LVT_TIMER, + MISCREG_APIC_LVT_THERMAL_SENSOR, + MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS, + MISCREG_APIC_LVT_LINT0, + MISCREG_APIC_LVT_LINT1, + MISCREG_APIC_LVT_ERROR, + MISCREG_APIC_INITIAL_COUNT, + MISCREG_APIC_CURRENT_COUNT, + MISCREG_APIC_DIVIDE_COUNT, + MISCREG_APIC_END = MISCREG_APIC_DIVIDE_COUNT, + + // "Fake" MSRs for internally implemented devices MISCREG_PCI_CONFIG_ADDRESS, NUM_MISCREGS @@ -446,6 +481,24 @@ namespace X86ISA return (MiscRegIndex)(MISCREG_SEG_ATTR_BASE + index); } + static inline MiscRegIndex + MISCREG_APIC_IN_SERVICE(int index) + { + return (MiscRegIndex)(MISCREG_APIC_IN_SERVICE_BASE + index); + } + + static inline MiscRegIndex + MISCREG_APIC_TRIGGER_MODE(int index) + { + return (MiscRegIndex)(MISCREG_APIC_TRIGGER_MODE_BASE + index); + } + + static inline MiscRegIndex + MISCREG_APIC_INTERRUPT_REQUEST(int index) + { + return (MiscRegIndex)(MISCREG_APIC_INTERRUPT_REQUEST_BASE + index); + } + /** * A type to describe the condition code bits of the RFLAGS register, * plus two flags, EZF and ECF, which are only visible to microcode. @@ -794,6 +847,16 @@ namespace X86ISA */ BitUnion64(TR) EndBitUnion(TR) + + + /** + * Local APIC Base Register + */ + BitUnion64(LocalApicBase) + Bitfield<51, 12> base; + Bitfield<11> enable; + Bitfield<8> bsp; + EndBitUnion(LocalApicBase) }; #endif // __ARCH_X86_INTREGS_HH__ diff --git a/src/arch/x86/mmaped_ipr.hh b/src/arch/x86/mmaped_ipr.hh index 36c0baaca..eda85c084 100644 --- a/src/arch/x86/mmaped_ipr.hh +++ b/src/arch/x86/mmaped_ipr.hh @@ -78,7 +78,15 @@ namespace X86ISA #if !FULL_SYSTEM panic("Shouldn't have a memory mapped register in SE\n"); #else - pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg))); + MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg)); + if (index == MISCREG_PCI_CONFIG_ADDRESS || + (index >= MISCREG_APIC_START && + index <= MISCREG_APIC_END)) { + pkt->set((uint32_t)(xc->readMiscReg(pkt->getAddr() / + sizeof(MiscReg)))); + } else { + pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg))); + } #endif return xc->getCpuPtr()->ticks(1); } @@ -90,7 +98,9 @@ namespace X86ISA panic("Shouldn't have a memory mapped register in SE\n"); #else MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg)); - if (index == MISCREG_PCI_CONFIG_ADDRESS) { + if (index == MISCREG_PCI_CONFIG_ADDRESS || + (index >= MISCREG_APIC_START && + index <= MISCREG_APIC_END)) { xc->setMiscReg(index, gtoh(pkt->get())); } else { xc->setMiscReg(pkt->getAddr() / sizeof(MiscReg), diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index ae8fcf9be..a87abf212 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -108,8 +108,8 @@ TLB::insert(Addr vpn, TlbEntry &entry) entryList.push_front(newEntry); } -TlbEntry * -TLB::lookup(Addr va, bool update_lru) +TLB::EntryList::iterator +TLB::lookupIt(Addr va, bool update_lru) { //TODO make this smarter at some point EntryList::iterator entry; @@ -117,15 +117,25 @@ TLB::lookup(Addr va, bool update_lru) if ((*entry)->vaddr <= va && (*entry)->vaddr + (*entry)->size > va) { DPRINTF(TLB, "Matched vaddr %#x to entry starting at %#x " "with size %#x.\n", va, (*entry)->vaddr, (*entry)->size); - TlbEntry *e = *entry; if (update_lru) { + entryList.push_front(*entry); entryList.erase(entry); - entryList.push_front(e); + entry = entryList.begin(); } - return e; + break; } } - return NULL; + return entry; +} + +TlbEntry * +TLB::lookup(Addr va, bool update_lru) +{ + EntryList::iterator entry = lookupIt(va, update_lru); + if (entry == entryList.end()) + return NULL; + else + return *entry; } #if FULL_SYSTEM @@ -206,6 +216,9 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) case 0x10: regNum = MISCREG_TSC; break; + case 0x1B: + regNum = MISCREG_APIC_BASE; + break; case 0xFE: regNum = MISCREG_MTRRCAP; break; @@ -578,6 +591,148 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, vaddr); req->setPaddr(vaddr); } + // Check for an access to the local APIC + LocalApicBase localApicBase = tc->readMiscRegNoEffect(MISCREG_APIC_BASE); + Addr baseAddr = localApicBase.base << 12; + Addr paddr = req->getPaddr(); + if (baseAddr <= paddr && baseAddr + (1 << 12) > paddr) { + req->setMmapedIpr(true); + // Check alignment + if (paddr & ((32/8) - 1)) + return new GeneralProtection(0); + // Check access size + if (req->getSize() != (32/8)) + return new GeneralProtection(0); + MiscReg regNum; + switch (paddr - baseAddr) + { + case 0x20: + regNum = MISCREG_APIC_ID; + break; + case 0x30: + regNum = MISCREG_APIC_VERSION; + break; + case 0x80: + regNum = MISCREG_APIC_TASK_PRIORITY; + break; + case 0x90: + regNum = MISCREG_APIC_ARBITRATION_PRIORITY; + break; + case 0xA0: + regNum = MISCREG_APIC_PROCESSOR_PRIORITY; + break; + case 0xB0: + regNum = MISCREG_APIC_EOI; + break; + case 0xD0: + regNum = MISCREG_APIC_LOGICAL_DESTINATION; + break; + case 0xE0: + regNum = MISCREG_APIC_DESTINATION_FORMAT; + break; + case 0xF0: + regNum = MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR; + break; + case 0x100: + case 0x108: + case 0x110: + case 0x118: + case 0x120: + case 0x128: + case 0x130: + case 0x138: + case 0x140: + case 0x148: + case 0x150: + case 0x158: + case 0x160: + case 0x168: + case 0x170: + case 0x178: + regNum = MISCREG_APIC_IN_SERVICE( + (paddr - baseAddr - 0x100) / 0x8); + break; + case 0x180: + case 0x188: + case 0x190: + case 0x198: + case 0x1A0: + case 0x1A8: + case 0x1B0: + case 0x1B8: + case 0x1C0: + case 0x1C8: + case 0x1D0: + case 0x1D8: + case 0x1E0: + case 0x1E8: + case 0x1F0: + case 0x1F8: + regNum = MISCREG_APIC_TRIGGER_MODE( + (paddr - baseAddr - 0x180) / 0x8); + break; + case 0x200: + case 0x208: + case 0x210: + case 0x218: + case 0x220: + case 0x228: + case 0x230: + case 0x238: + case 0x240: + case 0x248: + case 0x250: + case 0x258: + case 0x260: + case 0x268: + case 0x270: + case 0x278: + regNum = MISCREG_APIC_INTERRUPT_REQUEST( + (paddr - baseAddr - 0x200) / 0x8); + break; + case 0x280: + regNum = MISCREG_APIC_ERROR_STATUS; + break; + case 0x300: + regNum = MISCREG_APIC_INTERRUPT_COMMAND_LOW; + break; + case 0x310: + regNum = MISCREG_APIC_INTERRUPT_COMMAND_HIGH; + break; + case 0x320: + regNum = MISCREG_APIC_LVT_TIMER; + break; + case 0x330: + regNum = MISCREG_APIC_LVT_THERMAL_SENSOR; + break; + case 0x340: + regNum = MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; + break; + case 0x350: + regNum = MISCREG_APIC_LVT_LINT0; + break; + case 0x360: + regNum = MISCREG_APIC_LVT_LINT1; + break; + case 0x370: + regNum = MISCREG_APIC_LVT_ERROR; + break; + case 0x380: + regNum = MISCREG_APIC_INITIAL_COUNT; + break; + case 0x390: + regNum = MISCREG_APIC_CURRENT_COUNT; + break; + case 0x3E0: + regNum = MISCREG_APIC_DIVIDE_COUNT; + break; + default: + // A reserved register field. + return new GeneralProtection(0); + break; + } + req->setPaddr(regNum * sizeof(MiscReg)); + } return NoFault; }; diff --git a/src/arch/x86/tlb.hh b/src/arch/x86/tlb.hh index f6ccd5731..89b965e97 100644 --- a/src/arch/x86/tlb.hh +++ b/src/arch/x86/tlb.hh @@ -90,6 +90,8 @@ namespace X86ISA friend class FakeITLBFault; friend class FakeDTLBFault; + typedef std::list EntryList; + bool _allowNX; uint32_t configAddress; @@ -108,6 +110,10 @@ namespace X86ISA void setConfigAddress(uint32_t addr); + protected: + + EntryList::iterator lookupIt(Addr va, bool update_lru = true); + #if FULL_SYSTEM protected: @@ -128,7 +134,6 @@ namespace X86ISA TlbEntry * tlb; - typedef std::list EntryList; EntryList freeList; EntryList entryList; diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index f5e87b860..5fe5bf8c3 100644 --- a/src/arch/x86/utility.cc +++ b/src/arch/x86/utility.cc @@ -248,6 +248,16 @@ void initCPU(ThreadContext *tc, int cpuId) // TODO Turn on the APIC. This should be handled elsewhere but it isn't // currently being handled at all. + LocalApicBase lApicBase = 0; + lApicBase.base = 0xFEE00000 >> 12; + lApicBase.enable = 1; + lApicBase.bsp = (cpuId == 0); + tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); + + tc->setMiscRegNoEffect(MISCREG_APIC_ID, cpuId << 24); + + tc->setMiscRegNoEffect(MISCREG_APIC_VERSION, (5 << 16) | 0x14); + // TODO Set the SMRAM base address (SMBASE) to 0x00030000 tc->setMiscReg(MISCREG_VM_CR, 0);