faults.cc revision 3574:dbddfe6ebb2d
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<InternalProcessorError>::vals = {"intprocerr", 0x029, 4};
54
55template<> SparcFaultBase::FaultVals
56    SparcFault<MemAddressNotAligned>::vals = {"unalign", 0x034, 10};
57
58template<> SparcFaultBase::FaultVals
59    SparcFault<PowerOnReset>::vals = {"pow_reset", 0x001, 0};
60
61template<> SparcFaultBase::FaultVals
62    SparcFault<WatchDogReset>::vals = {"watch_dog_reset", 0x002, 1};
63
64template<> SparcFaultBase::FaultVals
65    SparcFault<ExternallyInitiatedReset>::vals = {"extern_reset", 0x003, 1};
66
67template<> SparcFaultBase::FaultVals
68    SparcFault<SoftwareInitiatedReset>::vals = {"software_reset", 0x004, 1};
69
70template<> SparcFaultBase::FaultVals
71    SparcFault<REDStateException>::vals = {"red_counte", 0x005, 1};
72
73template<> SparcFaultBase::FaultVals
74    SparcFault<InstructionAccessException>::vals = {"inst_access", 0x008, 5};
75
76template<> SparcFaultBase::FaultVals
77    SparcFault<InstructionAccessMMUMiss>::vals = {"inst_mmu", 0x009, 2};
78
79template<> SparcFaultBase::FaultVals
80    SparcFault<InstructionAccessError>::vals = {"inst_error", 0x00A, 3};
81
82template<> SparcFaultBase::FaultVals
83    SparcFault<IllegalInstruction>::vals = {"illegal_inst", 0x010, 7};
84
85template<> SparcFaultBase::FaultVals
86    SparcFault<PrivilegedOpcode>::vals = {"priv_opcode", 0x011, 6};
87
88template<> SparcFaultBase::FaultVals
89    SparcFault<UnimplementedLDD>::vals = {"unimp_ldd", 0x012, 6};
90
91template<> SparcFaultBase::FaultVals
92    SparcFault<UnimplementedSTD>::vals = {"unimp_std", 0x013, 6};
93
94template<> SparcFaultBase::FaultVals
95    SparcFault<FpDisabled>::vals = {"fp_disabled", 0x020, 8};
96
97template<> SparcFaultBase::FaultVals
98    SparcFault<FpExceptionIEEE754>::vals = {"fp_754", 0x021, 11};
99
100template<> SparcFaultBase::FaultVals
101    SparcFault<FpExceptionOther>::vals = {"fp_other", 0x022, 11};
102
103template<> SparcFaultBase::FaultVals
104    SparcFault<TagOverflow>::vals = {"tag_overflow", 0x023, 14};
105
106template<> SparcFaultBase::FaultVals
107    SparcFault<DivisionByZero>::vals = {"div_by_zero", 0x028, 15};
108
109template<> SparcFaultBase::FaultVals
110    SparcFault<DataAccessException>::vals = {"data_access", 0x030, 12};
111
112template<> SparcFaultBase::FaultVals
113    SparcFault<DataAccessMMUMiss>::vals = {"data_mmu", 0x031, 12};
114
115template<> SparcFaultBase::FaultVals
116    SparcFault<DataAccessError>::vals = {"data_error", 0x032, 12};
117
118template<> SparcFaultBase::FaultVals
119    SparcFault<DataAccessProtection>::vals = {"data_protection", 0x033, 12};
120
121template<> SparcFaultBase::FaultVals
122    SparcFault<LDDFMemAddressNotAligned>::vals = {"unalign_lddf", 0x035, 10};
123
124template<> SparcFaultBase::FaultVals
125    SparcFault<STDFMemAddressNotAligned>::vals = {"unalign_stdf", 0x036, 10};
126
127template<> SparcFaultBase::FaultVals
128    SparcFault<PrivilegedAction>::vals = {"priv_action", 0x037, 11};
129
130template<> SparcFaultBase::FaultVals
131    SparcFault<LDQFMemAddressNotAligned>::vals = {"unalign_ldqf", 0x038, 10};
132
133template<> SparcFaultBase::FaultVals
134    SparcFault<STQFMemAddressNotAligned>::vals = {"unalign_stqf", 0x039, 10};
135
136template<> SparcFaultBase::FaultVals
137    SparcFault<AsyncDataError>::vals = {"async_data", 0x040, 2};
138
139template<> SparcFaultBase::FaultVals
140    SparcFault<CleanWindow>::vals = {"clean_win", 0x024, 10};
141
142//The enumerated faults
143
144template<> SparcFaultBase::FaultVals
145    SparcFault<InterruptLevelN>::vals = {"interrupt_n", 0x041, 0};
146
147template<> SparcFaultBase::FaultVals
148    SparcFault<SpillNNormal>::vals = {"spill_n_normal", 0x080, 9};
149
150template<> SparcFaultBase::FaultVals
151    SparcFault<SpillNOther>::vals = {"spill_n_other", 0x0A0, 9};
152
153template<> SparcFaultBase::FaultVals
154    SparcFault<FillNNormal>::vals = {"fill_n_normal", 0x0C0, 9};
155
156template<> SparcFaultBase::FaultVals
157    SparcFault<FillNOther>::vals = {"fill_n_other", 0x0E0, 9};
158
159template<> SparcFaultBase::FaultVals
160    SparcFault<TrapInstruction>::vals = {"trap_inst_n", 0x100, 16};
161
162#if !FULL_SYSTEM
163template<> SparcFaultBase::FaultVals
164    SparcFault<PageTableFault>::vals = {"page_table_fault", 0x0000, 0};
165#endif
166
167/**
168 * This sets everything up for a normal trap except for actually jumping to
169 * the handler. It will need to be expanded to include the state machine in
170 * the manual. Right now it assumes that traps will always be to the
171 * privileged level.
172 */
173
174void doNormalFault(ThreadContext *tc, TrapType tt)
175{
176    uint64_t TL = tc->readMiscReg(MISCREG_TL);
177    uint64_t TSTATE = tc->readMiscReg(MISCREG_TSTATE);
178    uint64_t PSTATE = tc->readMiscReg(MISCREG_PSTATE);
179    uint64_t HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
180    uint64_t CCR = tc->readMiscReg(MISCREG_CCR);
181    uint64_t ASI = tc->readMiscReg(MISCREG_ASI);
182    uint64_t CWP = tc->readMiscReg(MISCREG_CWP);
183    uint64_t CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
184    uint64_t GL = tc->readMiscReg(MISCREG_GL);
185    uint64_t PC = tc->readPC();
186    uint64_t NPC = tc->readNextPC();
187
188    //Increment the trap level
189    TL++;
190    tc->setMiscReg(MISCREG_TL, TL);
191
192    //Save off state
193
194    //set TSTATE.gl to gl
195    replaceBits(TSTATE, 42, 40, GL);
196    //set TSTATE.ccr to ccr
197    replaceBits(TSTATE, 39, 32, CCR);
198    //set TSTATE.asi to asi
199    replaceBits(TSTATE, 31, 24, ASI);
200    //set TSTATE.pstate to pstate
201    replaceBits(TSTATE, 20, 8, PSTATE);
202    //set TSTATE.cwp to cwp
203    replaceBits(TSTATE, 4, 0, CWP);
204
205    //Write back TSTATE
206    tc->setMiscReg(MISCREG_TSTATE, TSTATE);
207
208    //set TPC to PC
209    tc->setMiscReg(MISCREG_TPC, PC);
210    //set TNPC to NPC
211    tc->setMiscReg(MISCREG_TNPC, NPC);
212
213    //set HTSTATE.hpstate to hpstate
214    tc->setMiscReg(MISCREG_HTSTATE, HPSTATE);
215
216    //TT = trap type;
217    tc->setMiscReg(MISCREG_TT, tt);
218
219    //Update the global register level
220    if(1/*We're delivering the trap in priveleged mode*/)
221        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
222    else
223        tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxPGL));
224
225    //PSTATE.mm is unchanged
226    //PSTATE.pef = whether or not an fpu is present
227    //XXX We'll say there's one present, even though there aren't
228    //implementations for a decent number of the instructions
229    PSTATE |= (1 << 4);
230    //PSTATE.am = 0
231    PSTATE &= ~(1 << 3);
232    if(1/*We're delivering the trap in priveleged mode*/)
233    {
234        //PSTATE.priv = 1
235        PSTATE |= (1 << 2);
236        //PSTATE.cle = PSTATE.tle
237        replaceBits(PSTATE, 9, 9, PSTATE >> 8);
238    }
239    else
240    {
241        //PSTATE.priv = 0
242        PSTATE &= ~(1 << 2);
243        //PSTATE.cle = 0
244        PSTATE &= ~(1 << 9);
245    }
246    //PSTATE.ie = 0
247    PSTATE &= ~(1 << 1);
248    //PSTATE.tle is unchanged
249    //PSTATE.tct = 0
250    //XXX Where exactly is this field?
251    tc->setMiscReg(MISCREG_PSTATE, PSTATE);
252
253    if(0/*We're delivering the trap in hyperprivileged mode*/)
254    {
255        //HPSTATE.red = 0
256        HPSTATE &= ~(1 << 5);
257        //HPSTATE.hpriv = 1
258        HPSTATE |= (1 << 2);
259        //HPSTATE.ibe = 0
260        HPSTATE &= ~(1 << 10);
261        //HPSTATE.tlz is unchanged
262        tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
263    }
264
265    bool changedCWP = true;
266    if(tt == 0x24)
267        CWP++;
268    else if(0x80 <= tt && tt <= 0xbf)
269        CWP += (CANSAVE + 2);
270    else if(0xc0 <= tt && tt <= 0xff)
271        CWP--;
272    else
273        changedCWP = false;
274
275    if(changedCWP)
276    {
277        CWP = (CWP + NWindows) % NWindows;
278        tc->setMiscRegWithEffect(MISCREG_CWP, CWP);
279    }
280}
281
282#if FULL_SYSTEM
283
284void SparcFaultBase::invoke(ThreadContext * tc)
285{
286    FaultBase::invoke(tc);
287    countStat()++;
288
289    //Use the SPARC trap state machine
290}
291
292void PowerOnReset::invoke(ThreadContext * tc)
293{
294    //For SPARC, when a system is first started, there is a power
295    //on reset Trap which sets the processor into the following state.
296    //Bits that aren't set aren't defined on startup.
297    /*
298    tl = MaxTL;
299    gl = MaxGL;
300
301    tickFields.counter = 0; //The TICK register is unreadable bya
302    tickFields.npt = 1; //The TICK register is unreadable by by !priv
303
304    softint = 0; // Clear all the soft interrupt bits
305    tick_cmprFields.int_dis = 1; // disable timer compare interrupts
306    tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
307    stickFields.npt = 1; //The TICK register is unreadable by by !priv
308    stick_cmprFields.int_dis = 1; // disable timer compare interrupts
309    stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
310
311    tt[tl] = _trapType;
312    pstate = 0; // fields 0 but pef
313    pstateFields.pef = 1;
314
315    hpstate = 0;
316    hpstateFields.red = 1;
317    hpstateFields.hpriv = 1;
318    hpstateFields.tlz = 0; // this is a guess
319    hintp = 0; // no interrupts pending
320    hstick_cmprFields.int_dis = 1; // disable timer compare interrupts
321    hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
322    */
323}
324
325#endif
326
327#if !FULL_SYSTEM
328
329void SpillNNormal::invoke(ThreadContext *tc)
330{
331    doNormalFault(tc, trapType());
332
333    Process *p = tc->getProcessPtr();
334
335    //This will only work in faults from a SparcLiveProcess
336    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
337    assert(lp);
338
339    //Then adjust the PC and NPC
340    Addr spillStart = lp->readSpillStart();
341    tc->setPC(spillStart);
342    tc->setNextPC(spillStart + sizeof(MachInst));
343    tc->setNextNPC(spillStart + 2*sizeof(MachInst));
344}
345
346void FillNNormal::invoke(ThreadContext *tc)
347{
348    doNormalFault(tc, trapType());
349
350    Process * p = tc->getProcessPtr();
351
352    //This will only work in faults from a SparcLiveProcess
353    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
354    assert(lp);
355
356    //The adjust the PC and NPC
357    Addr fillStart = lp->readFillStart();
358    tc->setPC(fillStart);
359    tc->setNextPC(fillStart + sizeof(MachInst));
360    tc->setNextNPC(fillStart + 2*sizeof(MachInst));
361}
362
363void PageTableFault::invoke(ThreadContext *tc)
364{
365    Process *p = tc->getProcessPtr();
366
367    // address is higher than the stack region or in the current stack region
368    if (vaddr > p->stack_base || vaddr > p->stack_min)
369        FaultBase::invoke(tc);
370
371    // We've accessed the next page
372    if (vaddr > p->stack_min - PageBytes) {
373        p->stack_min -= PageBytes;
374        if (p->stack_base - p->stack_min > 8*1024*1024)
375            fatal("Over max stack size for one thread\n");
376        p->pTable->allocate(p->stack_min, PageBytes);
377        warn("Increasing stack size by one page.");
378    } else {
379        FaultBase::invoke(tc);
380    }
381}
382
383#endif
384
385} // namespace SparcISA
386
387