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