99a1492640216dc1bcf958639ec012762d43e081
[gem5.git] / src / arch / arm / interrupts.hh
1 /*
2 * Copyright (c) 2010, 2012-2013, 2016 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) 2006 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #ifndef __ARCH_ARM_INTERRUPT_HH__
42 #define __ARCH_ARM_INTERRUPT_HH__
43
44 #include "arch/arm/faults.hh"
45 #include "arch/arm/isa_traits.hh"
46 #include "arch/arm/miscregs.hh"
47 #include "arch/arm/registers.hh"
48 #include "arch/arm/utility.hh"
49 #include "arch/generic/interrupts.hh"
50 #include "cpu/thread_context.hh"
51 #include "debug/Interrupt.hh"
52 #include "params/ArmInterrupts.hh"
53
54 namespace ArmISA
55 {
56
57 class Interrupts : public BaseInterrupts
58 {
59 private:
60 bool interrupts[NumInterruptTypes];
61 uint64_t intStatus;
62
63 public:
64
65 typedef ArmInterruptsParams Params;
66
67 const Params *
68 params() const
69 {
70 return dynamic_cast<const Params *>(_params);
71 }
72
73 Interrupts(Params * p) : BaseInterrupts(p)
74 {
75 clearAll();
76 }
77
78
79 void
80 post(int int_num, int index) override
81 {
82 DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
83
84 if (int_num < 0 || int_num >= NumInterruptTypes)
85 panic("int_num out of bounds\n");
86
87 if (index != 0)
88 panic("No support for other interrupt indexes\n");
89
90 interrupts[int_num] = true;
91 intStatus |= ULL(1) << int_num;
92 }
93
94 void
95 clear(int int_num, int index) override
96 {
97 DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
98
99 if (int_num < 0 || int_num >= NumInterruptTypes)
100 panic("int_num out of bounds\n");
101
102 if (index != 0)
103 panic("No support for other interrupt indexes\n");
104
105 interrupts[int_num] = false;
106 intStatus &= ~(ULL(1) << int_num);
107 }
108
109 void
110 clearAll() override
111 {
112 DPRINTF(Interrupt, "Interrupts all cleared\n");
113 intStatus = 0;
114 memset(interrupts, 0, sizeof(interrupts));
115 }
116
117 enum InterruptMask {
118 INT_MASK_M, // masked (subject to PSTATE.{A,I,F} mask bit
119 INT_MASK_T, // taken regardless of mask
120 INT_MASK_P // pending
121 };
122
123 bool takeInt(InterruptTypes int_type) const;
124
125 bool
126 checkInterrupts() const override
127 {
128 HCR hcr = tc->readMiscReg(MISCREG_HCR);
129
130 if (!(intStatus || hcr.va || hcr.vi || hcr.vf))
131 return false;
132
133 CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
134
135 bool no_vhe = !HaveVirtHostExt(tc);
136 bool amo, fmo, imo;
137 if (hcr.tge == 1){
138 amo = (no_vhe || hcr.e2h == 0);
139 fmo = (no_vhe || hcr.e2h == 0);
140 imo = (no_vhe || hcr.e2h == 0);
141 } else {
142 amo = hcr.amo;
143 fmo = hcr.fmo;
144 imo = hcr.imo;
145 }
146
147 bool isHypMode = currEL(tc) == EL2;
148 bool isSecure = inSecureState(tc);
149 bool allowVIrq = !cpsr.i && imo && !isSecure && !isHypMode;
150 bool allowVFiq = !cpsr.f && fmo && !isSecure && !isHypMode;
151 bool allowVAbort = !cpsr.a && amo && !isSecure && !isHypMode;
152
153 if ( !(intStatus || (hcr.vi && allowVIrq) || (hcr.vf && allowVFiq) ||
154 (hcr.va && allowVAbort)) )
155 return false;
156
157 bool take_irq = takeInt(INT_IRQ);
158 bool take_fiq = takeInt(INT_FIQ);
159 bool take_ea = takeInt(INT_ABT);
160
161 return ((interrupts[INT_IRQ] && take_irq) ||
162 (interrupts[INT_FIQ] && take_fiq) ||
163 (interrupts[INT_ABT] && take_ea) ||
164 ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) ||
165 ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq) ||
166 (hcr.va && allowVAbort) ||
167 (interrupts[INT_RST]) ||
168 (interrupts[INT_SEV])
169 );
170 }
171
172 /**
173 * This function is used to check if a wfi operation should sleep. If there
174 * is an interrupt pending, even if it's masked, wfi doesn't sleep.
175 * @return any interrupts pending
176 */
177 bool
178 checkWfiWake(HCR hcr, CPSR cpsr, SCR scr) const
179 {
180 uint64_t maskedIntStatus;
181 bool virtWake;
182
183 maskedIntStatus = intStatus & ~((1 << INT_VIRT_IRQ) |
184 (1 << INT_VIRT_FIQ));
185 virtWake = (hcr.vi || interrupts[INT_VIRT_IRQ]) && hcr.imo;
186 virtWake |= (hcr.vf || interrupts[INT_VIRT_FIQ]) && hcr.fmo;
187 virtWake |= hcr.va && hcr.amo;
188 virtWake &= (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr);
189 return maskedIntStatus || virtWake;
190 }
191
192 uint32_t
193 getISR(HCR hcr, CPSR cpsr, SCR scr)
194 {
195 bool useHcrMux;
196 CPSR isr = 0; // ARM ARM states ISR reg uses same bit possitions as CPSR
197
198 useHcrMux = (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr);
199 isr.i = (useHcrMux & hcr.imo) ? (interrupts[INT_VIRT_IRQ] || hcr.vi)
200 : interrupts[INT_IRQ];
201 isr.f = (useHcrMux & hcr.fmo) ? (interrupts[INT_VIRT_FIQ] || hcr.vf)
202 : interrupts[INT_FIQ];
203 isr.a = (useHcrMux & hcr.amo) ? hcr.va : interrupts[INT_ABT];
204 return isr;
205 }
206
207 /**
208 * Check the state of a particular interrupt, ignoring CPSR masks.
209 *
210 * This method is primarily used when running the target CPU in a
211 * hardware VM (e.g., KVM) to check if interrupts should be
212 * delivered upon guest entry.
213 *
214 * @param interrupt Interrupt type to check the state of.
215 * @return true if the interrupt is asserted, false otherwise.
216 */
217 bool
218 checkRaw(InterruptTypes interrupt) const
219 {
220 if (interrupt >= NumInterruptTypes)
221 panic("Interrupt number out of range.\n");
222
223 return interrupts[interrupt];
224 }
225
226 Fault
227 getInterrupt() override
228 {
229 assert(checkInterrupts());
230
231 HCR hcr = tc->readMiscReg(MISCREG_HCR);
232 CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
233
234 bool no_vhe = !HaveVirtHostExt(tc);
235 bool amo, fmo, imo;
236 if (hcr.tge == 1){
237 amo = (no_vhe || hcr.e2h == 0);
238 fmo = (no_vhe || hcr.e2h == 0);
239 imo = (no_vhe || hcr.e2h == 0);
240 } else {
241 amo = hcr.amo;
242 fmo = hcr.fmo;
243 imo = hcr.imo;
244 }
245
246 // Calculate a few temp vars so we can work out if there's a pending
247 // virtual interrupt, and if its allowed to happen
248 // ARM ARM Issue C section B1.9.9, B1.9.11, and B1.9.13
249 bool isHypMode = currEL(tc) == EL2;
250 bool isSecure = inSecureState(tc);
251 bool allowVIrq = !cpsr.i && imo && !isSecure && !isHypMode;
252 bool allowVFiq = !cpsr.f && fmo && !isSecure && !isHypMode;
253 bool allowVAbort = !cpsr.a && amo && !isSecure && !isHypMode;
254
255 bool take_irq = takeInt(INT_IRQ);
256 bool take_fiq = takeInt(INT_FIQ);
257 bool take_ea = takeInt(INT_ABT);
258
259 if (interrupts[INT_IRQ] && take_irq)
260 return std::make_shared<Interrupt>();
261 if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq)
262 return std::make_shared<VirtualInterrupt>();
263 if (interrupts[INT_FIQ] && take_fiq)
264 return std::make_shared<FastInterrupt>();
265 if ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq)
266 return std::make_shared<VirtualFastInterrupt>();
267 if (interrupts[INT_ABT] && take_ea)
268 return std::make_shared<SystemError>();
269 if (hcr.va && allowVAbort)
270 return std::make_shared<VirtualDataAbort>(
271 0, TlbEntry::DomainType::NoAccess, false,
272 ArmFault::AsynchronousExternalAbort);
273 if (interrupts[INT_RST])
274 return std::make_shared<Reset>();
275 if (interrupts[INT_SEV])
276 return std::make_shared<ArmSev>();
277
278 panic("intStatus and interrupts not in sync\n");
279 }
280
281 void updateIntrInfo() override {} // nothing to do
282
283 void
284 serialize(CheckpointOut &cp) const override
285 {
286 SERIALIZE_ARRAY(interrupts, NumInterruptTypes);
287 SERIALIZE_SCALAR(intStatus);
288 }
289
290 void
291 unserialize(CheckpointIn &cp) override
292 {
293 UNSERIALIZE_ARRAY(interrupts, NumInterruptTypes);
294 UNSERIALIZE_SCALAR(intStatus);
295 }
296 };
297 } // namespace ARM_ISA
298
299 #endif // __ARCH_ARM_INTERRUPT_HH__