changeset e8abda6e0980 in /z/repo/m5
details: http://repo.m5sim.org/m5?cmd=changeset;node=e8abda6e0980
description:
X86: Make the local APIC accessible through the memory system directly,
and make the timer work.
diffstat:
7 files changed, 3 insertions(+), 10 deletions(-)
src/arch/x86/interrupts.cc | 1 +
src/arch/x86/miscregfile.cc | 3 ---
src/arch/x86/mmaped_ipr.hh | 2 --
src/arch/x86/tlb.cc | 2 +-
src/arch/x86/utility.cc | 1 +
src/arch/x86/x86_traits.hh | 2 --
src/cpu/BaseCPU.py | 2 --
diffs (truncated from 673 to 300 lines):
diff -r b06b49498c79 -r e8abda6e0980 src/arch/x86/interrupts.cc
--- a/src/arch/x86/interrupts.cc Sun Oct 12 09:09:56 2008 -0700
+++ b/src/arch/x86/interrupts.cc Sun Oct 12 11:08:00 2008 -0700
@@ -55,10 +55,12 @@
* Authors: Gabe Black
*/
+#include "arch/x86/apicregs.hh"
#include "arch/x86/interrupts.hh"
#include "cpu/base.hh"
-int divideFromConf(uint32_t conf)
+int
+divideFromConf(uint32_t conf)
{
// This figures out what division we want from the division configuration
// register in the local APIC. The encoding is a little odd but it can
@@ -68,14 +70,171 @@
return 1 << shift;
}
-uint32_t
-X86ISA::Interrupts::readRegNoEffect(ApicRegIndex reg)
+namespace X86ISA
{
- return regs[reg];
+
+ApicRegIndex
+decodeAddr(Addr paddr)
+{
+ ApicRegIndex regNum;
+ paddr &= ~mask(3);
+ switch (paddr)
+ {
+ case 0x20:
+ regNum = APIC_ID;
+ break;
+ case 0x30:
+ regNum = APIC_VERSION;
+ break;
+ case 0x80:
+ regNum = APIC_TASK_PRIORITY;
+ break;
+ case 0x90:
+ regNum = APIC_ARBITRATION_PRIORITY;
+ break;
+ case 0xA0:
+ regNum = APIC_PROCESSOR_PRIORITY;
+ break;
+ case 0xB0:
+ regNum = APIC_EOI;
+ break;
+ case 0xD0:
+ regNum = APIC_LOGICAL_DESTINATION;
+ break;
+ case 0xE0:
+ regNum = APIC_DESTINATION_FORMAT;
+ break;
+ case 0xF0:
+ regNum = 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 = APIC_IN_SERVICE((paddr - 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 = APIC_TRIGGER_MODE((paddr - 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 = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
+ break;
+ case 0x280:
+ regNum = APIC_ERROR_STATUS;
+ break;
+ case 0x300:
+ regNum = APIC_INTERRUPT_COMMAND_LOW;
+ break;
+ case 0x310:
+ regNum = APIC_INTERRUPT_COMMAND_HIGH;
+ break;
+ case 0x320:
+ regNum = APIC_LVT_TIMER;
+ break;
+ case 0x330:
+ regNum = APIC_LVT_THERMAL_SENSOR;
+ break;
+ case 0x340:
+ regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
+ break;
+ case 0x350:
+ regNum = APIC_LVT_LINT0;
+ break;
+ case 0x360:
+ regNum = APIC_LVT_LINT1;
+ break;
+ case 0x370:
+ regNum = APIC_LVT_ERROR;
+ break;
+ case 0x380:
+ regNum = APIC_INITIAL_COUNT;
+ break;
+ case 0x390:
+ regNum = APIC_CURRENT_COUNT;
+ break;
+ case 0x3E0:
+ regNum = APIC_DIVIDE_CONFIGURATION;
+ break;
+ default:
+ // A reserved register field.
+ panic("Accessed reserved register field %#x.\n", paddr);
+ break;
+ }
+ return regNum;
+}
+}
+
+Tick
+X86ISA::Interrupts::read(PacketPtr pkt)
+{
+ Addr offset = pkt->getAddr() - pioAddr;
+ //Make sure we're at least only accessing one register.
+ if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
+ panic("Accessed more than one register at a time in the APIC!\n");
+ ApicRegIndex reg = decodeAddr(offset);
+ uint32_t val = htog(readReg(reg));
+ pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
+ return latency;
+}
+
+Tick
+X86ISA::Interrupts::write(PacketPtr pkt)
+{
+ Addr offset = pkt->getAddr() - pioAddr;
+ //Make sure we're at least only accessing one register.
+ if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
+ panic("Accessed more than one register at a time in the APIC!\n");
+ ApicRegIndex reg = decodeAddr(offset);
+ uint32_t val = regs[reg];
+ pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
+ setReg(reg, gtoh(val));
+ return latency;
}
uint32_t
-X86ISA::Interrupts::readReg(ApicRegIndex reg, ThreadContext * tc)
+X86ISA::Interrupts::readReg(ApicRegIndex reg)
{
if (reg >= APIC_TRIGGER_MODE(0) &&
reg <= APIC_TRIGGER_MODE(15)) {
@@ -104,24 +263,19 @@
break;
case APIC_CURRENT_COUNT:
{
- uint32_t val = regs[reg] - tc->getCpuPtr()->curCycle();
+ assert(clock);
+ uint32_t val = regs[reg] - curTick / clock;
val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
return val;
}
default:
break;
}
- return readRegNoEffect(reg);
+ return regs[reg];
}
void
-X86ISA::Interrupts::setRegNoEffect(ApicRegIndex reg, uint32_t val)
-{
- regs[reg] = val;
-}
-
-void
-X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val, ThreadContext *tc)
+X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
{
uint32_t newVal = val;
if (reg >= APIC_IN_SERVICE(0) &&
@@ -201,11 +355,24 @@
}
break;
case APIC_INITIAL_COUNT:
- newVal = bits(val, 31, 0);
- regs[APIC_CURRENT_COUNT] =
- tc->getCpuPtr()->curCycle() +
- (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])) * newVal;
- //FIXME This should schedule the timer event.
+ {
+ assert(clock);
+ newVal = bits(val, 31, 0);
+ uint32_t newCount = newVal *
+ (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16);
+ regs[APIC_CURRENT_COUNT] = newCount + curTick / clock;
+ // Find out how long a "tick" of the timer should take.
+ Tick timerTick = 16 * clock;
+ // Schedule on the edge of the next tick plus the new count.
+ Tick offset = curTick % timerTick;
+ if (offset) {
+ reschedule(apicTimerEvent,
+ curTick + (newCount + 1) * timerTick - offset, true);
+ } else {
+ reschedule(apicTimerEvent,
+ curTick + newCount * timerTick, true);
+ }
+ }
break;
case APIC_CURRENT_COUNT:
//Local APIC Current Count register is read only.
@@ -216,7 +383,7 @@
default:
break;
}
- setRegNoEffect(reg, newVal);
+ regs[reg] = newVal;
return;
}
diff -r b06b49498c79 -r e8abda6e0980 src/arch/x86/interrupts.hh
--- a/src/arch/x86/interrupts.hh Sun Oct 12 09:09:56 2008 -0700
+++ b/src/arch/x86/interrupts.hh Sun Oct 12 11:08:00 2008 -0700
@@ -61,6 +61,7 @@
#include "arch/x86/apicregs.hh"
#include "arch/x86/faults.hh"
#include "cpu/thread_context.hh"
+#include "dev/io_device.hh"
#include "params/X86LocalApic.hh"
#include "sim/eventq.hh"
#include "sim/sim_object.hh"
@@ -70,10 +71,12 @@
namespace X86ISA
{
-class Interrupts : public SimObject
+class Interrupts : public BasicPioDevice
{
protected:
uint32_t regs[NUM_APIC_REGS];
+ Tick latency;
+ Tick clock;
class ApicTimerEvent : public Event
{
@@ -92,20 +95,38 @@
public:
typedef X86LocalApicParams Params;
+ void setClock(Tick newClock)
+ {
+ clock = newClock;
+ }
+
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev