faults.cc revision 8566:812d279f7b51
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<AlignmentFault>::vals =
55    { "Alignment", 0x0301 };
56
57template <> FaultVals MipsFault<ResetFault>::vals =
58#if  FULL_SYSTEM
59    { "Reset Fault", 0xBFC00000};
60#else
61    { "Reset Fault", 0x001};
62#endif
63
64template <> FaultVals MipsFault<AddressErrorFault>::vals =
65    { "Address Error", 0x0180 };
66
67template <> FaultVals MipsFault<StoreAddressErrorFault>::vals =
68    { "Store Address Error", 0x0180 };
69
70template <> FaultVals MipsFault<SystemCallFault>::vals =
71    { "Syscall", 0x0180 };
72
73template <> FaultVals MipsFault<CoprocessorUnusableFault>::vals =
74    { "Coprocessor Unusable Fault", 0x180 };
75
76template <> FaultVals MipsFault<ReservedInstructionFault>::vals =
77    { "Reserved Instruction Fault", 0x0180 };
78
79template <> FaultVals MipsFault<ThreadFault>::vals =
80    { "Thread Fault", 0x00F1 };
81
82template <> FaultVals MipsFault<ArithmeticFault>::vals =
83    { "Arithmetic Overflow Exception", 0x180 };
84
85template <> FaultVals MipsFault<UnimplementedOpcodeFault>::vals =
86    { "opdec", 0x0481 };
87
88template <> FaultVals MipsFault<InterruptFault>::vals =
89    { "interrupt", 0x0180 };
90
91template <> FaultVals MipsFault<TrapFault>::vals =
92    { "Trap", 0x0180 };
93
94template <> FaultVals MipsFault<BreakpointFault>::vals =
95    { "Breakpoint", 0x0180 };
96
97template <> FaultVals MipsFault<ItbInvalidFault>::vals =
98    { "Invalid TLB Entry Exception (I-Fetch/LW)", 0x0180 };
99
100template <> FaultVals MipsFault<ItbPageFault>::vals =
101    { "itbmiss", 0x0181 };
102
103template <> FaultVals MipsFault<ItbMissFault>::vals =
104    { "itbmiss", 0x0181 };
105
106template <> FaultVals MipsFault<ItbAcvFault>::vals =
107    { "iaccvio", 0x0081 };
108
109template <> FaultVals MipsFault<ItbRefillFault>::vals =
110    { "TLB Refill Exception (I-Fetch/LW)", 0x0180 };
111
112template <> FaultVals MipsFault<NDtbMissFault>::vals =
113    { "dtb_miss_single", 0x0201 };
114
115template <> FaultVals MipsFault<PDtbMissFault>::vals =
116    { "dtb_miss_double", 0x0281 };
117
118template <> FaultVals MipsFault<DtbPageFault>::vals =
119    { "dfault", 0x0381 };
120
121template <> FaultVals MipsFault<DtbAcvFault>::vals =
122    { "dfault", 0x0381 };
123
124template <> FaultVals MipsFault<DtbInvalidFault>::vals =
125    { "Invalid TLB Entry Exception (Store)", 0x0180 };
126
127template <> FaultVals MipsFault<DtbRefillFault>::vals =
128    { "TLB Refill Exception (Store)", 0x0180 };
129
130template <> FaultVals MipsFault<TLBModifiedFault>::vals =
131    { "TLB Modified Exception", 0x0180 };
132
133template <> FaultVals MipsFault<FloatEnableFault>::vals =
134    { "float_enable_fault", 0x0581 };
135
136template <> FaultVals MipsFault<IntegerOverflowFault>::vals =
137    { "Integer Overflow Fault", 0x0501 };
138
139template <> FaultVals MipsFault<DspStateDisabledFault>::vals =
140    { "DSP Disabled Fault", 0x001a };
141
142#if FULL_SYSTEM
143void
144MipsFaultBase::setHandlerPC(Addr HandlerBase, ThreadContext *tc)
145{
146    tc->setPC(HandlerBase);
147    tc->setNextPC(HandlerBase + sizeof(MachInst));
148    tc->setNextNPC(HandlerBase + 2 * sizeof(MachInst));
149}
150
151void
152MipsFaultBase::setExceptionState(ThreadContext *tc, uint8_t excCode)
153{
154    // modify SRS Ctl - Save CSS, put ESS into CSS
155    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
156    if (status.exl != 1 && status.bev != 1) {
157        // SRS Ctl is modified only if Status_EXL and Status_BEV are not set
158        SRSCtlReg srsCtl = tc->readMiscReg(MISCREG_SRSCTL);
159        srsCtl.pss = srsCtl.css;
160        srsCtl.css = srsCtl.ess;
161        tc->setMiscRegNoEffect(MISCREG_SRSCTL, srsCtl);
162    }
163
164    // set EXL bit (don't care if it is already set!)
165    status.exl = 1;
166    tc->setMiscRegNoEffect(MISCREG_STATUS, status);
167
168    // write EPC
169    // CHECK ME  or FIXME or FIX ME or POSSIBLE HACK
170    // Check to see if the exception occurred in the branch delay slot
171    DPRINTF(MipsPRA, "PC: %x, NextPC: %x, NNPC: %x\n",
172            tc->readPC(), tc->readNextPC(), tc->readNextNPC());
173    int bd = 0;
174    if (tc->readPC() + sizeof(MachInst) != tc->readNextPC()) {
175        tc->setMiscRegNoEffect(MISCREG_EPC, tc->readPC() - sizeof(MachInst));
176        // In the branch delay slot? set CAUSE_31
177        bd = 1;
178    } else {
179        tc->setMiscRegNoEffect(MISCREG_EPC, tc->readPC());
180        // In the branch delay slot? reset CAUSE_31
181        bd = 0;
182    }
183
184    // Set Cause_EXCCODE field
185    CauseReg cause = tc->readMiscReg(MISCREG_CAUSE);
186    cause.excCode = excCode;
187    cause.bd = bd;
188    cause.ce = 0;
189    tc->setMiscRegNoEffect(MISCREG_CAUSE, cause);
190}
191
192void
193ArithmeticFault::invoke(ThreadContext *tc, StaticInstPtr inst)
194{
195    DPRINTF(MipsPRA, "%s encountered.\n", name());
196    setExceptionState(tc, 0xC);
197
198    // Set new PC
199    Addr HandlerBase;
200    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
201    // Here, the handler is dependent on BEV, which is not modified by
202    // setExceptionState()
203    if (!status.bev) {
204        // See MIPS ARM Vol 3, Revision 2, Page 38
205        HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
206    } else {
207        HandlerBase = 0xBFC00200;
208    }
209    setHandlerPC(HandlerBase, tc);
210}
211
212void
213StoreAddressErrorFault::invoke(ThreadContext *tc, StaticInstPtr inst)
214{
215    DPRINTF(MipsPRA, "%s encountered.\n", name());
216    setExceptionState(tc, 0x5);
217    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
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
227TrapFault::invoke(ThreadContext *tc, StaticInstPtr inst)
228{
229    DPRINTF(MipsPRA, "%s encountered.\n", name());
230    setExceptionState(tc, 0xD);
231
232    // Set new PC
233    Addr HandlerBase;
234    // Offset 0x180 - General Exception Vector
235    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
236    setHandlerPC(HandlerBase, tc);
237}
238
239void
240BreakpointFault::invoke(ThreadContext *tc, StaticInstPtr inst)
241{
242    setExceptionState(tc, 0x9);
243
244    // Set new PC
245    Addr HandlerBase;
246    // Offset 0x180 - General Exception Vector
247    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
248    setHandlerPC(HandlerBase, tc);
249}
250
251void
252DtbInvalidFault::invoke(ThreadContext *tc, StaticInstPtr inst)
253{
254    DPRINTF(MipsPRA, "%s encountered.\n", name());
255
256    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
257    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
258    entryHi.asid = entryHiAsid;
259    entryHi.vpn2 = entryHiVPN2;
260    entryHi.vpn2x = entryHiVPN2X;
261    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
262
263    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
264    context.badVPN2 = contextBadVPN2;
265    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
266    setExceptionState(tc, 0x3);
267
268
269    // Set new PC
270    Addr HandlerBase;
271    // Offset 0x180 - General Exception Vector
272    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
273    setHandlerPC(HandlerBase, tc);
274}
275
276void
277AddressErrorFault::invoke(ThreadContext *tc, StaticInstPtr inst)
278{
279    DPRINTF(MipsPRA, "%s encountered.\n", name());
280    setExceptionState(tc, 0x4);
281    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
282
283    // Set new PC
284    Addr HandlerBase;
285    // Offset 0x180 - General Exception Vector
286    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
287    setHandlerPC(HandlerBase, tc);
288}
289
290void
291ItbInvalidFault::invoke(ThreadContext *tc, StaticInstPtr inst)
292{
293    DPRINTF(MipsPRA, "%s encountered.\n", name());
294    setExceptionState(tc, 0x2);
295    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
296    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
297    entryHi.asid = entryHiAsid;
298    entryHi.vpn2 = entryHiVPN2;
299    entryHi.vpn2x = entryHiVPN2X;
300    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
301
302    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
303    context.badVPN2 = contextBadVPN2;
304    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
305
306
307    // Set new PC
308    Addr HandlerBase;
309    // Offset 0x180 - General Exception Vector
310    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
311    setHandlerPC(HandlerBase,tc);
312    DPRINTF(MipsPRA, "Exception Handler At: %x , EPC set to %x\n",
313            HandlerBase, tc->readMiscReg(MISCREG_EPC));
314}
315
316void
317ItbRefillFault::invoke(ThreadContext *tc, StaticInstPtr inst)
318{
319    DPRINTF(MipsPRA, "%s encountered (%x).\n", name(), MISCREG_BADVADDR);
320    Addr HandlerBase;
321    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
322    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
323    entryHi.asid = entryHiAsid;
324    entryHi.vpn2 = entryHiVPN2;
325    entryHi.vpn2x = entryHiVPN2X;
326    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
327    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
328    context.badVPN2 = contextBadVPN2;
329    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
330
331    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
332    // Since handler depends on EXL bit, must check EXL bit before setting it!!
333    // See MIPS ARM Vol 3, Revision 2, Page 38
334    if (status.exl == 1) {
335        // Offset 0x180 - General Exception Vector
336        HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
337    } else {
338        // Offset 0x000
339        HandlerBase = tc->readMiscReg(MISCREG_EBASE);
340    }
341
342    setExceptionState(tc, 0x2);
343    setHandlerPC(HandlerBase, tc);
344}
345
346void
347DtbRefillFault::invoke(ThreadContext *tc, StaticInstPtr inst)
348{
349    // Set new PC
350    DPRINTF(MipsPRA, "%s encountered.\n", name());
351    Addr HandlerBase;
352    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
353    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
354    entryHi.asid = entryHiAsid;
355    entryHi.vpn2 = entryHiVPN2;
356    entryHi.vpn2x = entryHiVPN2X;
357    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
358
359    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
360    context.badVPN2 = contextBadVPN2;
361    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
362
363    StatusReg status = tc->readMiscReg(MISCREG_STATUS);
364    // Since handler depends on EXL bit, must check EXL bit before setting it!!
365    // See MIPS ARM Vol 3, Revision 2, Page 38
366    if (status.exl) {
367        // Offset 0x180 - General Exception Vector
368        HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
369    } else {
370        // Offset 0x000
371        HandlerBase = tc->readMiscReg(MISCREG_EBASE);
372    }
373
374    setExceptionState(tc, 0x3);
375
376    setHandlerPC(HandlerBase, tc);
377}
378
379void
380TLBModifiedFault::invoke(ThreadContext *tc, StaticInstPtr inst)
381{
382    DPRINTF(MipsPRA, "%s encountered.\n", name());
383    tc->setMiscRegNoEffect(MISCREG_BADVADDR, badVAddr);
384    EntryHiReg entryHi = tc->readMiscReg(MISCREG_ENTRYHI);
385    entryHi.asid = entryHiAsid;
386    entryHi.vpn2 = entryHiVPN2;
387    entryHi.vpn2x = entryHiVPN2X;
388    tc->setMiscRegNoEffect(MISCREG_ENTRYHI, entryHi);
389
390    ContextReg context = tc->readMiscReg(MISCREG_CONTEXT);
391    context.badVPN2 = contextBadVPN2;
392    tc->setMiscRegNoEffect(MISCREG_CONTEXT, context);
393
394    // Set new PC
395    Addr HandlerBase;
396    // Offset 0x180 - General Exception Vector
397    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
398    setExceptionState(tc, 0x1);
399    setHandlerPC(HandlerBase, tc);
400
401}
402
403void
404SystemCallFault::invoke(ThreadContext *tc, StaticInstPtr inst)
405{
406    DPRINTF(MipsPRA, "%s encountered.\n", name());
407    setExceptionState(tc, 0x8);
408
409    // Set new PC
410    Addr HandlerBase;
411    // Offset 0x180 - General Exception Vector
412    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
413    setHandlerPC(HandlerBase, tc);
414}
415
416void
417InterruptFault::invoke(ThreadContext *tc, StaticInstPtr inst)
418{
419#if  FULL_SYSTEM
420    DPRINTF(MipsPRA, "%s encountered.\n", name());
421    setExceptionState(tc, 0x0A);
422    Addr HandlerBase;
423
424    CauseReg cause = tc->readMiscRegNoEffect(MISCREG_CAUSE);
425    if (cause.iv) {
426        // Offset 200 for release 2
427        HandlerBase = 0x20 + vect() + tc->readMiscRegNoEffect(MISCREG_EBASE);
428    } else {
429        //Ofset at 180 for release 1
430        HandlerBase = vect() + tc->readMiscRegNoEffect(MISCREG_EBASE);
431    }
432
433    setHandlerPC(HandlerBase, tc);
434#endif
435}
436
437#endif // FULL_SYSTEM
438
439void
440ResetFault::invoke(ThreadContext *tc, StaticInstPtr inst)
441{
442#if FULL_SYSTEM
443    DPRINTF(MipsPRA, "%s encountered.\n", name());
444    /* All reset activity must be invoked from here */
445    tc->setPC(vect());
446    tc->setNextPC(vect() + sizeof(MachInst));
447    tc->setNextNPC(vect() + sizeof(MachInst) + sizeof(MachInst));
448    DPRINTF(MipsPRA, "ResetFault::invoke : PC set to %x", tc->readPC());
449#endif
450
451    // Set Coprocessor 1 (Floating Point) To Usable
452    StatusReg status = tc->readMiscRegNoEffect(MISCREG_STATUS);
453    status.cu.cu1 = 1;
454    tc->setMiscReg(MISCREG_STATUS, status);
455}
456
457void
458ReservedInstructionFault::invoke(ThreadContext *tc, StaticInstPtr inst)
459{
460#if  FULL_SYSTEM
461    DPRINTF(MipsPRA, "%s encountered.\n", name());
462    setExceptionState(tc, 0x0A);
463    Addr HandlerBase;
464    // Offset 0x180 - General Exception Vector
465    HandlerBase = vect() + tc->readMiscRegNoEffect(MISCREG_EBASE);
466    setHandlerPC(HandlerBase, tc);
467#else
468    panic("%s encountered.\n", name());
469#endif
470}
471
472void
473ThreadFault::invoke(ThreadContext *tc, StaticInstPtr inst)
474{
475    DPRINTF(MipsPRA, "%s encountered.\n", name());
476    panic("%s encountered.\n", name());
477}
478
479void
480DspStateDisabledFault::invoke(ThreadContext *tc, StaticInstPtr inst)
481{
482    DPRINTF(MipsPRA, "%s encountered.\n", name());
483    panic("%s encountered.\n", name());
484}
485
486void
487CoprocessorUnusableFault::invoke(ThreadContext *tc, StaticInstPtr inst)
488{
489#if FULL_SYSTEM
490    DPRINTF(MipsPRA, "%s encountered.\n", name());
491    setExceptionState(tc, 0xb);
492    // The ID of the coprocessor causing the exception is stored in
493    // CoprocessorUnusableFault::coProcID
494    CauseReg cause = tc->readMiscReg(MISCREG_CAUSE);
495    cause.ce = coProcID;
496    tc->setMiscRegNoEffect(MISCREG_CAUSE, cause);
497
498    Addr HandlerBase;
499    // Offset 0x180 - General Exception Vector
500    HandlerBase = vect() + tc->readMiscReg(MISCREG_EBASE);
501    setHandlerPC(HandlerBase, tc);
502
503#else
504    warn("%s (CP%d) encountered.\n", name(), coProcID);
505#endif
506}
507
508} // namespace MipsISA
509
510