| /* |
| * Copyright (c) 2003-2005 The Regents of The University of Michigan |
| * Copyright (c) 2007 MIPS Technologies, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef __MIPS_FAULTS_HH__ |
| #define __MIPS_FAULTS_HH__ |
| |
| #include "arch/mips/pra_constants.hh" |
| #include "arch/mips/regs/misc.hh" |
| #include "cpu/null_static_inst.hh" |
| #include "cpu/thread_context.hh" |
| #include "debug/MipsPRA.hh" |
| #include "sim/faults.hh" |
| #include "sim/full_system.hh" |
| |
| namespace gem5 |
| { |
| |
| namespace MipsISA |
| { |
| |
| typedef Addr FaultVect; |
| |
| enum ExcCode |
| { |
| // A dummy value to use when the code isn't defined or doesn't matter. |
| ExcCodeDummy = 0, |
| |
| ExcCodeInt = 0, |
| ExcCodeMod = 1, |
| ExcCodeTlbL = 2, |
| ExcCodeTlbS = 3, |
| ExcCodeAdEL = 4, |
| ExcCodeAdES = 5, |
| ExcCodeIBE = 6, |
| ExcCodeDBE = 7, |
| ExcCodeSys = 8, |
| ExcCodeBp = 9, |
| ExcCodeRI = 10, |
| ExcCodeCpU = 11, |
| ExcCodeOv = 12, |
| ExcCodeTr = 13, |
| ExcCodeC2E = 18, |
| ExcCodeMDMX = 22, |
| ExcCodeWatch = 23, |
| ExcCodeMCheck = 24, |
| ExcCodeThread = 25, |
| ExcCodeCacheErr = 30 |
| }; |
| |
| class MipsFaultBase : public FaultBase |
| { |
| public: |
| struct FaultVals |
| { |
| const FaultName name; |
| const FaultVect offset; |
| const ExcCode code; |
| }; |
| |
| void setExceptionState(ThreadContext *, uint8_t); |
| |
| virtual FaultVect offset(ThreadContext *tc) const = 0; |
| virtual ExcCode code() const = 0; |
| virtual FaultVect base(ThreadContext *tc) const |
| { |
| StatusReg status = tc->readMiscReg(misc_reg::Status); |
| if (!status.bev) |
| return tc->readMiscReg(misc_reg::Ebase); |
| else |
| return 0xbfc00200; |
| } |
| |
| FaultVect |
| vect(ThreadContext *tc) const |
| { |
| return base(tc) + offset(tc); |
| } |
| |
| void invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr); |
| }; |
| |
| template <typename T> |
| class MipsFault : public MipsFaultBase |
| { |
| protected: |
| static FaultVals vals; |
| public: |
| FaultName name() const { return vals.name; } |
| FaultVect offset(ThreadContext *tc) const { return vals.offset; } |
| ExcCode code() const { return vals.code; } |
| }; |
| |
| class SystemCallFault : public MipsFault<SystemCallFault> {}; |
| class ReservedInstructionFault : public MipsFault<ReservedInstructionFault> {}; |
| class ThreadFault : public MipsFault<ThreadFault> {}; |
| class IntegerOverflowFault : public MipsFault<IntegerOverflowFault> {}; |
| class TrapFault : public MipsFault<TrapFault> {}; |
| class BreakpointFault : public MipsFault<BreakpointFault> {}; |
| class DspStateDisabledFault : public MipsFault<DspStateDisabledFault> {}; |
| |
| class MachineCheckFault : public MipsFault<MachineCheckFault> |
| { |
| public: |
| bool isMachineCheckFault() { return true; } |
| }; |
| |
| class ResetFault : public MipsFault<ResetFault> |
| { |
| public: |
| void invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr); |
| |
| }; |
| |
| class SoftResetFault : public MipsFault<SoftResetFault> |
| { |
| public: |
| void invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr); |
| }; |
| |
| class NonMaskableInterrupt : public MipsFault<NonMaskableInterrupt> |
| { |
| public: |
| void invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr); |
| }; |
| |
| class CoprocessorUnusableFault : public MipsFault<CoprocessorUnusableFault> |
| { |
| protected: |
| int coProcID; |
| public: |
| CoprocessorUnusableFault(int _procid) : coProcID(_procid) |
| {} |
| |
| void |
| invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr) |
| { |
| MipsFault<CoprocessorUnusableFault>::invoke(tc, inst); |
| if (FullSystem) { |
| CauseReg cause = tc->readMiscReg(misc_reg::Cause); |
| cause.ce = coProcID; |
| tc->setMiscRegNoEffect(misc_reg::Cause, cause); |
| } |
| } |
| }; |
| |
| class InterruptFault : public MipsFault<InterruptFault> |
| { |
| public: |
| FaultVect |
| offset(ThreadContext *tc) const |
| { |
| CauseReg cause = tc->readMiscRegNoEffect(misc_reg::Cause); |
| // offset 0x200 for release 2, 0x180 for release 1. |
| return cause.iv ? 0x200 : 0x180; |
| } |
| }; |
| |
| template <typename T> |
| class AddressFault : public MipsFault<T> |
| { |
| protected: |
| Addr vaddr; |
| bool store; |
| |
| AddressFault(Addr _vaddr, bool _store) : vaddr(_vaddr), store(_store) |
| {} |
| |
| void |
| invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr) |
| { |
| MipsFault<T>::invoke(tc, inst); |
| if (FullSystem) |
| tc->setMiscRegNoEffect(misc_reg::Badvaddr, vaddr); |
| } |
| }; |
| |
| class AddressErrorFault : public AddressFault<AddressErrorFault> |
| { |
| public: |
| AddressErrorFault(Addr _vaddr, bool _store) : |
| AddressFault<AddressErrorFault>(_vaddr, _store) |
| {} |
| |
| ExcCode |
| code() const |
| { |
| return store ? ExcCodeAdES : ExcCodeAdEL; |
| } |
| |
| }; |
| |
| template <typename T> |
| class TlbFault : public AddressFault<T> |
| { |
| protected: |
| Addr asid; |
| Addr vpn; |
| |
| TlbFault(Addr _asid, Addr _vaddr, Addr _vpn, bool _store) : |
| AddressFault<T>(_vaddr, _store), asid(_asid), vpn(_vpn) |
| {} |
| |
| void |
| setTlbExceptionState(ThreadContext *tc, uint8_t excCode) |
| { |
| this->setExceptionState(tc, excCode); |
| |
| tc->setMiscRegNoEffect(misc_reg::Badvaddr, this->vaddr); |
| EntryHiReg entryHi = tc->readMiscReg(misc_reg::Entryhi); |
| entryHi.asid = this->asid; |
| entryHi.vpn2 = this->vpn >> 2; |
| entryHi.vpn2x = this->vpn & 0x3; |
| tc->setMiscRegNoEffect(misc_reg::Entryhi, entryHi); |
| |
| ContextReg context = tc->readMiscReg(misc_reg::Context); |
| context.badVPN2 = this->vpn >> 2; |
| tc->setMiscRegNoEffect(misc_reg::Context, context); |
| } |
| |
| void |
| invoke(ThreadContext * tc, const StaticInstPtr &inst = |
| nullStaticInstPtr) |
| { |
| if (FullSystem) { |
| DPRINTF(MipsPRA, "Fault %s encountered.\n", this->name()); |
| Addr vect = this->vect(tc); |
| setTlbExceptionState(tc, this->code()); |
| tc->pcState(vect); |
| } else { |
| AddressFault<T>::invoke(tc, inst); |
| } |
| } |
| |
| ExcCode |
| code() const |
| { |
| return this->store ? ExcCodeTlbS : ExcCodeTlbL; |
| } |
| }; |
| |
| class TlbRefillFault : public TlbFault<TlbRefillFault> |
| { |
| public: |
| TlbRefillFault(Addr asid, Addr vaddr, Addr vpn, bool store) : |
| TlbFault<TlbRefillFault>(asid, vaddr, vpn, store) |
| {} |
| |
| FaultVect |
| offset(ThreadContext *tc) const |
| { |
| StatusReg status = tc->readMiscReg(misc_reg::Status); |
| return status.exl ? 0x180 : 0x000; |
| } |
| }; |
| |
| class TlbInvalidFault : public TlbFault<TlbInvalidFault> |
| { |
| public: |
| TlbInvalidFault(Addr asid, Addr vaddr, Addr vpn, bool store) : |
| TlbFault<TlbInvalidFault>(asid, vaddr, vpn, store) |
| {} |
| }; |
| |
| class TlbModifiedFault : public TlbFault<TlbModifiedFault> |
| { |
| public: |
| TlbModifiedFault(Addr asid, Addr vaddr, Addr vpn) : |
| TlbFault<TlbModifiedFault>(asid, vaddr, vpn, false) |
| {} |
| |
| ExcCode code() const { return MipsFault<TlbModifiedFault>::code(); } |
| }; |
| |
| /* |
| * Explicitly declare template static member variables to avoid warnings |
| * in some clang versions |
| */ |
| template<> MipsFaultBase::FaultVals MipsFault<SystemCallFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<ReservedInstructionFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<ThreadFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<IntegerOverflowFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<TrapFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<BreakpointFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<DspStateDisabledFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<MachineCheckFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<ResetFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<SoftResetFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<NonMaskableInterrupt>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<CoprocessorUnusableFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<InterruptFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<AddressErrorFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<TlbInvalidFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<TlbRefillFault>::vals; |
| template<> MipsFaultBase::FaultVals MipsFault<TlbModifiedFault>::vals; |
| |
| |
| |
| } // namespace MipsISA |
| } // namespace gem5 |
| |
| #endif // __MIPS_FAULTS_HH__ |