Change-Id: Ie812cf1d42536094273ba2ec731c16cca38db100 Reviewed-on: https://gem5-review.googlesource.com/c/14466 Reviewed-by: Alec Roelke <alec.roelke@gmail.com> Maintainer: Alec Roelke <alec.roelke@gmail.com>
198 lines
6.2 KiB
C++
198 lines
6.2 KiB
C++
/*
|
|
* 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(uint64_t) * 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<RiscvSystem *>(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
|