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