/* * Copyright (c) 2016 RISC-V Foundation * Copyright (c) 2016 The University of Virginia * Copyright (c) 2018 TU Dresden * 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. * * Authors: Alec Roelke * Robert Scheffel */ #include "arch/riscv/faults.hh" #include "arch/riscv/isa.hh" #include "arch/riscv/registers.hh" #include "arch/riscv/system.hh" #include "arch/riscv/utility.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" #include "sim/debug.hh" #include "sim/full_system.hh" namespace RiscvISA { void RiscvFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Fault %s encountered at pc 0x%016llx.", name(), tc->pcState().pc()); } void RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) { PCState pcState = tc->pcState(); if (FullSystem) { PrivilegeMode pp = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV); PrivilegeMode prv = PRV_M; STATUS status = tc->readMiscReg(MISCREG_STATUS); // Set fault handler privilege mode if (isInterrupt()) { if (pp != PRV_M && bits(tc->readMiscReg(MISCREG_MIDELEG), _code) != 0) { prv = PRV_S; } if (pp == PRV_U && bits(tc->readMiscReg(MISCREG_SIDELEG), _code) != 0) { prv = PRV_U; } } else { if (pp != PRV_M && bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) { prv = PRV_S; } if (pp == PRV_U && bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) { prv = PRV_U; } } // Set fault registers and status MiscRegIndex cause, epc, tvec, tval; switch (prv) { case PRV_U: cause = MISCREG_UCAUSE; epc = MISCREG_UEPC; tvec = MISCREG_UTVEC; tval = MISCREG_UTVAL; status.upie = status.uie; status.uie = 0; break; case PRV_S: cause = MISCREG_SCAUSE; epc = MISCREG_SEPC; tvec = MISCREG_STVEC; tval = MISCREG_STVAL; status.spp = pp; status.spie = status.sie; status.sie = 0; break; case PRV_M: cause = MISCREG_MCAUSE; epc = MISCREG_MEPC; tvec = MISCREG_MTVEC; tval = MISCREG_MTVAL; status.mpp = pp; status.mpie = status.sie; status.mie = 0; break; default: panic("Unknown privilege mode %d.", prv); break; } // Set fault cause, privilege, and return PC tc->setMiscReg(cause, (isInterrupt() << (sizeof(MiscReg) * 4 - 1)) | _code); tc->setMiscReg(epc, tc->instAddr()); tc->setMiscReg(tval, trap_value()); tc->setMiscReg(MISCREG_PRV, prv); tc->setMiscReg(MISCREG_STATUS, status); // Set PC to fault handler address Addr addr = tc->readMiscReg(tvec) >> 2; if (isInterrupt() && bits(tc->readMiscReg(tvec), 1, 0) == 1) addr += 4 * _code; pcState.set(addr); } else { invokeSE(tc, inst); advancePC(pcState, inst); } tc->pcState(pcState); } void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst) { tc->setMiscReg(MISCREG_PRV, PRV_M); STATUS status = tc->readMiscReg(MISCREG_STATUS); status.mie = 0; status.mprv = 0; tc->setMiscReg(MISCREG_STATUS, status); tc->setMiscReg(MISCREG_MCAUSE, 0); // Advance the PC to the implementation-defined reset vector PCState pc = static_cast(tc->getSystemPtr())->resetVect(); tc->pcState(pc); } void UnknownInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Unknown instruction 0x%08x at pc 0x%016llx", inst->machInst, tc->pcState().pc()); } void IllegalInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Illegal instruction 0x%08x at pc 0x%016llx: %s", inst->machInst, tc->pcState().pc(), reason.c_str()); } void UnimplementedFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Unimplemented instruction %s at pc 0x%016llx", instName, tc->pcState().pc()); } void IllegalFrmFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.", frm, tc->pcState().pc()); } void BreakpointFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { schedRelBreak(0); } void SyscallFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) { Fault *fault = NoFault; tc->syscall(tc->readIntReg(SyscallNumReg), fault); } } // namespace RiscvISA