faults.cc revision 8570
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Gabe Black
30 *          Korey Sewell
31 *          Jaidev Patwardhan
32 */
33
34#include "arch/mips/faults.hh"
35#include "arch/mips/pra_constants.hh"
36#include "base/trace.hh"
37#include "cpu/base.hh"
38#include "cpu/thread_context.hh"
39#include "debug/MipsPRA.hh"
40
41#if !FULL_SYSTEM
42#include "mem/page_table.hh"
43#include "sim/process.hh"
44#endif
45
46namespace MipsISA
47{
48
49typedef MipsFaultBase::FaultVals FaultVals;
50
51template <> FaultVals MipsFault<MachineCheckFault>::vals =
52    { "Machine Check", 0x0401 };
53
54template <> FaultVals MipsFault<ResetFault>::vals =
55#if  FULL_SYSTEM
56    { "Reset Fault", 0xBFC00000};
57#else
58    { "Reset Fault", 0x001};
59#endif
60
61template <> FaultVals MipsFault<AddressErrorFault>::vals =
62    { "Address Error", 0x0180 };
63
64template <> FaultVals MipsFault<SystemCallFault>::vals =
65    { "Syscall", 0x0180 };
66
67template <> FaultVals MipsFault<CoprocessorUnusableFault>::vals =
68    { "Coprocessor Unusable Fault", 0x180 };
69
70template <> FaultVals MipsFault<ReservedInstructionFault>::vals =
71    { "Reserved Instruction Fault", 0x0180 };
72
73template <> FaultVals MipsFault<ThreadFault>::vals =
74    { "Thread Fault", 0x00F1 };
75
76template <> FaultVals MipsFault<IntegerOverflowFault>::vals =
77    { "Integer Overflow Exception", 0x180 };
78
79template <> FaultVals MipsFault<InterruptFault>::vals =
80    { "interrupt", 0x0180 };
81
82template <> FaultVals MipsFault<TrapFault>::vals =
83    { "Trap", 0x0180 };
84
85template <> FaultVals MipsFault<BreakpointFault>::vals =
86    { "Breakpoint", 0x0180 };
87
88template <> FaultVals MipsFault<ItbInvalidFault>::vals =
89    { "Invalid TLB Entry Exception (I-Fetch/LW)", 0x0180 };
90
91template <> FaultVals MipsFault<ItbRefillFault>::vals =
92    { "TLB Refill Exception (I-Fetch/LW)", 0x0180 };
93
94template <> FaultVals MipsFault<DtbInvalidFault>::vals =
95    { "Invalid TLB Entry Exception (Store)", 0x0180 };
96
97template <> FaultVals MipsFault<DtbRefillFault>::vals =
98    { "TLB Refill Exception (Store)", 0x0180 };
99
100template <> FaultVals MipsFault<TLBModifiedFault>::vals =
101    { "TLB Modified Exception", 0x0180 };
102
103template <> FaultVals MipsFault<DspStateDisabledFault>::vals =
104    { "DSP Disabled Fault", 0x001a };
105
106#if FULL_SYSTEM
107void
108MipsFaultBase::setHandlerPC(Addr HandlerBase, ThreadContext *tc)
109{
110    tc->setPC(HandlerBase);
111    tc->setNextPC(HandlerBase + sizeof(MachInst));
112    tc->setNextNPC(HandlerBase + 2 * sizeof(MachInst));
113}
114
115void
116MipsFaultBase::setExceptionState(ThreadContext *tc, uint8_t excCode)
117{
118    // modify SRS Ctl - Save CSS, put ESS into CSS
119    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
120    if (status.exl != 1 && status.bev != 1) {
121        // SRS Ctl is modified only if Status_EXL and Status_BEV are not set
122        SRSCtlReg srsCtl = tc->readMiscReg(MISCREG_SRSCTL);
123        srsCtl.pss = srsCtl.css;
124        srsCtl.css = srsCtl.ess;
125        tc->setMiscRegNoEffect(MISCREG_SRSCTL, srsCtl);
126    }
127
128    // set EXL bit (don't care if it is already set!)
129    status.exl = 1;
130    tc->setMiscRegNoEffect(MISCREG_STATUS, status);
131
132    // write EPC
133    // CHECK ME  or FIXME or FIX ME or POSSIBLE HACK
134    // Check to see if the exception occurred in the branch delay slot
135    DPRINTF(MipsPRA, "PC: %x, NextPC: %x, NNPC: %x\n",
136            tc->readPC(), tc->readNextPC(), tc->readNextNPC());
137    int bd = 0;
138    if (tc->readPC() + sizeof(MachInst) != tc->readNextPC()) {
139        tc->setMiscRegNoEffect(MISCREG_EPC, tc->readPC() - sizeof(MachInst));
140        // In the branch delay slot? set CAUSE_31
141        bd = 1;
142    } else {
143        tc->setMiscRegNoEffect(MISCREG_EPC, tc->readPC());
144        // In the branch delay slot? reset CAUSE_31
145        bd = 0;
146    }
147
148    // Set Cause_EXCCODE field
149    CauseReg cause = tc->readMiscReg(MISCREG_CAUSE);
150    cause.excCode = excCode;
151    cause.bd = bd;
152    cause.ce = 0;
153    tc->setMiscRegNoEffect(MISCREG_CAUSE, cause);
154}
155
156void
157IntegerOverflowFault::invoke(ThreadContext *tc, StaticInstPtr inst)
158{
159    DPRINTF(MipsPRA, "%s encountered.\n", name());
160    setExceptionState(tc, 0xC);
161
162    // Set new PC
163    Addr HandlerBase;
164    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
165    // Here, the handler is dependent on BEV, which is not modified by
166    // setExceptionState()
167    if (!status.bev) {
168        // See MIPS ARM Vol 3, Revision 2, Page 38
169        HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
170    } else {
171        HandlerBase = 0xBFC00200;
172    }
173    setHandlerPC(HandlerBase, tc);
174}
175
176void
177TrapFault::invoke(ThreadContext *tc, StaticInstPtr inst)
178{
179    DPRINTF(MipsPRA, "%s encountered.\n", name());
180    setExceptionState(tc, 0xD);
181
182    // Set new PC
183    Addr HandlerBase;
184    // Offset 0x180 - General Exception Vector
185    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
186    setHandlerPC(HandlerBase, tc);
187}
188
189void
190BreakpointFault::invoke(ThreadContext *tc, StaticInstPtr inst)
191{
192    setExceptionState(tc, 0x9);
193
194    // Set new PC
195    Addr HandlerBase;
196    // Offset 0x180 - General Exception Vector
197    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
198    setHandlerPC(HandlerBase, tc);
199}
200
201void
202DtbInvalidFault::invoke(ThreadContext *tc, StaticInstPtr inst)
203{
204    DPRINTF(MipsPRA, "%s encountered.\n", name());
205
206    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
207    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
208    entryHi.asid = entryHiAsid;
209    entryHi.vpn2 = entryHiVPN2;
210    entryHi.vpn2x = entryHiVPN2X;
211    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
212
213    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
214    context.badVPN2 = contextBadVPN2;
215    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
216    setExceptionState(tc, 0x3);
217
218
219    // Set new PC
220    Addr HandlerBase;
221    // Offset 0x180 - General Exception Vector
222    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
223    setHandlerPC(HandlerBase, tc);
224}
225
226void
227AddressErrorFault::invoke(ThreadContext *tc, StaticInstPtr inst)
228{
229    DPRINTF(MipsPRA, "%s encountered.\n", name());
230    setExceptionState(tc, store ? 0x5 : 0x4);
231    tc->setMiscRegNoEffect(MISCREG_BADVADDR, vaddr);
232
233    // Set new PC
234    Addr HandlerBase;
235    // Offset 0x180 - General Exception Vector
236    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
237    setHandlerPC(HandlerBase, tc);
238}
239
240void
241ItbInvalidFault::invoke(ThreadContext *tc, StaticInstPtr inst)
242{
243    DPRINTF(MipsPRA, "%s encountered.\n", name());
244    setExceptionState(tc, 0x2);
245    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
246    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
247    entryHi.asid = entryHiAsid;
248    entryHi.vpn2 = entryHiVPN2;
249    entryHi.vpn2x = entryHiVPN2X;
250    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
251
252    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
253    context.badVPN2 = contextBadVPN2;
254    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
255
256
257    // Set new PC
258    Addr HandlerBase;
259    // Offset 0x180 - General Exception Vector
260    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
261    setHandlerPC(HandlerBase,tc);
262    DPRINTF(MipsPRA, "Exception Handler At: %x , EPC set to %x\n",
263            HandlerBase, tc->readMiscReg(MISCREG_EPC));
264}
265
266void
267ItbRefillFault::invoke(ThreadContext *tc, StaticInstPtr inst)
268{
269    DPRINTF(MipsPRA, "%s encountered (%x).\n", name(), MISCREG_BADVADDR);
270    Addr HandlerBase;
271    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
272    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
273    entryHi.asid = entryHiAsid;
274    entryHi.vpn2 = entryHiVPN2;
275    entryHi.vpn2x = entryHiVPN2X;
276    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
277    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
278    context.badVPN2 = contextBadVPN2;
279    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
280
281    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
282    // Since handler depends on EXL bit, must check EXL bit before setting it!!
283    // See MIPS ARM Vol 3, Revision 2, Page 38
284    if (status.exl == 1) {
285        // Offset 0x180 - General Exception Vector
286        HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
287    } else {
288        // Offset 0x000
289        HandlerBase = tc->readMiscReg(MISCREG_EBASE);
290    }
291
292    setExceptionState(tc, 0x2);
293    setHandlerPC(HandlerBase, tc);
294}
295
296void
297DtbRefillFault::invoke(ThreadContext *tc, StaticInstPtr inst)
298{
299    // Set new PC
300    DPRINTF(MipsPRA, "%s encountered.\n", name());
301    Addr HandlerBase;
302    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
303    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
304    entryHi.asid = entryHiAsid;
305    entryHi.vpn2 = entryHiVPN2;
306    entryHi.vpn2x = entryHiVPN2X;
307    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
308
309    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
310    context.badVPN2 = contextBadVPN2;
311    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
312
313    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
314    // Since handler depends on EXL bit, must check EXL bit before setting it!!
315    // See MIPS ARM Vol 3, Revision 2, Page 38
316    if (status.exl) {
317        // Offset 0x180 - General Exception Vector
318        HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
319    } else {
320        // Offset 0x000
321        HandlerBase = tc->readMiscReg(MISCREG_EBASE);
322    }
323
324    setExceptionState(tc, 0x3);
325
326    setHandlerPC(HandlerBase, tc);
327}
328
329void
330TLBModifiedFault::invoke(ThreadContext *tc, StaticInstPtr inst)
331{
332    DPRINTF(MipsPRA, "%s encountered.\n", name());
333    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
334    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
335    entryHi.asid = entryHiAsid;
336    entryHi.vpn2 = entryHiVPN2;
337    entryHi.vpn2x = entryHiVPN2X;
338    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
339
340    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
341    context.badVPN2 = contextBadVPN2;
342    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
343
344    // Set new PC
345    Addr HandlerBase;
346    // Offset 0x180 - General Exception Vector
347    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
348    setExceptionState(tc, 0x1);
349    setHandlerPC(HandlerBase, tc);
350
351}
352
353void
354SystemCallFault::invoke(ThreadContext *tc, StaticInstPtr inst)
355{
356    DPRINTF(MipsPRA, "%s encountered.\n", name());
357    setExceptionState(tc, 0x8);
358
359    // Set new PC
360    Addr HandlerBase;
361    // Offset 0x180 - General Exception Vector
362    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
363    setHandlerPC(HandlerBase, tc);
364}
365
366void
367InterruptFault::invoke(ThreadContext *tc, StaticInstPtr inst)
368{
369#if  FULL_SYSTEM
370    DPRINTF(MipsPRA, "%s encountered.\n", name());
371    setExceptionState(tc, 0x0A);
372    Addr HandlerBase;
373
374    CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE);
375    if (cause.iv) {
376        // Offset 200 for release 2
377        HandlerBase = 0x20 + vect() + tc->readMiscRegNoEffect(MISCREG_EBASE);
378    } else {
379        //Ofset at 180 for release 1
380        HandlerBase = vect() + tc->readMiscRegNoEffect(MISCREG_EBASE);
381    }
382
383    setHandlerPC(HandlerBase, tc);
384#endif
385}
386
387#endif // FULL_SYSTEM
388
389void
390ResetFault::invoke(ThreadContext *tc, StaticInstPtr inst)
391{
392#if FULL_SYSTEM
393    DPRINTF(MipsPRA, "%s encountered.\n", name());
394    /* All reset activity must be invoked from here */
395    tc->setPC(vect());
396    tc->setNextPC(vect() + sizeof(MachInst));
397    tc->setNextNPC(vect() + sizeof(MachInst) + sizeof(MachInst));
398    DPRINTF(MipsPRA, "ResetFault::invoke : PC set to %x", tc->readPC());
399#endif
400
401    // Set Coprocessor 1 (Floating Point) To Usable
402    StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
403    status.cu.cu1 = 1;
404    tc->setMiscReg(MISCREG_STATUS, status);
405}
406
407void
408ReservedInstructionFault::invoke(ThreadContext *tc, StaticInstPtr inst)
409{
410#if  FULL_SYSTEM
411    DPRINTF(MipsPRA, "%s encountered.\n", name());
412    setExceptionState(tc, 0x0A);
413    Addr HandlerBase;
414    // Offset 0x180 - General Exception Vector
415    HandlerBase = vect() + tc->readMiscRegNoEffect(MISCREG_EBASE);
416    setHandlerPC(HandlerBase, tc);
417#else
418    panic("%s encountered.\n", name());
419#endif
420}
421
422void
423ThreadFault::invoke(ThreadContext *tc, StaticInstPtr inst)
424{
425    DPRINTF(MipsPRA, "%s encountered.\n", name());
426    panic("%s encountered.\n", name());
427}
428
429void
430DspStateDisabledFault::invoke(ThreadContext *tc, StaticInstPtr inst)
431{
432    DPRINTF(MipsPRA, "%s encountered.\n", name());
433    panic("%s encountered.\n", name());
434}
435
436void
437CoprocessorUnusableFault::invoke(ThreadContext *tc, StaticInstPtr inst)
438{
439#if FULL_SYSTEM
440    DPRINTF(MipsPRA, "%s encountered.\n", name());
441    setExceptionState(tc, 0xb);
442    // The ID of the coprocessor causing the exception is stored in
443    // CoprocessorUnusableFault::coProcID
444    CauseReg cause = tc->readMiscReg(MISCREG_CAUSE);
445    cause.ce = coProcID;
446    tc->setMiscRegNoEffect(MISCREG_CAUSE, cause);
447
448    Addr HandlerBase;
449    // Offset 0x180 - General Exception Vector
450    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
451    setHandlerPC(HandlerBase, tc);
452
453#else
454    warn("%s (CP%d) encountered.\n", name(), coProcID);
455#endif
456}
457
458} // namespace MipsISA
459
460