From 5c1213d63dcf2f86bf64351ac8dfff98d823915c Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 24 Aug 2020 00:53:43 -0700 Subject: [PATCH] x86: Style fixes in x86's fault implementations. Change-Id: I320877a7e753eae5ffba2421e6dfe23b52352664 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/33279 Maintainer: Gabe Black Tested-by: kokoro Reviewed-by: Bobby R. Bruce --- src/arch/x86/faults.cc | 487 +++++++++++++++--------------- src/arch/x86/faults.hh | 653 +++++++++++++++++++---------------------- 2 files changed, 543 insertions(+), 597 deletions(-) diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc index 0754da388..36cc47e43 100644 --- a/src/arch/x86/faults.cc +++ b/src/arch/x86/faults.cc @@ -51,272 +51,269 @@ namespace X86ISA { - void X86FaultBase::invoke(ThreadContext * tc, const StaticInstPtr &inst) - { - if (!FullSystem) { - FaultBase::invoke(tc, inst); - return; - } - PCState pcState = tc->pcState(); - Addr pc = pcState.pc(); - DPRINTF(Faults, "RIP %#x: vector %d: %s\n", - pc, vector, describe()); - using namespace X86ISAInst::RomLabels; - HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); - MicroPC entry; +void +X86FaultBase::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + if (!FullSystem) { + FaultBase::invoke(tc, inst); + return; + } + + PCState pcState = tc->pcState(); + Addr pc = pcState.pc(); + DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc, vector, describe()); + using namespace X86ISAInst::RomLabels; + HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); + MicroPC entry; + if (m5reg.mode == LongMode) { + entry = isSoft() ? extern_label_longModeSoftInterrupt : + extern_label_longModeInterrupt; + } else { + entry = extern_label_legacyModeInterrupt; + } + tc->setIntReg(INTREG_MICRO(1), vector); + tc->setIntReg(INTREG_MICRO(7), pc); + if (errorCode != (uint64_t)(-1)) { if (m5reg.mode == LongMode) { - if (isSoft()) { - entry = extern_label_longModeSoftInterrupt; - } else { - entry = extern_label_longModeInterrupt; - } + entry = extern_label_longModeInterruptWithError; } else { - entry = extern_label_legacyModeInterrupt; + panic("Legacy mode interrupts with error codes " + "aren't implemented."); } - tc->setIntReg(INTREG_MICRO(1), vector); - tc->setIntReg(INTREG_MICRO(7), pc); - 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); - } - pcState.upc(romMicroPC(entry)); - pcState.nupc(romMicroPC(entry) + 1); - tc->pcState(pcState); + // 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); } + pcState.upc(romMicroPC(entry)); + pcState.nupc(romMicroPC(entry) + 1); + tc->pcState(pcState); +} - std::string - X86FaultBase::describe() const - { - std::stringstream ss; - ccprintf(ss, "%s", mnemonic()); - if (errorCode != (uint64_t)(-1)) { - ccprintf(ss, "(%#x)", errorCode); - } - - return ss.str(); - } +std::string +X86FaultBase::describe() const +{ + std::stringstream ss; + ccprintf(ss, "%s", mnemonic()); + if (errorCode != (uint64_t)(-1)) + ccprintf(ss, "(%#x)", errorCode); - void X86Trap::invoke(ThreadContext * tc, const StaticInstPtr &inst) - { - X86FaultBase::invoke(tc); - if (!FullSystem) - return; + return ss.str(); +} - // This is the same as a fault, but it happens -after- the - // instruction. - PCState pc = tc->pcState(); - pc.uEnd(); - } +void +X86Trap::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + X86FaultBase::invoke(tc); + if (!FullSystem) + return; + + // This is the same as a fault, but it happens -after- the + // instruction. + PCState pc = tc->pcState(); + pc.uEnd(); +} + +void +X86Abort::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + panic("Abort exception!"); +} - void X86Abort::invoke(ThreadContext * tc, const StaticInstPtr &inst) - { - panic("Abort exception!"); +void +InvalidOpcode::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + if (FullSystem) { + X86Fault::invoke(tc, inst); + } else { + panic("Unrecognized/invalid instruction executed:\n %s", + inst->machInst); } +} - void - InvalidOpcode::invoke(ThreadContext * tc, const StaticInstPtr &inst) - { - if (FullSystem) { - X86Fault::invoke(tc, inst); +void +PageFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + if (FullSystem) { + // Invalidate any matching TLB entries before handling the page fault. + tc->getITBPtr()->demapPage(addr, 0); + tc->getDTBPtr()->demapPage(addr, 0); + 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); + } else if (!tc->getProcessPtr()->fixupFault(addr)) { + PageFaultErrorCode code = errorCode; + const char *modeStr = ""; + if (code.fetch) + modeStr = "execute"; + else if (code.write) + modeStr = "write"; + else + modeStr = "read"; + + // print information about what we are panic'ing on + if (!inst) { + panic("Tried to %s unmapped address %#x.", modeStr, addr); } else { - panic("Unrecognized/invalid instruction executed:\n %s", - inst->machInst); + panic("Tried to %s unmapped address %#x.\nPC: %#x, Instr: %s", + modeStr, addr, tc->pcState().pc(), + inst->disassemble(tc->pcState().pc(), + &Loader::debugSymbolTable)); } } +} - void PageFault::invoke(ThreadContext * tc, const StaticInstPtr &inst) - { - if (FullSystem) { - /* Invalidate any matching TLB entries before handling the page fault */ - tc->getITBPtr()->demapPage(addr, 0); - tc->getDTBPtr()->demapPage(addr, 0); - 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); - } - } else if (!tc->getProcessPtr()->fixupFault(addr)) { - PageFaultErrorCode code = errorCode; - const char *modeStr = ""; - if (code.fetch) - modeStr = "execute"; - else if (code.write) - modeStr = "write"; - else - modeStr = "read"; - - // print information about what we are panic'ing on - if (!inst) { - panic("Tried to %s unmapped address %#x.\n", modeStr, addr); - } else { - panic("Tried to %s unmapped address %#x.\nPC: %#x, Instr: %s", - modeStr, addr, tc->pcState().pc(), - inst->disassemble(tc->pcState().pc(), - &Loader::debugSymbolTable)); - } - } - } +std::string +PageFault::describe() const +{ + std::stringstream ss; + ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr); + return ss.str(); +} - std::string - PageFault::describe() const - { - std::stringstream ss; - ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr); - return ss.str(); +void +InitInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + DPRINTF(Faults, "Init interrupt.\n"); + // The otherwise unmodified integer registers should be set to 0. + for (int index = 0; index < NUM_INTREGS; index++) { + tc->setIntReg(index, 0); } - void - InitInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst) - { - DPRINTF(Faults, "Init interrupt.\n"); - // The otherwise unmodified integer registers should be set to 0. - for (int index = 0; index < NUM_INTREGS; index++) { - tc->setIntReg(index, 0); - } - - CR0 cr0 = tc->readMiscReg(MISCREG_CR0); - CR0 newCR0 = 1 << 4; - newCR0.cd = cr0.cd; - newCR0.nw = cr0.nw; - tc->setMiscReg(MISCREG_CR0, newCR0); - tc->setMiscReg(MISCREG_CR2, 0); - tc->setMiscReg(MISCREG_CR3, 0); - tc->setMiscReg(MISCREG_CR4, 0); - - tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL); - - tc->setMiscReg(MISCREG_EFER, 0); - - SegAttr dataAttr = 0; - dataAttr.dpl = 0; - dataAttr.unusable = 0; - dataAttr.defaultSize = 0; - dataAttr.longMode = 0; - dataAttr.avl = 0; - dataAttr.granularity = 0; - dataAttr.present = 1; - dataAttr.type = 3; - dataAttr.writable = 1; - dataAttr.readable = 1; - dataAttr.expandDown = 0; - dataAttr.system = 1; - - for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) { - tc->setMiscReg(MISCREG_SEG_SEL(seg), 0); - tc->setMiscReg(MISCREG_SEG_BASE(seg), 0); - tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0); - tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff); - tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr); - } + CR0 cr0 = tc->readMiscReg(MISCREG_CR0); + CR0 newCR0 = 1 << 4; + newCR0.cd = cr0.cd; + newCR0.nw = cr0.nw; + tc->setMiscReg(MISCREG_CR0, newCR0); + tc->setMiscReg(MISCREG_CR2, 0); + tc->setMiscReg(MISCREG_CR3, 0); + tc->setMiscReg(MISCREG_CR4, 0); + + tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL); + + tc->setMiscReg(MISCREG_EFER, 0); + + SegAttr dataAttr = 0; + dataAttr.dpl = 0; + dataAttr.unusable = 0; + dataAttr.defaultSize = 0; + dataAttr.longMode = 0; + dataAttr.avl = 0; + dataAttr.granularity = 0; + dataAttr.present = 1; + dataAttr.type = 3; + dataAttr.writable = 1; + dataAttr.readable = 1; + dataAttr.expandDown = 0; + dataAttr.system = 1; + + for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) { + tc->setMiscReg(MISCREG_SEG_SEL(seg), 0); + tc->setMiscReg(MISCREG_SEG_BASE(seg), 0); + tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0); + tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff); + tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr); + } - SegAttr codeAttr = 0; - codeAttr.dpl = 0; - codeAttr.unusable = 0; - codeAttr.defaultSize = 0; - codeAttr.longMode = 0; - codeAttr.avl = 0; - codeAttr.granularity = 0; - codeAttr.present = 1; - codeAttr.type = 10; - codeAttr.writable = 0; - codeAttr.readable = 1; - codeAttr.expandDown = 0; - codeAttr.system = 1; - - tc->setMiscReg(MISCREG_CS, 0xf000); - tc->setMiscReg(MISCREG_CS_BASE, - 0x00000000ffff0000ULL); - tc->setMiscReg(MISCREG_CS_EFF_BASE, - 0x00000000ffff0000ULL); - // This has the base value pre-added. - tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff); - tc->setMiscReg(MISCREG_CS_ATTR, codeAttr); - - PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE)); - tc->pcState(pc); - - tc->setMiscReg(MISCREG_TSG_BASE, 0); - tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff); - - tc->setMiscReg(MISCREG_IDTR_BASE, 0); - tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff); - - SegAttr tslAttr = 0; - tslAttr.present = 1; - tslAttr.type = 2; // LDT - tc->setMiscReg(MISCREG_TSL, 0); - tc->setMiscReg(MISCREG_TSL_BASE, 0); - tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff); - tc->setMiscReg(MISCREG_TSL_ATTR, tslAttr); - - SegAttr trAttr = 0; - trAttr.present = 1; - trAttr.type = 3; // Busy 16-bit TSS - tc->setMiscReg(MISCREG_TR, 0); - tc->setMiscReg(MISCREG_TR_BASE, 0); - tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff); - tc->setMiscReg(MISCREG_TR_ATTR, trAttr); - - // This value should be the family/model/stepping of the processor. - // (page 418). It should be consistent with the value from CPUID, but - // the actual value probably doesn't matter much. - tc->setIntReg(INTREG_RDX, 0); - - tc->setMiscReg(MISCREG_DR0, 0); - tc->setMiscReg(MISCREG_DR1, 0); - tc->setMiscReg(MISCREG_DR2, 0); - tc->setMiscReg(MISCREG_DR3, 0); - - tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL); - tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL); - - tc->setMiscReg(MISCREG_MXCSR, 0x1f80); - - // Flag all elements on the x87 stack as empty. - tc->setMiscReg(MISCREG_FTW, 0xFFFF); - - // Update the handy M5 Reg. - tc->setMiscReg(MISCREG_M5_REG, 0); - MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt; - pc.upc(romMicroPC(entry)); - pc.nupc(romMicroPC(entry) + 1); - tc->pcState(pc); + SegAttr codeAttr = 0; + codeAttr.dpl = 0; + codeAttr.unusable = 0; + codeAttr.defaultSize = 0; + codeAttr.longMode = 0; + codeAttr.avl = 0; + codeAttr.granularity = 0; + codeAttr.present = 1; + codeAttr.type = 10; + codeAttr.writable = 0; + codeAttr.readable = 1; + codeAttr.expandDown = 0; + codeAttr.system = 1; + + tc->setMiscReg(MISCREG_CS, 0xf000); + tc->setMiscReg(MISCREG_CS_BASE, + 0x00000000ffff0000ULL); + tc->setMiscReg(MISCREG_CS_EFF_BASE, + 0x00000000ffff0000ULL); + // This has the base value pre-added. + tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff); + tc->setMiscReg(MISCREG_CS_ATTR, codeAttr); + + PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE)); + tc->pcState(pc); + + tc->setMiscReg(MISCREG_TSG_BASE, 0); + tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff); + + tc->setMiscReg(MISCREG_IDTR_BASE, 0); + tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff); + + SegAttr tslAttr = 0; + tslAttr.present = 1; + tslAttr.type = 2; // LDT + tc->setMiscReg(MISCREG_TSL, 0); + tc->setMiscReg(MISCREG_TSL_BASE, 0); + tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff); + tc->setMiscReg(MISCREG_TSL_ATTR, tslAttr); + + SegAttr trAttr = 0; + trAttr.present = 1; + trAttr.type = 3; // Busy 16-bit TSS + tc->setMiscReg(MISCREG_TR, 0); + tc->setMiscReg(MISCREG_TR_BASE, 0); + tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff); + tc->setMiscReg(MISCREG_TR_ATTR, trAttr); + + // This value should be the family/model/stepping of the processor. + // (page 418). It should be consistent with the value from CPUID, but + // the actual value probably doesn't matter much. + tc->setIntReg(INTREG_RDX, 0); + + tc->setMiscReg(MISCREG_DR0, 0); + tc->setMiscReg(MISCREG_DR1, 0); + tc->setMiscReg(MISCREG_DR2, 0); + tc->setMiscReg(MISCREG_DR3, 0); + + tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL); + tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL); + + tc->setMiscReg(MISCREG_MXCSR, 0x1f80); + + // Flag all elements on the x87 stack as empty. + tc->setMiscReg(MISCREG_FTW, 0xFFFF); + + // Update the handy M5 Reg. + tc->setMiscReg(MISCREG_M5_REG, 0); + MicroPC entry = X86ISAInst::RomLabels::extern_label_initIntHalt; + pc.upc(romMicroPC(entry)); + pc.nupc(romMicroPC(entry) + 1); + tc->pcState(pc); +} + +void +StartupInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst) +{ + DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector); + HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG); + if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) { + panic("Startup IPI recived outside of real mode. " + "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode); } - void - StartupInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst) - { - DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector); - HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG); - if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) { - panic("Startup IPI recived outside of real mode. " - "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode); - } + tc->setMiscReg(MISCREG_CS, vector << 8); + tc->setMiscReg(MISCREG_CS_BASE, vector << 12); + tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12); + // This has the base value pre-added. + tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff); - tc->setMiscReg(MISCREG_CS, vector << 8); - tc->setMiscReg(MISCREG_CS_BASE, vector << 12); - tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12); - // This has the base value pre-added. - tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff); + tc->pcState(tc->readMiscReg(MISCREG_CS_BASE)); +} - tc->pcState(tc->readMiscReg(MISCREG_CS_BASE)); - } } // namespace X86ISA - diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh index 0721865be..7dfd36c2b 100644 --- a/src/arch/x86/faults.hh +++ b/src/arch/x86/faults.hh @@ -47,385 +47,334 @@ namespace X86ISA { - // Base class for all x86 "faults" where faults is in the m5 sense - class X86FaultBase : public FaultBase - { - protected: - const char * faultName; - const char * mnem; - uint8_t vector; - uint64_t errorCode; - - X86FaultBase(const char * _faultName, const char * _mnem, - const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1) - : faultName(_faultName), mnem(_mnem), - vector(_vector), errorCode(_errorCode) - { - } - - const char * name() const - { - return faultName; - } - - virtual bool isBenign() - { - return true; - } - - virtual const char * mnemonic() const - { - return mnem; - } - - virtual bool isSoft() - { - return false; - } - - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - - virtual std::string describe() const; - - public: - /** - * Get the vector of an interrupt. - * - * @return interrupt vector number. - */ - virtual uint8_t getVector() const { return vector; } - }; - - // Base class for x86 faults which behave as if the underlying instruction - // didn't happen. - class X86Fault : public X86FaultBase - { - protected: - X86Fault(const char * name, const char * mnem, - const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) - : X86FaultBase(name, mnem, vector, _errorCode) - {} - }; - - // Base class for x86 traps which behave as if the underlying instruction - // completed. - class X86Trap : public X86FaultBase - { - protected: - X86Trap(const char * name, const char * mnem, - const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) - : X86FaultBase(name, mnem, vector, _errorCode) - {} - - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - }; - - // Base class for x86 aborts which seem to be catastrophic failures. - class X86Abort : public X86FaultBase - { - protected: - X86Abort(const char * name, const char * mnem, - const uint8_t vector, uint64_t _errorCode = (uint64_t)-1) - : X86FaultBase(name, mnem, vector, _errorCode) - {} - - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - }; - - // Base class for x86 interrupts. - class X86Interrupt : public X86FaultBase - { - protected: - X86Interrupt(const char * name, const char * mnem, - const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1) - : X86FaultBase(name, mnem, _vector, _errorCode) - {} - }; - - class UnimpInstFault : public FaultBase - { - public: - const char * name() const - { - return "unimplemented_micro"; - } - - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr) - { - panic("Unimplemented instruction!"); - } - }; - - // Below is a summary of the interrupt/exception information in the - // architecture manuals. - - // Class | Type | vector | Cause | mnem - //------------------------------------------------------------------------ - //Contrib Fault 0 Divide Error #DE - //Benign Either 1 Debug #DB - //Benign Interrupt 2 Non-Maskable-Interrupt #NMI - //Benign Trap 3 Breakpoint #BP - //Benign Trap 4 Overflow #OF - //Benign Fault 5 Bound-Range #BR - //Benign Fault 6 Invalid-Opcode #UD - //Benign Fault 7 Device-Not-Available #NM - //Benign Abort 8 Double-Fault #DF - // 9 Coprocessor-Segment-Overrun - //Contrib Fault 10 Invalid-TSS #TS - //Contrib Fault 11 Segment-Not-Present #NP - //Contrib Fault 12 Stack #SS - //Contrib Fault 13 General-Protection #GP - //Either Fault 14 Page-Fault #PF - // 15 Reserved - //Benign Fault 16 x87 Floating-Point Exception Pending #MF - //Benign Fault 17 Alignment-Check #AC - //Benign Abort 18 Machine-Check #MC - //Benign Fault 19 SIMD Floating-Point #XF - // 20-29 Reserved - //Contrib ? 30 Security Exception #SX - // 31 Reserved - //Benign Interrupt 0-255 External Interrupts #INTR - //Benign Interrupt 0-255 Software Interrupts INTn - - // Note that - class DivideError : public X86Fault - { - public: - DivideError() : - X86Fault("Divide-Error", "#DE", 0) - {} - }; - class DebugException : public X86FaultBase - { - public: - DebugException() : - X86FaultBase("Debug", "#DB", 1) - {} - }; +// Base class for all x86 "faults" where faults is in the m5 sense +class X86FaultBase : public FaultBase +{ + protected: + const char *faultName; + const char *mnem; + uint8_t vector; + uint64_t errorCode; + + X86FaultBase(const char *_faultName, const char *_mnem, + const uint8_t _vector, uint64_t _errorCode=(uint64_t)-1) : + faultName(_faultName), mnem(_mnem), + vector(_vector), errorCode(_errorCode) + {} + + const char *name() const override { return faultName; } + virtual bool isBenign() { return true; } + virtual const char *mnemonic() const { return mnem; } + virtual bool isSoft() { return false; } + + void invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr) override; + + virtual std::string describe() const; + + public: + /** + * Get the vector of an interrupt. + * + * @return interrupt vector number. + */ + virtual uint8_t getVector() const { return vector; } +}; + +// Base class for x86 faults which behave as if the underlying instruction +// didn't happen. +class X86Fault : public X86FaultBase +{ + protected: + using X86FaultBase::X86FaultBase; +}; - class NonMaskableInterrupt : public X86Interrupt - { - public: - NonMaskableInterrupt(uint8_t _vector) : - X86Interrupt("Non Maskable Interrupt", "#NMI", 2, _vector) - {} - }; +// Base class for x86 traps which behave as if the underlying instruction +// completed. +class X86Trap : public X86FaultBase +{ + protected: + using X86FaultBase::X86FaultBase; - class Breakpoint : public X86Trap - { - public: - Breakpoint() : - X86Trap("Breakpoint", "#BP", 3) - {} - }; + void invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr) override; +}; - class OverflowTrap : public X86Trap - { - public: - OverflowTrap() : - X86Trap("Overflow", "#OF", 4) - {} - }; +// Base class for x86 aborts which seem to be catastrophic failures. +class X86Abort : public X86FaultBase +{ + protected: + using X86FaultBase::X86FaultBase; + + void invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr) override; +}; + +// Base class for x86 interrupts. +class X86Interrupt : public X86FaultBase +{ + protected: + using X86FaultBase::X86FaultBase; +}; - class BoundRange : public X86Fault +class UnimpInstFault : public FaultBase +{ + public: + const char * + name() const override { - public: - BoundRange() : - X86Fault("Bound-Range", "#BR", 5) - {} - }; + return "unimplemented_micro"; + } - class InvalidOpcode : public X86Fault + void + invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr) override { - public: - InvalidOpcode() : - X86Fault("Invalid-Opcode", "#UD", 6) - {} + panic("Unimplemented instruction!"); + } +}; + +// Below is a summary of the interrupt/exception information in the +// architecture manuals. + +// Class | Type | vector | Cause | mnem +//------------------------------------------------------------------------ +//Contrib Fault 0 Divide Error #DE +//Benign Either 1 Debug #DB +//Benign Interrupt 2 Non-Maskable-Interrupt #NMI +//Benign Trap 3 Breakpoint #BP +//Benign Trap 4 Overflow #OF +//Benign Fault 5 Bound-Range #BR +//Benign Fault 6 Invalid-Opcode #UD +//Benign Fault 7 Device-Not-Available #NM +//Benign Abort 8 Double-Fault #DF +// 9 Coprocessor-Segment-Overrun +//Contrib Fault 10 Invalid-TSS #TS +//Contrib Fault 11 Segment-Not-Present #NP +//Contrib Fault 12 Stack #SS +//Contrib Fault 13 General-Protection #GP +//Either Fault 14 Page-Fault #PF +// 15 Reserved +//Benign Fault 16 x87 Floating-Point Exception Pending #MF +//Benign Fault 17 Alignment-Check #AC +//Benign Abort 18 Machine-Check #MC +//Benign Fault 19 SIMD Floating-Point #XF +// 20-29 Reserved +//Contrib ? 30 Security Exception #SX +// 31 Reserved +//Benign Interrupt 0-255 External Interrupts #INTR +//Benign Interrupt 0-255 Software Interrupts INTn + +// Note that +class DivideError : public X86Fault +{ + public: + DivideError() : X86Fault("Divide-Error", "#DE", 0) {} +}; - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - }; +class DebugException : public X86FaultBase +{ + public: + DebugException() : X86FaultBase("Debug", "#DB", 1) {} +}; - class DeviceNotAvailable : public X86Fault - { - public: - DeviceNotAvailable() : - X86Fault("Device-Not-Available", "#NM", 7) - {} - }; +class NonMaskableInterrupt : public X86Interrupt +{ + public: + NonMaskableInterrupt(uint8_t _vector) : + X86Interrupt("Non Maskable Interrupt", "#NMI", 2, _vector) + {} +}; - class DoubleFault : public X86Abort - { - public: - DoubleFault() : - X86Abort("Double-Fault", "#DF", 8, 0) - {} - }; +class Breakpoint : public X86Trap +{ + public: + Breakpoint() : X86Trap("Breakpoint", "#BP", 3) {} +}; - class InvalidTSS : public X86Fault - { - public: - InvalidTSS(uint32_t _errorCode) : - X86Fault("Invalid-TSS", "#TS", 10, _errorCode) - {} - }; +class OverflowTrap : public X86Trap +{ + public: + OverflowTrap() : X86Trap("Overflow", "#OF", 4) {} +}; - class SegmentNotPresent : public X86Fault - { - public: - SegmentNotPresent(uint32_t _errorCode) : - X86Fault("Segment-Not-Present", "#NP", 11, _errorCode) - {} - }; +class BoundRange : public X86Fault +{ + public: + BoundRange() : X86Fault("Bound-Range", "#BR", 5) {} +}; - class StackFault : public X86Fault - { - public: - StackFault(uint32_t _errorCode) : - X86Fault("Stack", "#SS", 12, _errorCode) - {} - }; +class InvalidOpcode : public X86Fault +{ + public: + InvalidOpcode() : X86Fault("Invalid-Opcode", "#UD", 6) {} - class GeneralProtection : public X86Fault - { - public: - GeneralProtection(uint32_t _errorCode) : - X86Fault("General-Protection", "#GP", 13, _errorCode) - {} - }; + void invoke(ThreadContext *tc, const StaticInstPtr &inst = + StaticInst::nullStaticInstPtr) override; +}; - class PageFault : public X86Fault - { - protected: - BitUnion32(PageFaultErrorCode) - Bitfield<0> present; - Bitfield<1> write; - Bitfield<2> user; - Bitfield<3> reserved; - Bitfield<4> fetch; - EndBitUnion(PageFaultErrorCode) - - Addr addr; - - public: - PageFault(Addr _addr, uint32_t _errorCode) : - X86Fault("Page-Fault", "#PF", 14, _errorCode), addr(_addr) - {} - - PageFault(Addr _addr, bool present, BaseTLB::Mode mode, - bool user, bool reserved) : - X86Fault("Page-Fault", "#PF", 14, 0), addr(_addr) - { - PageFaultErrorCode code = 0; - code.present = present; - code.write = (mode == BaseTLB::Write); - code.user = user; - code.reserved = reserved; - code.fetch = (mode == BaseTLB::Execute); - errorCode = code; - } - - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - - virtual std::string describe() const; - }; - - class X87FpExceptionPending : public X86Fault - { - public: - X87FpExceptionPending() : - X86Fault("x87 Floating-Point Exception Pending", "#MF", 16) - {} - }; +class DeviceNotAvailable : public X86Fault +{ + public: + DeviceNotAvailable() : X86Fault("Device-Not-Available", "#NM", 7) {} +}; - class AlignmentCheck : public X86Fault - { - public: - AlignmentCheck() : - X86Fault("Alignment-Check", "#AC", 17, 0) - {} - }; +class DoubleFault : public X86Abort +{ + public: + DoubleFault() : X86Abort("Double-Fault", "#DF", 8, 0) {} +}; - class MachineCheck : public X86Abort - { - public: - MachineCheck() : - X86Abort("Machine-Check", "#MC", 18) - {} - }; +class InvalidTSS : public X86Fault +{ + public: + InvalidTSS(uint32_t _errorCode) : + X86Fault("Invalid-TSS", "#TS", 10, _errorCode) + {} +}; - class SIMDFloatingPointFault : public X86Fault - { - public: - SIMDFloatingPointFault() : - X86Fault("SIMD Floating-Point", "#XF", 19) - {} - }; +class SegmentNotPresent : public X86Fault +{ + public: + SegmentNotPresent(uint32_t _errorCode) : + X86Fault("Segment-Not-Present", "#NP", 11, _errorCode) + {} +}; - class SecurityException : public X86FaultBase - { - public: - SecurityException() : - X86FaultBase("Security Exception", "#SX", 30) - {} - }; +class StackFault : public X86Fault +{ + public: + StackFault(uint32_t _errorCode) : X86Fault("Stack", "#SS", 12, _errorCode) + {} +}; - class ExternalInterrupt : public X86Interrupt - { - public: - ExternalInterrupt(uint8_t _vector) : - X86Interrupt("External Interrupt", "#INTR", _vector) - {} - }; +class GeneralProtection : public X86Fault +{ + public: + GeneralProtection(uint32_t _errorCode) : + X86Fault("General-Protection", "#GP", 13, _errorCode) + {} +}; - class SystemManagementInterrupt : public X86Interrupt +class PageFault : public X86Fault +{ + protected: + BitUnion32(PageFaultErrorCode) + Bitfield<0> present; + Bitfield<1> write; + Bitfield<2> user; + Bitfield<3> reserved; + Bitfield<4> fetch; + EndBitUnion(PageFaultErrorCode) + + Addr addr; + + public: + PageFault(Addr _addr, uint32_t _errorCode) : + X86Fault("Page-Fault", "#PF", 14, _errorCode), addr(_addr) + {} + + PageFault(Addr _addr, bool present, BaseTLB::Mode mode, + bool user, bool reserved) : + X86Fault("Page-Fault", "#PF", 14, 0), addr(_addr) { - public: - SystemManagementInterrupt() : - X86Interrupt("System Management Interrupt", "#SMI", 0) - {} - }; + PageFaultErrorCode code = 0; + code.present = present; + code.write = (mode == BaseTLB::Write); + code.user = user; + code.reserved = reserved; + code.fetch = (mode == BaseTLB::Execute); + errorCode = code; + } + + void + invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr); + + virtual std::string describe() const; +}; + +class X87FpExceptionPending : public X86Fault +{ + public: + X87FpExceptionPending() : + X86Fault("x87 Floating-Point Exception Pending", "#MF", 16) + {} +}; - class InitInterrupt : public X86Interrupt - { - public: - InitInterrupt(uint8_t _vector) : - X86Interrupt("INIT Interrupt", "#INIT", _vector) - {} +class AlignmentCheck : public X86Fault +{ + public: + AlignmentCheck() : X86Fault("Alignment-Check", "#AC", 17, 0) {} +}; - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - }; +class MachineCheck : public X86Abort +{ + public: + MachineCheck() : X86Abort("Machine-Check", "#MC", 18) {} +}; - class StartupInterrupt : public X86Interrupt - { - public: - StartupInterrupt(uint8_t _vector) : - X86Interrupt("Startup Interrupt", "#SIPI", _vector) - {} +class SIMDFloatingPointFault : public X86Fault +{ + public: + SIMDFloatingPointFault() : X86Fault("SIMD Floating-Point", "#XF", 19) {} +}; - void invoke(ThreadContext * tc, const StaticInstPtr &inst = - StaticInst::nullStaticInstPtr); - }; +class SecurityException : public X86FaultBase +{ + public: + SecurityException() : X86FaultBase("Security Exception", "#SX", 30) {} +}; - class SoftwareInterrupt : public X86Interrupt - { - public: - SoftwareInterrupt(uint8_t _vector) : - X86Interrupt("Software Interrupt", "#INTR", _vector) - {} - - bool isSoft() - { - return true; - } - }; -} +class ExternalInterrupt : public X86Interrupt +{ + public: + ExternalInterrupt(uint8_t _vector) : + X86Interrupt("External Interrupt", "#INTR", _vector) + {} +}; + +class SystemManagementInterrupt : public X86Interrupt +{ + public: + SystemManagementInterrupt() : + X86Interrupt("System Management Interrupt", "#SMI", 0) + {} +}; + +class InitInterrupt : public X86Interrupt +{ + public: + InitInterrupt(uint8_t _vector) : + X86Interrupt("INIT Interrupt", "#INIT", _vector) + {} + + void invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr) override; +}; + +class StartupInterrupt : public X86Interrupt +{ + public: + StartupInterrupt(uint8_t _vector) : + X86Interrupt("Startup Interrupt", "#SIPI", _vector) + {} + + void invoke(ThreadContext *tc, const StaticInstPtr &inst= + StaticInst::nullStaticInstPtr) override; +}; + +class SoftwareInterrupt : public X86Interrupt +{ + public: + SoftwareInterrupt(uint8_t _vector) : + X86Interrupt("Software Interrupt", "#INTR", _vector) + {} + + bool isSoft() override { return true; } +}; + +} // namespace X86ISA #endif // __ARCH_X86_FAULTS_HH__ -- 2.30.2