faults.cc revision 3576
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Gabe Black
29 *          Kevin Lim
30 */
31
32#include <algorithm>
33
34#include "arch/sparc/faults.hh"
35#include "arch/sparc/isa_traits.hh"
36#include "base/bitfield.hh"
37#include "base/trace.hh"
38#include "config/full_system.hh"
39#include "cpu/base.hh"
40#include "cpu/thread_context.hh"
41#if !FULL_SYSTEM
42#include "arch/sparc/process.hh"
43#include "mem/page_table.hh"
44#include "sim/process.hh"
45#endif
46
47using namespace std;
48
49namespace SparcISA
50{
51
52template<> SparcFaultBase::FaultVals
53    SparcFault<PowerOnReset>::vals =
54    {"power_on_reset", 0x001, 0, {H, H, H}};
55
56template<> SparcFaultBase::FaultVals
57    SparcFault<WatchDogReset>::vals =
58    {"watch_dog_reset", 0x002, 120, {H, H, H}};
59
60template<> SparcFaultBase::FaultVals
61    SparcFault<ExternallyInitiatedReset>::vals =
62    {"externally_initiated_reset", 0x003, 110, {H, H, H}};
63
64template<> SparcFaultBase::FaultVals
65    SparcFault<SoftwareInitiatedReset>::vals =
66    {"software_initiated_reset", 0x004, 130, {SH, SH, H}};
67
68template<> SparcFaultBase::FaultVals
69    SparcFault<REDStateException>::vals =
70    {"RED_state_exception", 0x005, 1, {H, H, H}};
71
72template<> SparcFaultBase::FaultVals
73    SparcFault<StoreError>::vals =
74    {"store_error", 0x007, 201, {H, H, H}};
75
76template<> SparcFaultBase::FaultVals
77    SparcFault<InstructionAccessException>::vals =
78    {"instruction_access_exception", 0x008, 300, {H, H, H}};
79
80//XXX This trap is apparently dropped from ua2005
81/*template<> SparcFaultBase::FaultVals
82    SparcFault<InstructionAccessMMUMiss>::vals =
83    {"inst_mmu", 0x009, 2, {H, H, H}};*/
84
85template<> SparcFaultBase::FaultVals
86    SparcFault<InstructionAccessError>::vals =
87    {"instruction_access_error", 0x00A, 400, {H, H, H}};
88
89template<> SparcFaultBase::FaultVals
90    SparcFault<IllegalInstruction>::vals =
91    {"illegal_instruction", 0x010, 620, {H, H, H}};
92
93template<> SparcFaultBase::FaultVals
94    SparcFault<PrivilegedOpcode>::vals =
95    {"privileged_opcode", 0x011, 700, {P, SH, SH}};
96
97//XXX This trap is apparently dropped from ua2005
98/*template<> SparcFaultBase::FaultVals
99    SparcFault<UnimplementedLDD>::vals =
100    {"unimp_ldd", 0x012, 6, {H, H, H}};*/
101
102//XXX This trap is apparently dropped from ua2005
103/*template<> SparcFaultBase::FaultVals
104    SparcFault<UnimplementedSTD>::vals =
105    {"unimp_std", 0x013, 6, {H, H, H}};*/
106
107template<> SparcFaultBase::FaultVals
108    SparcFault<FpDisabled>::vals =
109    {"fp_disabled", 0x020, 800, {P, P, H}};
110
111template<> SparcFaultBase::FaultVals
112    SparcFault<FpExceptionIEEE754>::vals =
113    {"fp_exception_ieee_754", 0x021, 1110, {P, P, H}};
114
115template<> SparcFaultBase::FaultVals
116    SparcFault<FpExceptionOther>::vals =
117    {"fp_exception_other", 0x022, 1110, {P, P, H}};
118
119template<> SparcFaultBase::FaultVals
120    SparcFault<TagOverflow>::vals =
121    {"tag_overflow", 0x023, 1400, {P, P, H}};
122
123template<> SparcFaultBase::FaultVals
124    SparcFault<CleanWindow>::vals =
125    {"clean_window", 0x024, 1010, {P, P, H}};
126
127template<> SparcFaultBase::FaultVals
128    SparcFault<DivisionByZero>::vals =
129    {"division_by_zero", 0x028, 1500, {P, P, H}};
130
131template<> SparcFaultBase::FaultVals
132    SparcFault<InternalProcessorError>::vals =
133    {"internal_processor_error", 0x029, 4, {H, H, H}};
134
135template<> SparcFaultBase::FaultVals
136    SparcFault<InstructionInvalidTSBEntry>::vals =
137    {"instruction_invalid_tsb_entry", 0x02A, 210, {H, H, SH}};
138
139template<> SparcFaultBase::FaultVals
140    SparcFault<DataInvalidTSBEntry>::vals =
141    {"data_invalid_tsb_entry", 0x02B, 1203, {H, H, H}};
142
143template<> SparcFaultBase::FaultVals
144    SparcFault<DataAccessException>::vals =
145    {"data_access_exception", 0x030, 1201, {H, H, H}};
146
147//XXX This trap is apparently dropped from ua2005
148/*template<> SparcFaultBase::FaultVals
149    SparcFault<DataAccessMMUMiss>::vals =
150    {"data_mmu", 0x031, 12, {H, H, H}};*/
151
152template<> SparcFaultBase::FaultVals
153    SparcFault<DataAccessError>::vals =
154    {"data_access_error", 0x032, 1210, {H, H, H}};
155
156template<> SparcFaultBase::FaultVals
157    SparcFault<DataAccessProtection>::vals =
158    {"data_access_protection", 0x033, 1207, {H, H, H}};
159
160template<> SparcFaultBase::FaultVals
161    SparcFault<MemAddressNotAligned>::vals =
162    {"mem_address_not_aligned", 0x034, 1020, {H, H, H}};
163
164template<> SparcFaultBase::FaultVals
165    SparcFault<LDDFMemAddressNotAligned>::vals =
166    {"LDDF_mem_address_not_aligned", 0x035, 1010, {H, H, H}};
167
168template<> SparcFaultBase::FaultVals
169    SparcFault<STDFMemAddressNotAligned>::vals =
170    {"STDF_mem_address_not_aligned", 0x036, 1010, {H, H, H}};
171
172template<> SparcFaultBase::FaultVals
173    SparcFault<PrivilegedAction>::vals =
174    {"privileged_action", 0x037, 1110, {H, H, SH}};
175
176template<> SparcFaultBase::FaultVals
177    SparcFault<LDQFMemAddressNotAligned>::vals =
178    {"LDQF_mem_address_not_aligned", 0x038, 1010, {H, H, H}};
179
180template<> SparcFaultBase::FaultVals
181    SparcFault<STQFMemAddressNotAligned>::vals =
182    {"STQF_mem_address_not_aligned", 0x039, 1010, {H, H, H}};
183
184template<> SparcFaultBase::FaultVals
185    SparcFault<InstructionRealTranslationMiss>::vals =
186    {"instruction_real_translation_miss", 0x03E, 208, {H, H, SH}};
187
188template<> SparcFaultBase::FaultVals
189    SparcFault<DataRealTranslationMiss>::vals =
190    {"data_real_translation_miss", 0x03F, 1203, {H, H, H}};
191
192//XXX This trap is apparently dropped from ua2005
193/*template<> SparcFaultBase::FaultVals
194    SparcFault<AsyncDataError>::vals =
195    {"async_data", 0x040, 2, {H, H, H}};*/
196
197template<> SparcFaultBase::FaultVals
198    SparcFault<InterruptLevelN>::vals =
199    {"interrupt_level_n", 0x041, 0, {P, P, SH}};
200
201template<> SparcFaultBase::FaultVals
202    SparcFault<HstickMatch>::vals =
203    {"hstick_match", 0x05E, 1601, {H, H, H}};
204
205template<> SparcFaultBase::FaultVals
206    SparcFault<TrapLevelZero>::vals =
207    {"trap_level_zero", 0x05F, 202, {H, H, SH}};
208
209template<> SparcFaultBase::FaultVals
210    SparcFault<PAWatchpoint>::vals =
211    {"PA_watchpoint", 0x061, 1209, {H, H, H}};
212
213template<> SparcFaultBase::FaultVals
214    SparcFault<VAWatchpoint>::vals =
215    {"VA_watchpoint", 0x062, 1120, {P, P, SH}};
216
217template<> SparcFaultBase::FaultVals
218    SparcFault<FastInstructionAccessMMUMiss>::vals =
219    {"fast_instruction_access_MMU_miss", 0x064, 208, {H, H, SH}};
220
221template<> SparcFaultBase::FaultVals
222    SparcFault<FastDataAccessMMUMiss>::vals =
223    {"fast_data_access_MMU_miss", 0x068, 1203, {H, H, H}};
224
225template<> SparcFaultBase::FaultVals
226    SparcFault<FastDataAccessProtection>::vals =
227    {"fast_data_access_protection", 0x06C, 1207, {H, H, H}};
228
229template<> SparcFaultBase::FaultVals
230    SparcFault<InstructionBreakpoint>::vals =
231    {"instruction_break", 0x076, 610, {H, H, H}};
232
233template<> SparcFaultBase::FaultVals
234    SparcFault<CpuMondo>::vals =
235    {"cpu_mondo", 0x07C, 1608, {P, P, SH}};
236
237template<> SparcFaultBase::FaultVals
238    SparcFault<DevMondo>::vals =
239    {"dev_mondo", 0x07D, 1611, {P, P, SH}};
240
241template<> SparcFaultBase::FaultVals
242    SparcFault<ResumeableError>::vals =
243    {"resume_error", 0x07E, 3330, {P, P, SH}};
244
245template<> SparcFaultBase::FaultVals
246    SparcFault<SpillNNormal>::vals =
247    {"spill_n_normal", 0x080, 900, {P, P, H}};
248
249template<> SparcFaultBase::FaultVals
250    SparcFault<SpillNOther>::vals =
251    {"spill_n_other", 0x0A0, 900, {P, P, H}};
252
253template<> SparcFaultBase::FaultVals
254    SparcFault<FillNNormal>::vals =
255    {"fill_n_normal", 0x0C0, 900, {P, P, H}};
256
257template<> SparcFaultBase::FaultVals
258    SparcFault<FillNOther>::vals =
259    {"fill_n_other", 0x0E0, 900, {P, P, H}};
260
261template<> SparcFaultBase::FaultVals
262    SparcFault<TrapInstruction>::vals =
263    {"trap_instruction", 0x100, 1602, {P, P, H}};
264
265#if !FULL_SYSTEM
266template<> SparcFaultBase::FaultVals
267    SparcFault<PageTableFault>::vals =
268    {"page_table_fault", 0x0000, 0, {SH, SH, SH}};
269#endif
270
271/**
272 * This sets everything up for a normal trap except for actually jumping to
273 * the handler. It will need to be expanded to include the state machine in
274 * the manual. Right now it assumes that traps will always be to the
275 * privileged level.
276 */
277
278void doNormalFault(ThreadContext *tc, TrapType tt)
279{
280    uint64_t TL = tc->readMiscReg(MISCREG_TL);
281    uint64_t TSTATE = tc->readMiscReg(MISCREG_TSTATE);
282    uint64_t PSTATE = tc->readMiscReg(MISCREG_PSTATE);
283    uint64_t HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
284    uint64_t CCR = tc->readMiscReg(MISCREG_CCR);
285    uint64_t ASI = tc->readMiscReg(MISCREG_ASI);
286    uint64_t CWP = tc->readMiscReg(MISCREG_CWP);
287    uint64_t CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
288    uint64_t GL = tc->readMiscReg(MISCREG_GL);
289    uint64_t PC = tc->readPC();
290    uint64_t NPC = tc->readNextPC();
291
292    //Increment the trap level
293    TL++;
294    tc->setMiscReg(MISCREG_TL, TL);
295
296    //Save off state
297
298    //set TSTATE.gl to gl
299    replaceBits(TSTATE, 42, 40, GL);
300    //set TSTATE.ccr to ccr
301    replaceBits(TSTATE, 39, 32, CCR);
302    //set TSTATE.asi to asi
303    replaceBits(TSTATE, 31, 24, ASI);
304    //set TSTATE.pstate to pstate
305    replaceBits(TSTATE, 20, 8, PSTATE);
306    //set TSTATE.cwp to cwp
307    replaceBits(TSTATE, 4, 0, CWP);
308
309    //Write back TSTATE
310    tc->setMiscReg(MISCREG_TSTATE, TSTATE);
311
312    //set TPC to PC
313    tc->setMiscReg(MISCREG_TPC, PC);
314    //set TNPC to NPC
315    tc->setMiscReg(MISCREG_TNPC, NPC);
316
317    //set HTSTATE.hpstate to hpstate
318    tc->setMiscReg(MISCREG_HTSTATE, HPSTATE);
319
320    //TT = trap type;
321    tc->setMiscReg(MISCREG_TT, tt);
322
323    //Update the global register level
324    if(1/*We're delivering the trap in priveleged mode*/)
325        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
326    else
327        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxPGL));
328
329    //PSTATE.mm is unchanged
330    //PSTATE.pef = whether or not an fpu is present
331    //XXX We'll say there's one present, even though there aren't
332    //implementations for a decent number of the instructions
333    PSTATE |= (1 << 4);
334    //PSTATE.am = 0
335    PSTATE &= ~(1 << 3);
336    if(1/*We're delivering the trap in priveleged mode*/)
337    {
338        //PSTATE.priv = 1
339        PSTATE |= (1 << 2);
340        //PSTATE.cle = PSTATE.tle
341        replaceBits(PSTATE, 9, 9, PSTATE >> 8);
342    }
343    else
344    {
345        //PSTATE.priv = 0
346        PSTATE &= ~(1 << 2);
347        //PSTATE.cle = 0
348        PSTATE &= ~(1 << 9);
349    }
350    //PSTATE.ie = 0
351    PSTATE &= ~(1 << 1);
352    //PSTATE.tle is unchanged
353    //PSTATE.tct = 0
354    //XXX Where exactly is this field?
355    tc->setMiscReg(MISCREG_PSTATE, PSTATE);
356
357    if(0/*We're delivering the trap in hyperprivileged mode*/)
358    {
359        //HPSTATE.red = 0
360        HPSTATE &= ~(1 << 5);
361        //HPSTATE.hpriv = 1
362        HPSTATE |= (1 << 2);
363        //HPSTATE.ibe = 0
364        HPSTATE &= ~(1 << 10);
365        //HPSTATE.tlz is unchanged
366        tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
367    }
368
369    bool changedCWP = true;
370    if(tt == 0x24)
371        CWP++;
372    else if(0x80 <= tt && tt <= 0xbf)
373        CWP += (CANSAVE + 2);
374    else if(0xc0 <= tt && tt <= 0xff)
375        CWP--;
376    else
377        changedCWP = false;
378
379    if(changedCWP)
380    {
381        CWP = (CWP + NWindows) % NWindows;
382        tc->setMiscRegWithEffect(MISCREG_CWP, CWP);
383    }
384}
385
386#if FULL_SYSTEM
387
388void SparcFaultBase::invoke(ThreadContext * tc)
389{
390    FaultBase::invoke(tc);
391    countStat()++;
392
393    //Use the SPARC trap state machine
394}
395
396void PowerOnReset::invoke(ThreadContext * tc)
397{
398    //For SPARC, when a system is first started, there is a power
399    //on reset Trap which sets the processor into the following state.
400    //Bits that aren't set aren't defined on startup.
401    /*
402    tl = MaxTL;
403    gl = MaxGL;
404
405    tickFields.counter = 0; //The TICK register is unreadable bya
406    tickFields.npt = 1; //The TICK register is unreadable by by !priv
407
408    softint = 0; // Clear all the soft interrupt bits
409    tick_cmprFields.int_dis = 1; // disable timer compare interrupts
410    tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
411    stickFields.npt = 1; //The TICK register is unreadable by by !priv
412    stick_cmprFields.int_dis = 1; // disable timer compare interrupts
413    stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
414
415    tt[tl] = _trapType;
416    pstate = 0; // fields 0 but pef
417    pstateFields.pef = 1;
418
419    hpstate = 0;
420    hpstateFields.red = 1;
421    hpstateFields.hpriv = 1;
422    hpstateFields.tlz = 0; // this is a guess
423    hintp = 0; // no interrupts pending
424    hstick_cmprFields.int_dis = 1; // disable timer compare interrupts
425    hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
426    */
427}
428
429#endif
430
431#if !FULL_SYSTEM
432
433void SpillNNormal::invoke(ThreadContext *tc)
434{
435    doNormalFault(tc, trapType());
436
437    Process *p = tc->getProcessPtr();
438
439    //This will only work in faults from a SparcLiveProcess
440    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
441    assert(lp);
442
443    //Then adjust the PC and NPC
444    Addr spillStart = lp->readSpillStart();
445    tc->setPC(spillStart);
446    tc->setNextPC(spillStart + sizeof(MachInst));
447    tc->setNextNPC(spillStart + 2*sizeof(MachInst));
448}
449
450void FillNNormal::invoke(ThreadContext *tc)
451{
452    doNormalFault(tc, trapType());
453
454    Process * p = tc->getProcessPtr();
455
456    //This will only work in faults from a SparcLiveProcess
457    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
458    assert(lp);
459
460    //The adjust the PC and NPC
461    Addr fillStart = lp->readFillStart();
462    tc->setPC(fillStart);
463    tc->setNextPC(fillStart + sizeof(MachInst));
464    tc->setNextNPC(fillStart + 2*sizeof(MachInst));
465}
466
467void PageTableFault::invoke(ThreadContext *tc)
468{
469    Process *p = tc->getProcessPtr();
470
471    // address is higher than the stack region or in the current stack region
472    if (vaddr > p->stack_base || vaddr > p->stack_min)
473        FaultBase::invoke(tc);
474
475    // We've accessed the next page
476    if (vaddr > p->stack_min - PageBytes) {
477        p->stack_min -= PageBytes;
478        if (p->stack_base - p->stack_min > 8*1024*1024)
479            fatal("Over max stack size for one thread\n");
480        p->pTable->allocate(p->stack_min, PageBytes);
481        warn("Increasing stack size by one page.");
482    } else {
483        FaultBase::invoke(tc);
484    }
485}
486
487#endif
488
489} // namespace SparcISA
490
491