1/* 2 * Copyright (c) 2016 RISC-V Foundation 3 * Copyright (c) 2016 The University of Virginia 4 * Copyright (c) 2018 TU Dresden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer; 11 * redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution; 14 * neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Authors: Alec Roelke 31 * Robert Scheffel 32 */ 33#include "arch/riscv/faults.hh" 34 35#include "arch/riscv/isa.hh" 36#include "arch/riscv/registers.hh" 37#include "arch/riscv/system.hh" 38#include "arch/riscv/utility.hh" 39#include "cpu/base.hh" 40#include "cpu/thread_context.hh" 41#include "sim/debug.hh" 42#include "sim/full_system.hh" 43 44namespace RiscvISA 45{ 46 47void 48RiscvFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) 49{ 50 panic("Fault %s encountered at pc 0x%016llx.", name(), tc->pcState().pc()); 51} 52 53void 54RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) 55{ 56 PCState pcState = tc->pcState(); 57 58 if (FullSystem) { 59 PrivilegeMode pp = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV); 60 PrivilegeMode prv = PRV_M; 61 STATUS status = tc->readMiscReg(MISCREG_STATUS); 62 63 // Set fault handler privilege mode 64 if (isInterrupt()) { 65 if (pp != PRV_M && 66 bits(tc->readMiscReg(MISCREG_MIDELEG), _code) != 0) { 67 prv = PRV_S; 68 } 69 if (pp == PRV_U && 70 bits(tc->readMiscReg(MISCREG_SIDELEG), _code) != 0) { 71 prv = PRV_U; 72 } 73 } else { 74 if (pp != PRV_M && 75 bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) { 76 prv = PRV_S; 77 } 78 if (pp == PRV_U && 79 bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) { 80 prv = PRV_U; 81 } 82 } 83 84 // Set fault registers and status 85 MiscRegIndex cause, epc, tvec, tval; 86 switch (prv) { 87 case PRV_U: 88 cause = MISCREG_UCAUSE; 89 epc = MISCREG_UEPC; 90 tvec = MISCREG_UTVEC; 91 tval = MISCREG_UTVAL; 92 93 status.upie = status.uie; 94 status.uie = 0; 95 break; 96 case PRV_S: 97 cause = MISCREG_SCAUSE; 98 epc = MISCREG_SEPC; 99 tvec = MISCREG_STVEC; 100 tval = MISCREG_STVAL; 101 102 status.spp = pp; 103 status.spie = status.sie; 104 status.sie = 0; 105 break; 106 case PRV_M: 107 cause = MISCREG_MCAUSE; 108 epc = MISCREG_MEPC; 109 tvec = MISCREG_MTVEC; 110 tval = MISCREG_MTVAL; 111 112 status.mpp = pp; 113 status.mpie = status.sie; 114 status.mie = 0; 115 break; 116 default: 117 panic("Unknown privilege mode %d.", prv); 118 break; 119 } 120 121 // Set fault cause, privilege, and return PC 122 tc->setMiscReg(cause, 123 (isInterrupt() << (sizeof(uint64_t) * 4 - 1)) | _code); 124 tc->setMiscReg(epc, tc->instAddr()); 125 tc->setMiscReg(tval, trap_value()); 126 tc->setMiscReg(MISCREG_PRV, prv); 127 tc->setMiscReg(MISCREG_STATUS, status); 128 129 // Set PC to fault handler address 130 Addr addr = tc->readMiscReg(tvec) >> 2; 131 if (isInterrupt() && bits(tc->readMiscReg(tvec), 1, 0) == 1) 132 addr += 4 * _code; 133 pcState.set(addr); 134 } else { 135 invokeSE(tc, inst); 136 advancePC(pcState, inst); 137 } 138 tc->pcState(pcState); 139} 140 141void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst) 142{ 143 tc->setMiscReg(MISCREG_PRV, PRV_M); 144 STATUS status = tc->readMiscReg(MISCREG_STATUS); 145 status.mie = 0; 146 status.mprv = 0; 147 tc->setMiscReg(MISCREG_STATUS, status); 148 tc->setMiscReg(MISCREG_MCAUSE, 0); 149 150 // Advance the PC to the implementation-defined reset vector 151 PCState pc = static_cast<RiscvSystem *>(tc->getSystemPtr())->resetVect(); 152 tc->pcState(pc); 153} 154 155void 156UnknownInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) 157{ 158 panic("Unknown instruction 0x%08x at pc 0x%016llx", inst->machInst, 159 tc->pcState().pc()); 160} 161 162void 163IllegalInstFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) 164{ 165 panic("Illegal instruction 0x%08x at pc 0x%016llx: %s", inst->machInst, 166 tc->pcState().pc(), reason.c_str()); 167} 168 169void 170UnimplementedFault::invokeSE(ThreadContext *tc, 171 const StaticInstPtr &inst) 172{ 173 panic("Unimplemented instruction %s at pc 0x%016llx", instName, 174 tc->pcState().pc()); 175} 176 177void 178IllegalFrmFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) 179{ 180 panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.", 181 frm, tc->pcState().pc()); 182} 183 184void 185BreakpointFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) 186{ 187 schedRelBreak(0); 188} 189 190void 191SyscallFault::invokeSE(ThreadContext *tc, const StaticInstPtr &inst) 192{ 193 Fault *fault = NoFault; 194 tc->syscall(tc->readIntReg(SyscallNumReg), fault); 195} 196 197} // namespace RiscvISA 198