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