summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2008-02-26 23:39:53 -0500
committerGabe Black <gblack@eecs.umich.edu>2008-02-26 23:39:53 -0500
commit43ecce5fda625e057724d10e087180b02d027ca0 (patch)
tree2984a0315219c95b6aa6d9f06e4ad026e3090514
parent98d2ca403e859f289e6d637a2179e62728370d5f (diff)
downloadgem5-43ecce5fda625e057724d10e087180b02d027ca0.tar.xz
X86: Put in initial implementation of the local APIC.
--HG-- extra : convert_revision : 1708a93d96b819e64ed456c75dbb5325ac8114a8
-rw-r--r--src/arch/x86/miscregfile.cc164
-rw-r--r--src/arch/x86/miscregs.hh63
-rw-r--r--src/arch/x86/mmaped_ipr.hh14
-rw-r--r--src/arch/x86/tlb.cc167
-rw-r--r--src/arch/x86/tlb.hh7
-rw-r--r--src/arch/x86/utility.cc10
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<uint32_t>()));
} 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<TlbEntry *> 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<TlbEntry *> 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);