Merge with the main repo.
[gem5.git] / src / arch / arm / faults.cc
1 /*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * Copyright (c) 2007-2008 The Florida State University
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Ali Saidi
42 * Gabe Black
43 */
44
45 #include "arch/arm/faults.hh"
46 #include "base/trace.hh"
47 #include "cpu/base.hh"
48 #include "cpu/thread_context.hh"
49 #include "debug/Faults.hh"
50 #include "sim/full_system.hh"
51
52 namespace ArmISA
53 {
54
55 template<> ArmFault::FaultVals ArmFaultVals<Reset>::vals =
56 {"reset", 0x00, MODE_SVC, 0, 0, true, true};
57
58 template<> ArmFault::FaultVals ArmFaultVals<UndefinedInstruction>::vals =
59 {"Undefined Instruction", 0x04, MODE_UNDEFINED, 4 ,2, false, false} ;
60
61 template<> ArmFault::FaultVals ArmFaultVals<SupervisorCall>::vals =
62 {"Supervisor Call", 0x08, MODE_SVC, 4, 2, false, false};
63
64 template<> ArmFault::FaultVals ArmFaultVals<PrefetchAbort>::vals =
65 {"Prefetch Abort", 0x0C, MODE_ABORT, 4, 4, true, false};
66
67 template<> ArmFault::FaultVals ArmFaultVals<DataAbort>::vals =
68 {"Data Abort", 0x10, MODE_ABORT, 8, 8, true, false};
69
70 template<> ArmFault::FaultVals ArmFaultVals<Interrupt>::vals =
71 {"IRQ", 0x18, MODE_IRQ, 4, 4, true, false};
72
73 template<> ArmFault::FaultVals ArmFaultVals<FastInterrupt>::vals =
74 {"FIQ", 0x1C, MODE_FIQ, 4, 4, true, true};
75
76 template<> ArmFault::FaultVals ArmFaultVals<FlushPipe>::vals =
77 {"Pipe Flush", 0x00, MODE_SVC, 0, 0, true, true}; // some dummy values
78
79 template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals =
80 {"ArmSev Flush", 0x00, MODE_SVC, 0, 0, true, true}; // some dummy values
81 Addr
82 ArmFault::getVector(ThreadContext *tc)
83 {
84 // ARM ARM B1-3
85
86 SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
87
88 // panic if SCTLR.VE because I have no idea what to do with vectored
89 // interrupts
90 assert(!sctlr.ve);
91
92 if (!sctlr.v)
93 return offset();
94 return offset() + HighVecs;
95
96 }
97
98 void
99 ArmFault::invoke(ThreadContext *tc, StaticInstPtr inst)
100 {
101 // ARM ARM B1.6.3
102 FaultBase::invoke(tc);
103 if (!FullSystem)
104 return;
105 countStat()++;
106
107 SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
108 CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
109 CPSR saved_cpsr = tc->readMiscReg(MISCREG_CPSR);
110 saved_cpsr.nz = tc->readIntReg(INTREG_CONDCODES_NZ);
111 saved_cpsr.c = tc->readIntReg(INTREG_CONDCODES_C);
112 saved_cpsr.v = tc->readIntReg(INTREG_CONDCODES_V);
113 saved_cpsr.ge = tc->readIntReg(INTREG_CONDCODES_GE);
114
115 Addr curPc M5_VAR_USED = tc->pcState().pc();
116 ITSTATE it = tc->pcState().itstate();
117 saved_cpsr.it2 = it.top6;
118 saved_cpsr.it1 = it.bottom2;
119
120 cpsr.mode = nextMode();
121 cpsr.it1 = cpsr.it2 = 0;
122 cpsr.j = 0;
123
124 cpsr.t = sctlr.te;
125 cpsr.a = cpsr.a | abortDisable();
126 cpsr.f = cpsr.f | fiqDisable();
127 cpsr.i = 1;
128 cpsr.e = sctlr.ee;
129 tc->setMiscReg(MISCREG_CPSR, cpsr);
130 // Make sure mailbox sets to one always
131 tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
132 tc->setIntReg(INTREG_LR, curPc +
133 (saved_cpsr.t ? thumbPcOffset() : armPcOffset()));
134
135 switch (nextMode()) {
136 case MODE_FIQ:
137 tc->setMiscReg(MISCREG_SPSR_FIQ, saved_cpsr);
138 break;
139 case MODE_IRQ:
140 tc->setMiscReg(MISCREG_SPSR_IRQ, saved_cpsr);
141 break;
142 case MODE_SVC:
143 tc->setMiscReg(MISCREG_SPSR_SVC, saved_cpsr);
144 break;
145 case MODE_UNDEFINED:
146 tc->setMiscReg(MISCREG_SPSR_UND, saved_cpsr);
147 break;
148 case MODE_ABORT:
149 tc->setMiscReg(MISCREG_SPSR_ABT, saved_cpsr);
150 break;
151 default:
152 panic("unknown Mode\n");
153 }
154
155 Addr newPc = getVector(tc);
156 DPRINTF(Faults, "Invoking Fault:%s cpsr:%#x PC:%#x lr:%#x newVec: %#x\n",
157 name(), cpsr, curPc, tc->readIntReg(INTREG_LR), newPc);
158 PCState pc(newPc);
159 pc.thumb(cpsr.t);
160 pc.nextThumb(pc.thumb());
161 pc.jazelle(cpsr.j);
162 pc.nextJazelle(pc.jazelle());
163 tc->pcState(pc);
164 }
165
166 void
167 Reset::invoke(ThreadContext *tc, StaticInstPtr inst)
168 {
169 if (FullSystem) {
170 tc->getCpuPtr()->clearInterrupts();
171 tc->clearArchRegs();
172 }
173 ArmFault::invoke(tc, inst);
174 }
175
176 void
177 UndefinedInstruction::invoke(ThreadContext *tc, StaticInstPtr inst)
178 {
179 if (FullSystem) {
180 ArmFault::invoke(tc, inst);
181 } else {
182 // If the mnemonic isn't defined this has to be an unknown instruction.
183 assert(unknown || mnemonic != NULL);
184 if (disabled) {
185 panic("Attempted to execute disabled instruction "
186 "'%s' (inst 0x%08x)", mnemonic, machInst);
187 } else if (unknown) {
188 panic("Attempted to execute unknown instruction (inst 0x%08x)",
189 machInst);
190 } else {
191 panic("Attempted to execute unimplemented instruction "
192 "'%s' (inst 0x%08x)", mnemonic, machInst);
193 }
194 }
195 }
196
197 void
198 SupervisorCall::invoke(ThreadContext *tc, StaticInstPtr inst)
199 {
200 if (FullSystem) {
201 ArmFault::invoke(tc, inst);
202 } else {
203 // As of now, there isn't a 32 bit thumb version of this instruction.
204 assert(!machInst.bigThumb);
205 uint32_t callNum;
206 callNum = tc->readIntReg(INTREG_R7);
207 tc->syscall(callNum);
208
209 // Advance the PC since that won't happen automatically.
210 PCState pc = tc->pcState();
211 assert(inst);
212 inst->advancePC(pc);
213 tc->pcState(pc);
214 }
215 }
216
217 template<class T>
218 void
219 AbortFault<T>::invoke(ThreadContext *tc, StaticInstPtr inst)
220 {
221 ArmFaultVals<T>::invoke(tc, inst);
222 FSR fsr = 0;
223 fsr.fsLow = bits(status, 3, 0);
224 fsr.fsHigh = bits(status, 4);
225 fsr.domain = domain;
226 fsr.wnr = (write ? 1 : 0);
227 fsr.ext = 0;
228 tc->setMiscReg(T::FsrIndex, fsr);
229 tc->setMiscReg(T::FarIndex, faultAddr);
230
231 DPRINTF(Faults, "Abort Fault fsr=%#x faultAddr=%#x\n", fsr, faultAddr);
232 }
233
234 void
235 FlushPipe::invoke(ThreadContext *tc, StaticInstPtr inst) {
236 DPRINTF(Faults, "Invoking FlushPipe Fault\n");
237
238 // Set the PC to the next instruction of the faulting instruction.
239 // Net effect is simply squashing all instructions behind and
240 // start refetching from the next instruction.
241 PCState pc = tc->pcState();
242 assert(inst);
243 inst->advancePC(pc);
244 tc->pcState(pc);
245 }
246
247 template void AbortFault<PrefetchAbort>::invoke(ThreadContext *tc,
248 StaticInstPtr inst);
249 template void AbortFault<DataAbort>::invoke(ThreadContext *tc,
250 StaticInstPtr inst);
251
252 void
253 ArmSev::invoke(ThreadContext *tc, StaticInstPtr inst) {
254 DPRINTF(Faults, "Invoking ArmSev Fault\n");
255 if (FullSystem) {
256 // Set sev_mailbox to 1, clear the pending interrupt from remote
257 // SEV execution and let pipeline continue as pcState is still
258 // valid.
259 tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
260 tc->getCpuPtr()->clearInterrupt(INT_SEV, 0);
261 }
262 }
263
264 // return via SUBS pc, lr, xxx; rfe, movs, ldm
265
266 } // namespace ArmISA