faults.cc revision 11850
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 "arch/sparc/faults.hh"
33
34#include <algorithm>
35
36#include "arch/sparc/isa_traits.hh"
37#include "arch/sparc/process.hh"
38#include "arch/sparc/types.hh"
39#include "base/bitfield.hh"
40#include "base/trace.hh"
41#include "cpu/base.hh"
42#include "cpu/thread_context.hh"
43#include "mem/page_table.hh"
44#include "sim/full_system.hh"
45#include "sim/process.hh"
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}, FaultStat()};
55
56template<> SparcFaultBase::FaultVals
57    SparcFault<WatchDogReset>::vals =
58{"watch_dog_reset", 0x002, 120, {H, H, H}, FaultStat()};
59
60template<> SparcFaultBase::FaultVals
61    SparcFault<ExternallyInitiatedReset>::vals =
62{"externally_initiated_reset", 0x003, 110, {H, H, H}, FaultStat()};
63
64template<> SparcFaultBase::FaultVals
65    SparcFault<SoftwareInitiatedReset>::vals =
66{"software_initiated_reset", 0x004, 130, {SH, SH, H}, FaultStat()};
67
68template<> SparcFaultBase::FaultVals
69    SparcFault<REDStateException>::vals =
70{"RED_state_exception", 0x005, 1, {H, H, H}, FaultStat()};
71
72template<> SparcFaultBase::FaultVals
73    SparcFault<StoreError>::vals =
74{"store_error", 0x007, 201, {H, H, H}, FaultStat()};
75
76template<> SparcFaultBase::FaultVals
77    SparcFault<InstructionAccessException>::vals =
78{"instruction_access_exception", 0x008, 300, {H, H, H}, FaultStat()};
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}, FaultStat()};
88
89template<> SparcFaultBase::FaultVals
90    SparcFault<IllegalInstruction>::vals =
91{"illegal_instruction", 0x010, 620, {H, H, H}, FaultStat()};
92
93template<> SparcFaultBase::FaultVals
94    SparcFault<PrivilegedOpcode>::vals =
95{"privileged_opcode", 0x011, 700, {P, SH, SH}, FaultStat()};
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}, FaultStat()};
110
111template<> SparcFaultBase::FaultVals
112    SparcFault<FpExceptionIEEE754>::vals =
113{"fp_exception_ieee_754", 0x021, 1110, {P, P, H}, FaultStat()};
114
115template<> SparcFaultBase::FaultVals
116    SparcFault<FpExceptionOther>::vals =
117{"fp_exception_other", 0x022, 1110, {P, P, H}, FaultStat()};
118
119template<> SparcFaultBase::FaultVals
120    SparcFault<TagOverflow>::vals =
121{"tag_overflow", 0x023, 1400, {P, P, H}, FaultStat()};
122
123template<> SparcFaultBase::FaultVals
124    SparcFault<CleanWindow>::vals =
125{"clean_window", 0x024, 1010, {P, P, H}, FaultStat()};
126
127template<> SparcFaultBase::FaultVals
128    SparcFault<DivisionByZero>::vals =
129{"division_by_zero", 0x028, 1500, {P, P, H}, FaultStat()};
130
131template<> SparcFaultBase::FaultVals
132    SparcFault<InternalProcessorError>::vals =
133{"internal_processor_error", 0x029, 4, {H, H, H}, FaultStat()};
134
135template<> SparcFaultBase::FaultVals
136    SparcFault<InstructionInvalidTSBEntry>::vals =
137{"instruction_invalid_tsb_entry", 0x02A, 210, {H, H, SH}, FaultStat()};
138
139template<> SparcFaultBase::FaultVals
140    SparcFault<DataInvalidTSBEntry>::vals =
141{"data_invalid_tsb_entry", 0x02B, 1203, {H, H, H}, FaultStat()};
142
143template<> SparcFaultBase::FaultVals
144    SparcFault<DataAccessException>::vals =
145{"data_access_exception", 0x030, 1201, {H, H, H}, FaultStat()};
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}, FaultStat()};
155
156template<> SparcFaultBase::FaultVals
157    SparcFault<DataAccessProtection>::vals =
158{"data_access_protection", 0x033, 1207, {H, H, H}, FaultStat()};
159
160template<> SparcFaultBase::FaultVals
161    SparcFault<MemAddressNotAligned>::vals =
162{"mem_address_not_aligned", 0x034, 1020, {H, H, H}, FaultStat()};
163
164template<> SparcFaultBase::FaultVals
165    SparcFault<LDDFMemAddressNotAligned>::vals =
166{"LDDF_mem_address_not_aligned", 0x035, 1010, {H, H, H}, FaultStat()};
167
168template<> SparcFaultBase::FaultVals
169    SparcFault<STDFMemAddressNotAligned>::vals =
170{"STDF_mem_address_not_aligned", 0x036, 1010, {H, H, H}, FaultStat()};
171
172template<> SparcFaultBase::FaultVals
173    SparcFault<PrivilegedAction>::vals =
174{"privileged_action", 0x037, 1110, {H, H, SH}, FaultStat()};
175
176template<> SparcFaultBase::FaultVals
177    SparcFault<LDQFMemAddressNotAligned>::vals =
178{"LDQF_mem_address_not_aligned", 0x038, 1010, {H, H, H}, FaultStat()};
179
180template<> SparcFaultBase::FaultVals
181    SparcFault<STQFMemAddressNotAligned>::vals =
182{"STQF_mem_address_not_aligned", 0x039, 1010, {H, H, H}, FaultStat()};
183
184template<> SparcFaultBase::FaultVals
185    SparcFault<InstructionRealTranslationMiss>::vals =
186{"instruction_real_translation_miss", 0x03E, 208, {H, H, SH}, FaultStat()};
187
188template<> SparcFaultBase::FaultVals
189    SparcFault<DataRealTranslationMiss>::vals =
190{"data_real_translation_miss", 0x03F, 1203, {H, H, H}, FaultStat()};
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", 0x040, 0, {P, P, SH}, FaultStat()};
200
201template<> SparcFaultBase::FaultVals
202    SparcFault<HstickMatch>::vals =
203{"hstick_match", 0x05E, 1601, {H, H, H}, FaultStat()};
204
205template<> SparcFaultBase::FaultVals
206    SparcFault<TrapLevelZero>::vals =
207{"trap_level_zero", 0x05F, 202, {H, H, SH}, FaultStat()};
208
209template<> SparcFaultBase::FaultVals
210    SparcFault<InterruptVector>::vals =
211{"interrupt_vector", 0x060, 2630, {H, H, H}, FaultStat()};
212
213template<> SparcFaultBase::FaultVals
214    SparcFault<PAWatchpoint>::vals =
215{"PA_watchpoint", 0x061, 1209, {H, H, H}, FaultStat()};
216
217template<> SparcFaultBase::FaultVals
218    SparcFault<VAWatchpoint>::vals =
219{"VA_watchpoint", 0x062, 1120, {P, P, SH}, FaultStat()};
220
221template<> SparcFaultBase::FaultVals
222    SparcFault<FastInstructionAccessMMUMiss>::vals =
223{"fast_instruction_access_MMU_miss", 0x064, 208, {H, H, SH}, FaultStat()};
224
225template<> SparcFaultBase::FaultVals
226    SparcFault<FastDataAccessMMUMiss>::vals =
227{"fast_data_access_MMU_miss", 0x068, 1203, {H, H, H}, FaultStat()};
228
229template<> SparcFaultBase::FaultVals
230    SparcFault<FastDataAccessProtection>::vals =
231{"fast_data_access_protection", 0x06C, 1207, {H, H, H}, FaultStat()};
232
233template<> SparcFaultBase::FaultVals
234    SparcFault<InstructionBreakpoint>::vals =
235{"instruction_break", 0x076, 610, {H, H, H}, FaultStat()};
236
237template<> SparcFaultBase::FaultVals
238    SparcFault<CpuMondo>::vals =
239{"cpu_mondo", 0x07C, 1608, {P, P, SH}, FaultStat()};
240
241template<> SparcFaultBase::FaultVals
242    SparcFault<DevMondo>::vals =
243{"dev_mondo", 0x07D, 1611, {P, P, SH}, FaultStat()};
244
245template<> SparcFaultBase::FaultVals
246    SparcFault<ResumableError>::vals =
247{"resume_error", 0x07E, 3330, {P, P, SH}, FaultStat()};
248
249template<> SparcFaultBase::FaultVals
250    SparcFault<SpillNNormal>::vals =
251{"spill_n_normal", 0x080, 900, {P, P, H}, FaultStat()};
252
253template<> SparcFaultBase::FaultVals
254    SparcFault<SpillNOther>::vals =
255{"spill_n_other", 0x0A0, 900, {P, P, H}, FaultStat()};
256
257template<> SparcFaultBase::FaultVals
258    SparcFault<FillNNormal>::vals =
259{"fill_n_normal", 0x0C0, 900, {P, P, H}, FaultStat()};
260
261template<> SparcFaultBase::FaultVals
262    SparcFault<FillNOther>::vals =
263{"fill_n_other", 0x0E0, 900, {P, P, H}, FaultStat()};
264
265template<> SparcFaultBase::FaultVals
266    SparcFault<TrapInstruction>::vals =
267{"trap_instruction", 0x100, 1602, {P, P, H}, FaultStat()};
268
269/**
270 * This causes the thread context to enter RED state. This causes the side
271 * effects which go with entering RED state because of a trap.
272 */
273
274void
275enterREDState(ThreadContext *tc)
276{
277    //@todo Disable the mmu?
278    //@todo Disable watchpoints?
279    HPSTATE hpstate= tc->readMiscRegNoEffect(MISCREG_HPSTATE);
280    hpstate.red = 1;
281    hpstate.hpriv = 1;
282    tc->setMiscReg(MISCREG_HPSTATE, hpstate);
283    // PSTATE.priv is set to 1 here. The manual says it should be 0, but
284    // Legion sets it to 1.
285    PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
286    pstate.priv = 1;
287    tc->setMiscReg(MISCREG_PSTATE, pstate);
288}
289
290/**
291 * This sets everything up for a RED state trap except for actually jumping to
292 * the handler.
293 */
294
295void
296doREDFault(ThreadContext *tc, TrapType tt)
297{
298    MiscReg TL = tc->readMiscRegNoEffect(MISCREG_TL);
299    MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE);
300    PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
301    HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
302    MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);
303    MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI);
304    MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP);
305    MiscReg CANSAVE = tc->readMiscRegNoEffect(NumIntArchRegs + 3);
306    MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);
307    PCState pc = tc->pcState();
308
309    TL++;
310
311    Addr pcMask = pstate.am ? mask(32) : mask(64);
312
313    // set TSTATE.gl to gl
314    replaceBits(TSTATE, 42, 40, GL);
315    // set TSTATE.ccr to ccr
316    replaceBits(TSTATE, 39, 32, CCR);
317    // set TSTATE.asi to asi
318    replaceBits(TSTATE, 31, 24, ASI);
319    // set TSTATE.pstate to pstate
320    replaceBits(TSTATE, 20, 8, pstate);
321    // set TSTATE.cwp to cwp
322    replaceBits(TSTATE, 4, 0, CWP);
323
324    // Write back TSTATE
325    tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);
326
327    // set TPC to PC
328    tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask);
329    // set TNPC to NPC
330    tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask);
331
332    // set HTSTATE.hpstate to hpstate
333    tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate);
334
335    // TT = trap type;
336    tc->setMiscRegNoEffect(MISCREG_TT, tt);
337
338    // Update GL
339    tc->setMiscReg(MISCREG_GL, min<int>(GL+1, MaxGL));
340
341    bool priv = pstate.priv; // just save the priv bit
342    pstate = 0;
343    pstate.priv = priv;
344    pstate.pef = 1;
345    tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate);
346
347    hpstate.red = 1;
348    hpstate.hpriv = 1;
349    hpstate.ibe = 0;
350    hpstate.tlz = 0;
351    tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate);
352
353    bool changedCWP = true;
354    if (tt == 0x24)
355        CWP++;
356    else if (0x80 <= tt && tt <= 0xbf)
357        CWP += (CANSAVE + 2);
358    else if (0xc0 <= tt && tt <= 0xff)
359        CWP--;
360    else
361        changedCWP = false;
362
363    if (changedCWP) {
364        CWP = (CWP + NWindows) % NWindows;
365        tc->setMiscReg(MISCREG_CWP, CWP);
366    }
367}
368
369/**
370 * This sets everything up for a normal trap except for actually jumping to
371 * the handler.
372 */
373
374void
375doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv)
376{
377    MiscReg TL = tc->readMiscRegNoEffect(MISCREG_TL);
378    MiscReg TSTATE = tc->readMiscRegNoEffect(MISCREG_TSTATE);
379    PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
380    HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
381    MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2);
382    MiscReg ASI = tc->readMiscRegNoEffect(MISCREG_ASI);
383    MiscReg CWP = tc->readMiscRegNoEffect(MISCREG_CWP);
384    MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3);
385    MiscReg GL = tc->readMiscRegNoEffect(MISCREG_GL);
386    PCState pc = tc->pcState();
387
388    // Increment the trap level
389    TL++;
390    tc->setMiscRegNoEffect(MISCREG_TL, TL);
391
392    Addr pcMask = pstate.am ? mask(32) : mask(64);
393
394    // Save off state
395
396    // set TSTATE.gl to gl
397    replaceBits(TSTATE, 42, 40, GL);
398    // set TSTATE.ccr to ccr
399    replaceBits(TSTATE, 39, 32, CCR);
400    // set TSTATE.asi to asi
401    replaceBits(TSTATE, 31, 24, ASI);
402    // set TSTATE.pstate to pstate
403    replaceBits(TSTATE, 20, 8, pstate);
404    // set TSTATE.cwp to cwp
405    replaceBits(TSTATE, 4, 0, CWP);
406
407    // Write back TSTATE
408    tc->setMiscRegNoEffect(MISCREG_TSTATE, TSTATE);
409
410    // set TPC to PC
411    tc->setMiscRegNoEffect(MISCREG_TPC, pc.pc() & pcMask);
412    // set TNPC to NPC
413    tc->setMiscRegNoEffect(MISCREG_TNPC, pc.npc() & pcMask);
414
415    // set HTSTATE.hpstate to hpstate
416    tc->setMiscRegNoEffect(MISCREG_HTSTATE, hpstate);
417
418    // TT = trap type;
419    tc->setMiscRegNoEffect(MISCREG_TT, tt);
420
421    // Update the global register level
422    if (!gotoHpriv)
423        tc->setMiscReg(MISCREG_GL, min<int>(GL + 1, MaxPGL));
424    else
425        tc->setMiscReg(MISCREG_GL, min<int>(GL + 1, MaxGL));
426
427    // pstate.mm is unchanged
428    pstate.pef = 1; // PSTATE.pef = whether or not an fpu is present
429    pstate.am = 0;
430    pstate.ie = 0;
431    // pstate.tle is unchanged
432    // pstate.tct = 0
433
434    if (gotoHpriv) {
435        pstate.cle = 0;
436        // The manual says PSTATE.priv should be 0, but Legion leaves it alone
437        hpstate.red = 0;
438        hpstate.hpriv = 1;
439        hpstate.ibe = 0;
440        // hpstate.tlz is unchanged
441        tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate);
442    } else { // we are going to priv
443        pstate.priv = 1;
444        pstate.cle = pstate.tle;
445    }
446    tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate);
447
448
449    bool changedCWP = true;
450    if (tt == 0x24)
451        CWP++;
452    else if (0x80 <= tt && tt <= 0xbf)
453        CWP += (CANSAVE + 2);
454    else if (0xc0 <= tt && tt <= 0xff)
455        CWP--;
456    else
457        changedCWP = false;
458
459    if (changedCWP) {
460        CWP = (CWP + NWindows) % NWindows;
461        tc->setMiscReg(MISCREG_CWP, CWP);
462    }
463}
464
465void
466getREDVector(MiscReg TT, Addr &PC, Addr &NPC)
467{
468    //XXX The following constant might belong in a header file.
469    const Addr RSTVAddr = 0xFFF0000000ULL;
470    PC = RSTVAddr | ((TT << 5) & 0xFF);
471    NPC = PC + sizeof(MachInst);
472}
473
474void
475getHyperVector(ThreadContext * tc, Addr &PC, Addr &NPC, MiscReg TT)
476{
477    Addr HTBA = tc->readMiscRegNoEffect(MISCREG_HTBA);
478    PC = (HTBA & ~mask(14)) | ((TT << 5) & mask(14));
479    NPC = PC + sizeof(MachInst);
480}
481
482void
483getPrivVector(ThreadContext *tc, Addr &PC, Addr &NPC, MiscReg TT, MiscReg TL)
484{
485    Addr TBA = tc->readMiscRegNoEffect(MISCREG_TBA);
486    PC = (TBA & ~mask(15)) |
487        (TL > 1 ? (1 << 14) : 0) |
488        ((TT << 5) & mask(14));
489    NPC = PC + sizeof(MachInst);
490}
491
492void
493SparcFaultBase::invoke(ThreadContext * tc, const StaticInstPtr &inst)
494{
495    FaultBase::invoke(tc);
496    if (!FullSystem)
497        return;
498
499    countStat()++;
500
501    // We can refer to this to see what the trap level -was-, but something
502    // in the middle could change it in the regfile out from under us.
503    MiscReg tl = tc->readMiscRegNoEffect(MISCREG_TL);
504    MiscReg tt = tc->readMiscRegNoEffect(MISCREG_TT);
505    PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
506    HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
507
508    Addr PC, NPC;
509
510    PrivilegeLevel current;
511    if (hpstate.hpriv)
512        current = Hyperprivileged;
513    else if (pstate.priv)
514        current = Privileged;
515    else
516        current = User;
517
518    PrivilegeLevel level = getNextLevel(current);
519
520    if (hpstate.red || (tl == MaxTL - 1)) {
521        getREDVector(5, PC, NPC);
522        doREDFault(tc, tt);
523        // This changes the hpstate and pstate, so we need to make sure we
524        // save the old version on the trap stack in doREDFault.
525        enterREDState(tc);
526    } else if (tl == MaxTL) {
527        panic("Should go to error state here.. crap\n");
528        // Do error_state somehow?
529        // Probably inject a WDR fault using the interrupt mechanism.
530        // What should the PC and NPC be set to?
531    } else if (tl > MaxPTL && level == Privileged) {
532        // guest_watchdog fault
533        doNormalFault(tc, trapType(), true);
534        getHyperVector(tc, PC, NPC, 2);
535    } else if (level == Hyperprivileged ||
536               (level == Privileged && trapType() >= 384)) {
537        doNormalFault(tc, trapType(), true);
538        getHyperVector(tc, PC, NPC, trapType());
539    } else {
540        doNormalFault(tc, trapType(), false);
541        getPrivVector(tc, PC, NPC, trapType(), tl + 1);
542    }
543
544    PCState pc;
545    pc.pc(PC);
546    pc.npc(NPC);
547    pc.nnpc(NPC + sizeof(MachInst));
548    pc.upc(0);
549    pc.nupc(1);
550    tc->pcState(pc);
551}
552
553void
554PowerOnReset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
555{
556    // For SPARC, when a system is first started, there is a power
557    // on reset Trap which sets the processor into the following state.
558    // Bits that aren't set aren't defined on startup.
559
560    tc->setMiscRegNoEffect(MISCREG_TL, MaxTL);
561    tc->setMiscRegNoEffect(MISCREG_TT, trapType());
562    tc->setMiscReg(MISCREG_GL, MaxGL);
563
564    PSTATE pstate = 0;
565    pstate.pef = 1;
566    pstate.priv = 1;
567    tc->setMiscRegNoEffect(MISCREG_PSTATE, pstate);
568
569    // Turn on red and hpriv, set everything else to 0
570    HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
571    hpstate.red = 1;
572    hpstate.hpriv = 1;
573    hpstate.ibe = 0;
574    hpstate.tlz = 0;
575    tc->setMiscRegNoEffect(MISCREG_HPSTATE, hpstate);
576
577    // The tick register is unreadable by nonprivileged software
578    tc->setMiscRegNoEffect(MISCREG_TICK, 1ULL << 63);
579
580    // Enter RED state. We do this last so that the actual state preserved in
581    // the trap stack is the state from before this fault.
582    enterREDState(tc);
583
584    Addr PC, NPC;
585    getREDVector(trapType(), PC, NPC);
586
587    PCState pc;
588    pc.pc(PC);
589    pc.npc(NPC);
590    pc.nnpc(NPC + sizeof(MachInst));
591    pc.upc(0);
592    pc.nupc(1);
593    tc->pcState(pc);
594
595    // These registers are specified as "undefined" after a POR, and they
596    // should have reasonable values after the miscregfile is reset
597    /*
598    // Clear all the soft interrupt bits
599    softint = 0;
600    // disable timer compare interrupts, reset tick_cmpr
601    tc->setMiscRegNoEffect(MISCREG_
602    tick_cmprFields.int_dis = 1;
603    tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
604    stickFields.npt = 1; // The TICK register is unreadable by by !priv
605    stick_cmprFields.int_dis = 1; // disable timer compare interrupts
606    stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
607
608    tt[tl] = _trapType;
609
610    hintp = 0; // no interrupts pending
611    hstick_cmprFields.int_dis = 1; // disable timer compare interrupts
612    hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
613    */
614}
615
616void
617FastInstructionAccessMMUMiss::invoke(ThreadContext *tc,
618                                     const StaticInstPtr &inst)
619{
620    if (FullSystem) {
621        SparcFaultBase::invoke(tc, inst);
622        return;
623    }
624
625    Process *p = tc->getProcessPtr();
626    TlbEntry entry;
627    bool success = p->pTable->lookup(vaddr, entry);
628    if (!success) {
629        panic("Tried to execute unmapped address %#x.\n", vaddr);
630    } else {
631        Addr alignedvaddr = p->pTable->pageAlign(vaddr);
632
633        // Grab fields used during instruction translation to figure out
634        // which context to use.
635        uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
636
637        // Inside a VM, a real address is the address that guest OS would
638        // interpret to be a physical address. To map to the physical address,
639        // it still needs to undergo a translation. The instruction
640        // translation code in the SPARC ITLB code assumes that the context is
641        // zero (kernel-level) if real addressing is being used.
642        bool is_real_address = !bits(tlbdata, 4);
643
644        // The SPARC ITLB code assumes that traps are executed in context
645        // zero so we carry that assumption through here.
646        bool trapped = bits(tlbdata, 18, 16) > 0;
647
648        // The primary context acts as a PASID. It allows the MMU to
649        // distinguish between virtual addresses that would alias to the
650        // same physical address (if two or more processes shared the same
651        // virtual address mapping).
652        int primary_context = bits(tlbdata, 47, 32);
653
654        // The partition id distinguishes between virtualized environments.
655        int const partition_id = 0;
656
657        // Given the assumptions in the translateInst code in the SPARC ITLB,
658        // the logic works out to the following for the context.
659        int context_id = (is_real_address || trapped) ? 0 : primary_context;
660
661        // Insert the TLB entry.
662        // The entry specifying whether the address is "real" is set to
663        // false for syscall emulation mode regardless of whether the
664        // address is real in preceding code. Not sure sure that this is
665        // correct, but also not sure if it matters at all.
666        tc->getITBPtr()->insert(alignedvaddr, partition_id, context_id,
667                                false, entry.pte);
668    }
669}
670
671void
672FastDataAccessMMUMiss::invoke(ThreadContext *tc, const StaticInstPtr &inst)
673{
674    if (FullSystem) {
675        SparcFaultBase::invoke(tc, inst);
676        return;
677    }
678
679    Process *p = tc->getProcessPtr();
680    TlbEntry entry;
681    bool success = p->pTable->lookup(vaddr, entry);
682    if (!success) {
683        if (p->fixupStackFault(vaddr))
684            success = p->pTable->lookup(vaddr, entry);
685    }
686    if (!success) {
687        panic("Tried to access unmapped address %#x.\n", vaddr);
688    } else {
689        Addr alignedvaddr = p->pTable->pageAlign(vaddr);
690
691        // Grab fields used during data translation to figure out
692        // which context to use.
693        uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
694
695        // The primary context acts as a PASID. It allows the MMU to
696        // distinguish between virtual addresses that would alias to the
697        // same physical address (if two or more processes shared the same
698        // virtual address mapping). There's a secondary context used in the
699        // DTLB translation code, but it should __probably__ be zero for
700        // syscall emulation code. (The secondary context is used by Solaris
701        // to allow kernel privilege code to access user space code:
702        // [ISBN 0-13-022496-0]:PG199.)
703        int primary_context = bits(tlbdata, 47, 32);
704
705        // "Hyper-Privileged Mode" is in use. There are three main modes of
706        // operation for Sparc: Hyper-Privileged Mode, Privileged Mode, and
707        // User Mode.
708        int hpriv = bits(tlbdata, 0);
709
710        // Reset, Error and Debug state is in use. Something horrible has
711        // happened or the system is operating in Reset Mode.
712        int red = bits(tlbdata, 1);
713
714        // Inside a VM, a real address is the address that guest OS would
715        // interpret to be a physical address. To map to the physical address,
716        // it still needs to undergo a translation. The instruction
717        // translation code in the SPARC ITLB code assumes that the context is
718        // zero (kernel-level) if real addressing is being used.
719        int is_real_address = !bits(tlbdata, 5);
720
721        // Grab the address space identifier register from the thread context.
722        // XXX: Inspecting how setMiscReg and setMiscRegNoEffect behave for
723        // MISCREG_ASI causes me to think that the ASI register implementation
724        // might be bugged. The NoEffect variant changes the ASI register
725        // value in the architectural state while the normal variant changes
726        // the context field in the thread context's currently decoded request
727        // but does not directly affect the ASI register value in the
728        // architectural state. The ASI values and the context field in the
729        // request packet seem to have completely different uses.
730        MiscReg reg_asi = tc->readMiscRegNoEffect(MISCREG_ASI);
731        ASI asi = static_cast<ASI>(reg_asi);
732
733        // The SPARC DTLB code assumes that traps are executed in context
734        // zero if the asi value is ASI_IMPLICIT (which is 0x0). There's also
735        // an assumption that the nucleus address space is being used, but
736        // the context is the relevant issue since we need to pass it to TLB.
737        bool trapped = bits(tlbdata, 18, 16) > 0;
738
739        // Given the assumptions in the translateData code in the SPARC DTLB,
740        // the logic works out to the following for the context.
741        int context_id = ((!hpriv && !red && is_real_address) ||
742                          asiIsReal(asi) ||
743                          (trapped && asi == ASI_IMPLICIT))
744                         ? 0 : primary_context;
745
746        // The partition id distinguishes between virtualized environments.
747        int const partition_id = 0;
748
749        // Insert the TLB entry.
750        // The entry specifying whether the address is "real" is set to
751        // false for syscall emulation mode regardless of whether the
752        // address is real in preceding code. Not sure sure that this is
753        // correct, but also not sure if it matters at all.
754        tc->getDTBPtr()->insert(alignedvaddr, partition_id, context_id,
755                                false, entry.pte);
756    }
757}
758
759void
760SpillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst)
761{
762    if (FullSystem) {
763        SparcFaultBase::invoke(tc, inst);
764        return;
765    }
766
767    doNormalFault(tc, trapType(), false);
768
769    Process *p = tc->getProcessPtr();
770
771    //XXX This will only work in faults from a SparcLiveProcess
772    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
773    assert(lp);
774
775    // Then adjust the PC and NPC
776    tc->pcState(lp->readSpillStart());
777}
778
779void
780FillNNormal::invoke(ThreadContext *tc, const StaticInstPtr &inst)
781{
782    if (FullSystem) {
783        SparcFaultBase::invoke(tc, inst);
784        return;
785    }
786
787    doNormalFault(tc, trapType(), false);
788
789    Process *p = tc->getProcessPtr();
790
791    //XXX This will only work in faults from a SparcLiveProcess
792    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
793    assert(lp);
794
795    // Then adjust the PC and NPC
796    tc->pcState(lp->readFillStart());
797}
798
799void
800TrapInstruction::invoke(ThreadContext *tc, const StaticInstPtr &inst)
801{
802    if (FullSystem) {
803        SparcFaultBase::invoke(tc, inst);
804        return;
805    }
806
807    // In SE, this mechanism is how the process requests a service from
808    // the operating system. We'll get the process object from the thread
809    // context and let it service the request.
810
811    Process *p = tc->getProcessPtr();
812
813    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
814    assert(lp);
815
816    lp->handleTrap(_n, tc);
817
818    // We need to explicitly advance the pc, since that's not done for us
819    // on a faulting instruction
820    PCState pc = tc->pcState();
821    pc.advance();
822    tc->pcState(pc);
823}
824
825} // namespace SparcISA
826
827