diff options
Diffstat (limited to 'src/arch/x86/faults.cc')
-rw-r--r-- | src/arch/x86/faults.cc | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc index 7702d98eb..1234e68e5 100644 --- a/src/arch/x86/faults.cc +++ b/src/arch/x86/faults.cc @@ -101,34 +101,67 @@ namespace X86ISA { #if FULL_SYSTEM - void X86Trap::invoke(ThreadContext * tc) - { - panic("X86 faults are not implemented!"); - } - - void X86Abort::invoke(ThreadContext * tc) - { - panic("X86 faults are not implemented!"); - } - - void X86Interrupt::invoke(ThreadContext * tc) + void X86FaultBase::invoke(ThreadContext * tc) { using namespace X86ISAInst::RomLabels; HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); MicroPC entry; if (m5reg.mode == LongMode) { - entry = extern_label_longModeInterrupt; + if (isSoft()) { + entry = extern_label_longModeSoftInterrupt; + } else { + entry = extern_label_longModeInterrupt; + } } else { entry = extern_label_legacyModeInterrupt; } tc->setIntReg(INTREG_MICRO(1), vector); tc->setIntReg(INTREG_MICRO(7), tc->readPC()); if (errorCode != (uint64_t)(-1)) { + if (m5reg.mode == LongMode) { + entry = extern_label_longModeInterruptWithError; + } else { + panic("Legacy mode interrupts with error codes " + "aren't implementde.\n"); + } + // Software interrupts shouldn't have error codes. If one does, + // there would need to be microcode to set it up. + assert(!isSoft()); tc->setIntReg(INTREG_MICRO(15), errorCode); } tc->setMicroPC(romMicroPC(entry)); tc->setNextMicroPC(romMicroPC(entry) + 1); } + + void X86Trap::invoke(ThreadContext * tc) + { + X86FaultBase::invoke(tc); + // This is the same as a fault, but it happens -after- the instruction. + tc->setPC(tc->readNextPC()); + tc->setNextPC(tc->readNextNPC()); + tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst)); + } + + void X86Abort::invoke(ThreadContext * tc) + { + panic("Abort exception!"); + } + + void PageFault::invoke(ThreadContext * tc) + { + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + X86FaultBase::invoke(tc); + /* + * If something bad happens while trying to enter the page fault + * handler, I'm pretty sure that's a double fault and then all bets are + * off. That means it should be safe to update this state now. + */ + if (m5reg.mode == LongMode) { + tc->setMiscReg(MISCREG_CR2, addr); + } else { + tc->setMiscReg(MISCREG_CR2, (uint32_t)addr); + } + } void FakeITLBFault::invoke(ThreadContext * tc) { |