vgic.cc (12092:9bb326b4661d) vgic.cc (12132:559e67bd19dc)
1/*
2 * Copyright (c) 2013 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 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Matt Evans
38 */
39
40#include "dev/arm/vgic.hh"
41
42#include "base/trace.hh"
43#include "debug/Checkpoint.hh"
44#include "debug/VGIC.hh"
45#include "dev/arm/base_gic.hh"
46#include "dev/terminal.hh"
47#include "mem/packet.hh"
48#include "mem/packet_access.hh"
49
50VGic::VGic(const Params *p)
51 : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr),
52 hvAddr(p->hv_addr), pioDelay(p->pio_delay),
53 maintInt(p->ppint)
54{
55 for (int x = 0; x < VGIC_CPU_MAX; x++) {
1/*
2 * Copyright (c) 2013 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 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Matt Evans
38 */
39
40#include "dev/arm/vgic.hh"
41
42#include "base/trace.hh"
43#include "debug/Checkpoint.hh"
44#include "debug/VGIC.hh"
45#include "dev/arm/base_gic.hh"
46#include "dev/terminal.hh"
47#include "mem/packet.hh"
48#include "mem/packet_access.hh"
49
50VGic::VGic(const Params *p)
51 : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr),
52 hvAddr(p->hv_addr), pioDelay(p->pio_delay),
53 maintInt(p->ppint)
54{
55 for (int x = 0; x < VGIC_CPU_MAX; x++) {
56 postVIntEvent[x] = new PostVIntEvent(x, p->platform);
56 postVIntEvent[x] = new EventFunctionWrapper(
57 [this, x]{ processPostVIntEvent(x); },
58 "Post VInterrupt to CPU");
57 maintIntPosted[x] = false;
58 vIntPosted[x] = false;
59 }
60 assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
61}
62
63VGic::~VGic()
64{
65 for (int x = 0; x < VGIC_CPU_MAX; x++)
66 delete postVIntEvent[x];
67}
68
69Tick
70VGic::read(PacketPtr pkt)
71{
72 Addr addr = pkt->getAddr();
73
74 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
75 return readVCpu(pkt);
76 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
77 return readCtrl(pkt);
78 else
79 panic("Read to unknown address %#x\n", pkt->getAddr());
80}
81
82Tick
83VGic::write(PacketPtr pkt)
84{
85 Addr addr = pkt->getAddr();
86
87 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
88 return writeVCpu(pkt);
89 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
90 return writeCtrl(pkt);
91 else
92 panic("Write to unknown address %#x\n", pkt->getAddr());
93}
94
95Tick
96VGic::readVCpu(PacketPtr pkt)
97{
98 Addr daddr = pkt->getAddr() - vcpuAddr;
99
100 ContextID ctx_id = pkt->req->contextId();
101 assert(ctx_id < VGIC_CPU_MAX);
102 struct vcpuIntData *vid = &vcpuData[ctx_id];
103
104 DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr);
105
106 switch (daddr) {
107 case GICV_CTLR:
108 pkt->set<uint32_t>(vid->vctrl);
109 break;
110 case GICV_IAR: {
111 int i = findHighestPendingLR(vid);
112 if (i < 0 || !vid->vctrl.En) {
113 pkt->set<uint32_t>(1023); // "No int" marker
114 } else {
115 ListReg *lr = &vid->LR[i];
116
117 pkt->set<uint32_t>(lr->VirtualID |
118 (((int)lr->CpuID) << 10));
119 // We don't support auto-EOI of HW interrupts via real GIC!
120 // Fortunately, KVM doesn't use this. How about Xen...? Ulp!
121 if (lr->HW)
122 panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
123 *lr);
124 lr->State = LR_ACTIVE;
125 DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
126 lr->VirtualID, lr->CpuID, i, lr->EOI);
127 }
128 } break;
129 default:
130 panic("VGIC VCPU read of bad address %#x\n", daddr);
131 }
132
133 updateIntState(ctx_id);
134
135 pkt->makeAtomicResponse();
136 return pioDelay;
137}
138
139Tick
140VGic::readCtrl(PacketPtr pkt)
141{
142 Addr daddr = pkt->getAddr() - hvAddr;
143
144 ContextID ctx_id = pkt->req->contextId();
145
146 DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr);
147
148 /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
149 * Anything > that is 0x200-sized slices of 'per CPU' regs.
150 */
151 if (daddr & ~0x1ff) {
152 ctx_id = (daddr >> 9);
153 if (ctx_id > 8)
154 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
155 daddr &= ~0x1ff;
156 }
157 assert(ctx_id < VGIC_CPU_MAX);
158 struct vcpuIntData *vid = &vcpuData[ctx_id];
159
160 switch (daddr) {
161 case GICH_HCR:
162 pkt->set<uint32_t>(vid->hcr);
163 break;
164
165 case GICH_VTR:
166 pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1));
167 break;
168
169 case GICH_VMCR:
170 pkt->set<uint32_t>(
171 ((uint32_t)vid->VMPriMask << 27) |
172 ((uint32_t)vid->VMBP << 21) |
173 ((uint32_t)vid->VMABP << 18) |
174 ((uint32_t)vid->VEM << 9) |
175 ((uint32_t)vid->VMCBPR << 4) |
176 ((uint32_t)vid->VMFiqEn << 3) |
177 ((uint32_t)vid->VMAckCtl << 2) |
178 ((uint32_t)vid->VMGrp1En << 1) |
179 ((uint32_t)vid->VMGrp0En << 0)
180 );
181 break;
182
183 case GICH_MISR:
184 pkt->set<uint32_t>(getMISR(vid));
185 break;
186
187 case GICH_EISR0:
188 pkt->set<uint32_t>(vid->eisr & 0xffffffff);
189 break;
190
191 case GICH_EISR1:
192 pkt->set<uint32_t>(vid->eisr >> 32);
193 break;
194
195 case GICH_ELSR0: {
196 uint32_t bm = 0;
197 for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) {
198 if (!vid->LR[i].State)
199 bm |= 1 << i;
200 }
201 pkt->set<uint32_t>(bm);
202 } break;
203
204 case GICH_ELSR1: {
205 uint32_t bm = 0;
206 for (int i = 32; i < NUM_LR; i++) {
207 if (!vid->LR[i].State)
208 bm |= 1 << (i-32);
209 }
210 pkt->set<uint32_t>(bm);
211 } break;
212
213 case GICH_APR0:
214 warn_once("VGIC GICH_APR read!\n");
215 pkt->set<uint32_t>(0);
216 break;
217
218 case GICH_LR0:
219 case GICH_LR1:
220 case GICH_LR2:
221 case GICH_LR3:
222 pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]);
223 break;
224
225 default:
226 panic("VGIC HVCtrl read of bad address %#x\n", daddr);
227 }
228
229 pkt->makeAtomicResponse();
230 return pioDelay;
231}
232
233Tick
234VGic::writeVCpu(PacketPtr pkt)
235{
236 Addr daddr = pkt->getAddr() - vcpuAddr;
237
238 ContextID ctx_id = pkt->req->contextId();
239 assert(ctx_id < VGIC_CPU_MAX);
240 struct vcpuIntData *vid = &vcpuData[ctx_id];
241
242 DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
243
244 switch (daddr) {
245 case GICV_CTLR:
246 vid->vctrl = pkt->get<uint32_t>();
247 break;
248 case GICV_PMR:
249 vid->VMPriMask = pkt->get<uint32_t>();
250 break;
251 case GICV_EOIR: {
252 // We don't handle the split EOI-then-DIR mode. Linux (guest)
253 // doesn't need it though.
254 assert(!vid->vctrl.EOImode);
255 uint32_t w = pkt->get<uint32_t>();
256 unsigned int virq = w & 0x3ff;
257 unsigned int vcpu = (w >> 10) & 7;
258 int i = findLRForVIRQ(vid, virq, vcpu);
259 if (i < 0) {
260 DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu);
261 } else {
262 DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu);
263 ListReg *lr = &vid->LR[i];
264 lr->State = 0;
265 // Maintenance interrupt -- via eisr -- is flagged when
266 // LRs have EOI=1 and State=INVALID!
267 }
268 } break;
269 default:
270 panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr);
271 }
272
273 // This updates the EISRs and flags IRQs:
274 updateIntState(ctx_id);
275
276 pkt->makeAtomicResponse();
277 return pioDelay;
278}
279
280Tick
281VGic::writeCtrl(PacketPtr pkt)
282{
283 Addr daddr = pkt->getAddr() - hvAddr;
284
285 ContextID ctx_id = pkt->req->contextId();
286
287 DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
288
289 /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
290 * Anything > that is 0x200-sized slices of 'per CPU' regs.
291 */
292 if (daddr & ~0x1ff) {
293 ctx_id = (daddr >> 9);
294 if (ctx_id > 8)
295 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
296 daddr &= ~0x1ff;
297 }
298 assert(ctx_id < VGIC_CPU_MAX);
299 struct vcpuIntData *vid = &vcpuData[ctx_id];
300
301 switch (daddr) {
302 case GICH_HCR:
303 vid->hcr = pkt->get<uint32_t>();
304 // update int state
305 break;
306
307 case GICH_VMCR: {
308 uint32_t d = pkt->get<uint32_t>();
309 vid->VMPriMask = d >> 27;
310 vid->VMBP = (d >> 21) & 7;
311 vid->VMABP = (d >> 18) & 7;
312 vid->VEM = (d >> 9) & 1;
313 vid->VMCBPR = (d >> 4) & 1;
314 vid->VMFiqEn = (d >> 3) & 1;
315 vid->VMAckCtl = (d >> 2) & 1;
316 vid->VMGrp1En = (d >> 1) & 1;
317 vid->VMGrp0En = d & 1;
318 } break;
319
320 case GICH_APR0:
321 warn_once("VGIC GICH_APR0 written, ignored\n");
322 break;
323
324 case GICH_LR0:
325 case GICH_LR1:
326 case GICH_LR2:
327 case GICH_LR3:
328 vid->LR[(daddr - GICH_LR0) >> 2] = pkt->get<uint32_t>();
329 // update int state
330 break;
331
332 default:
333 panic("VGIC HVCtrl write to bad address %#x\n", daddr);
334 }
335
336 updateIntState(ctx_id);
337
338 pkt->makeAtomicResponse();
339 return pioDelay;
340}
341
342
343uint32_t
344VGic::getMISR(struct vcpuIntData *vid)
345{
346 return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) |
347 (!!vid->hcr.VGrp1EIE && vid->VMGrp1En ? 0x40 : 0) |
348 (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) |
349 (!!vid->hcr.VGrp0EIE && vid->VMGrp0En ? 0x10 : 0) |
350 (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) |
351 (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) |
352 (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) |
353 (vid->eisr ? 0x01 : 0);
354}
355
356void
357VGic::postVInt(uint32_t cpu, Tick when)
358{
359 DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu);
360 if (!(postVIntEvent[cpu]->scheduled()))
361 eventq->schedule(postVIntEvent[cpu], when);
362}
363
364void
365VGic::unPostVInt(uint32_t cpu)
366{
367 DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu);
368 platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0);
369}
370
371void
59 maintIntPosted[x] = false;
60 vIntPosted[x] = false;
61 }
62 assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
63}
64
65VGic::~VGic()
66{
67 for (int x = 0; x < VGIC_CPU_MAX; x++)
68 delete postVIntEvent[x];
69}
70
71Tick
72VGic::read(PacketPtr pkt)
73{
74 Addr addr = pkt->getAddr();
75
76 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
77 return readVCpu(pkt);
78 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
79 return readCtrl(pkt);
80 else
81 panic("Read to unknown address %#x\n", pkt->getAddr());
82}
83
84Tick
85VGic::write(PacketPtr pkt)
86{
87 Addr addr = pkt->getAddr();
88
89 if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
90 return writeVCpu(pkt);
91 else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
92 return writeCtrl(pkt);
93 else
94 panic("Write to unknown address %#x\n", pkt->getAddr());
95}
96
97Tick
98VGic::readVCpu(PacketPtr pkt)
99{
100 Addr daddr = pkt->getAddr() - vcpuAddr;
101
102 ContextID ctx_id = pkt->req->contextId();
103 assert(ctx_id < VGIC_CPU_MAX);
104 struct vcpuIntData *vid = &vcpuData[ctx_id];
105
106 DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr);
107
108 switch (daddr) {
109 case GICV_CTLR:
110 pkt->set<uint32_t>(vid->vctrl);
111 break;
112 case GICV_IAR: {
113 int i = findHighestPendingLR(vid);
114 if (i < 0 || !vid->vctrl.En) {
115 pkt->set<uint32_t>(1023); // "No int" marker
116 } else {
117 ListReg *lr = &vid->LR[i];
118
119 pkt->set<uint32_t>(lr->VirtualID |
120 (((int)lr->CpuID) << 10));
121 // We don't support auto-EOI of HW interrupts via real GIC!
122 // Fortunately, KVM doesn't use this. How about Xen...? Ulp!
123 if (lr->HW)
124 panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
125 *lr);
126 lr->State = LR_ACTIVE;
127 DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
128 lr->VirtualID, lr->CpuID, i, lr->EOI);
129 }
130 } break;
131 default:
132 panic("VGIC VCPU read of bad address %#x\n", daddr);
133 }
134
135 updateIntState(ctx_id);
136
137 pkt->makeAtomicResponse();
138 return pioDelay;
139}
140
141Tick
142VGic::readCtrl(PacketPtr pkt)
143{
144 Addr daddr = pkt->getAddr() - hvAddr;
145
146 ContextID ctx_id = pkt->req->contextId();
147
148 DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr);
149
150 /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
151 * Anything > that is 0x200-sized slices of 'per CPU' regs.
152 */
153 if (daddr & ~0x1ff) {
154 ctx_id = (daddr >> 9);
155 if (ctx_id > 8)
156 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
157 daddr &= ~0x1ff;
158 }
159 assert(ctx_id < VGIC_CPU_MAX);
160 struct vcpuIntData *vid = &vcpuData[ctx_id];
161
162 switch (daddr) {
163 case GICH_HCR:
164 pkt->set<uint32_t>(vid->hcr);
165 break;
166
167 case GICH_VTR:
168 pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1));
169 break;
170
171 case GICH_VMCR:
172 pkt->set<uint32_t>(
173 ((uint32_t)vid->VMPriMask << 27) |
174 ((uint32_t)vid->VMBP << 21) |
175 ((uint32_t)vid->VMABP << 18) |
176 ((uint32_t)vid->VEM << 9) |
177 ((uint32_t)vid->VMCBPR << 4) |
178 ((uint32_t)vid->VMFiqEn << 3) |
179 ((uint32_t)vid->VMAckCtl << 2) |
180 ((uint32_t)vid->VMGrp1En << 1) |
181 ((uint32_t)vid->VMGrp0En << 0)
182 );
183 break;
184
185 case GICH_MISR:
186 pkt->set<uint32_t>(getMISR(vid));
187 break;
188
189 case GICH_EISR0:
190 pkt->set<uint32_t>(vid->eisr & 0xffffffff);
191 break;
192
193 case GICH_EISR1:
194 pkt->set<uint32_t>(vid->eisr >> 32);
195 break;
196
197 case GICH_ELSR0: {
198 uint32_t bm = 0;
199 for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) {
200 if (!vid->LR[i].State)
201 bm |= 1 << i;
202 }
203 pkt->set<uint32_t>(bm);
204 } break;
205
206 case GICH_ELSR1: {
207 uint32_t bm = 0;
208 for (int i = 32; i < NUM_LR; i++) {
209 if (!vid->LR[i].State)
210 bm |= 1 << (i-32);
211 }
212 pkt->set<uint32_t>(bm);
213 } break;
214
215 case GICH_APR0:
216 warn_once("VGIC GICH_APR read!\n");
217 pkt->set<uint32_t>(0);
218 break;
219
220 case GICH_LR0:
221 case GICH_LR1:
222 case GICH_LR2:
223 case GICH_LR3:
224 pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]);
225 break;
226
227 default:
228 panic("VGIC HVCtrl read of bad address %#x\n", daddr);
229 }
230
231 pkt->makeAtomicResponse();
232 return pioDelay;
233}
234
235Tick
236VGic::writeVCpu(PacketPtr pkt)
237{
238 Addr daddr = pkt->getAddr() - vcpuAddr;
239
240 ContextID ctx_id = pkt->req->contextId();
241 assert(ctx_id < VGIC_CPU_MAX);
242 struct vcpuIntData *vid = &vcpuData[ctx_id];
243
244 DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
245
246 switch (daddr) {
247 case GICV_CTLR:
248 vid->vctrl = pkt->get<uint32_t>();
249 break;
250 case GICV_PMR:
251 vid->VMPriMask = pkt->get<uint32_t>();
252 break;
253 case GICV_EOIR: {
254 // We don't handle the split EOI-then-DIR mode. Linux (guest)
255 // doesn't need it though.
256 assert(!vid->vctrl.EOImode);
257 uint32_t w = pkt->get<uint32_t>();
258 unsigned int virq = w & 0x3ff;
259 unsigned int vcpu = (w >> 10) & 7;
260 int i = findLRForVIRQ(vid, virq, vcpu);
261 if (i < 0) {
262 DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu);
263 } else {
264 DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu);
265 ListReg *lr = &vid->LR[i];
266 lr->State = 0;
267 // Maintenance interrupt -- via eisr -- is flagged when
268 // LRs have EOI=1 and State=INVALID!
269 }
270 } break;
271 default:
272 panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr);
273 }
274
275 // This updates the EISRs and flags IRQs:
276 updateIntState(ctx_id);
277
278 pkt->makeAtomicResponse();
279 return pioDelay;
280}
281
282Tick
283VGic::writeCtrl(PacketPtr pkt)
284{
285 Addr daddr = pkt->getAddr() - hvAddr;
286
287 ContextID ctx_id = pkt->req->contextId();
288
289 DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
290
291 /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
292 * Anything > that is 0x200-sized slices of 'per CPU' regs.
293 */
294 if (daddr & ~0x1ff) {
295 ctx_id = (daddr >> 9);
296 if (ctx_id > 8)
297 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
298 daddr &= ~0x1ff;
299 }
300 assert(ctx_id < VGIC_CPU_MAX);
301 struct vcpuIntData *vid = &vcpuData[ctx_id];
302
303 switch (daddr) {
304 case GICH_HCR:
305 vid->hcr = pkt->get<uint32_t>();
306 // update int state
307 break;
308
309 case GICH_VMCR: {
310 uint32_t d = pkt->get<uint32_t>();
311 vid->VMPriMask = d >> 27;
312 vid->VMBP = (d >> 21) & 7;
313 vid->VMABP = (d >> 18) & 7;
314 vid->VEM = (d >> 9) & 1;
315 vid->VMCBPR = (d >> 4) & 1;
316 vid->VMFiqEn = (d >> 3) & 1;
317 vid->VMAckCtl = (d >> 2) & 1;
318 vid->VMGrp1En = (d >> 1) & 1;
319 vid->VMGrp0En = d & 1;
320 } break;
321
322 case GICH_APR0:
323 warn_once("VGIC GICH_APR0 written, ignored\n");
324 break;
325
326 case GICH_LR0:
327 case GICH_LR1:
328 case GICH_LR2:
329 case GICH_LR3:
330 vid->LR[(daddr - GICH_LR0) >> 2] = pkt->get<uint32_t>();
331 // update int state
332 break;
333
334 default:
335 panic("VGIC HVCtrl write to bad address %#x\n", daddr);
336 }
337
338 updateIntState(ctx_id);
339
340 pkt->makeAtomicResponse();
341 return pioDelay;
342}
343
344
345uint32_t
346VGic::getMISR(struct vcpuIntData *vid)
347{
348 return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) |
349 (!!vid->hcr.VGrp1EIE && vid->VMGrp1En ? 0x40 : 0) |
350 (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) |
351 (!!vid->hcr.VGrp0EIE && vid->VMGrp0En ? 0x10 : 0) |
352 (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) |
353 (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) |
354 (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) |
355 (vid->eisr ? 0x01 : 0);
356}
357
358void
359VGic::postVInt(uint32_t cpu, Tick when)
360{
361 DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu);
362 if (!(postVIntEvent[cpu]->scheduled()))
363 eventq->schedule(postVIntEvent[cpu], when);
364}
365
366void
367VGic::unPostVInt(uint32_t cpu)
368{
369 DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu);
370 platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0);
371}
372
373void
374VGic::processPostVIntEvent(uint32_t cpu)
375{
376 platform->intrctrl->post(cpu, ArmISA::INT_VIRT_IRQ, 0);
377}
378
379
380void
372VGic::postMaintInt(uint32_t cpu)
373{
374 DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu);
375 // Linux DT configures this as Level.
376 gic->sendPPInt(maintInt, cpu);
377}
378
379void
380VGic::unPostMaintInt(uint32_t cpu)
381{
382 DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu);
383 gic->clearPPInt(maintInt, cpu);
384}
385
386/* Update state (in general); something concerned with ctx_id has changed.
387 * This may raise a maintenance interrupt.
388 */
389void
390VGic::updateIntState(ContextID ctx_id)
391{
392 // @todo This should update APRs!
393
394 // Build EISR contents:
395 // (Cached so that regs can read them without messing about again)
396 struct vcpuIntData *tvid = &vcpuData[ctx_id];
397
398 tvid->eisr = 0;
399 for (int i = 0; i < NUM_LR; i++) {
400 if (!tvid->LR[i].State && tvid->LR[i].EOI) {
401 tvid->eisr |= 1 << i;
402 }
403 }
404
405 assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
406 for (int i = 0; i < sys->numRunningContexts(); i++) {
407 struct vcpuIntData *vid = &vcpuData[i];
408 // Are any LRs active that weren't before?
409 if (!vIntPosted[i]) {
410 if (lrPending(vid) && vid->vctrl.En) {
411 vIntPosted[i] = true;
412 postVInt(i, curTick() + 1);
413 }
414 } else if (!lrPending(vid)) {
415 vIntPosted[i] = false;
416 unPostVInt(i);
417 }
418
419 // Any maintenance ints to send?
420 if (!maintIntPosted[i]) {
421 if (vid->hcr.En && getMISR(vid)) {
422 maintIntPosted[i] = true;
423 postMaintInt(i);
424 }
425 } else {
426 if (!vid->hcr.En || !getMISR(vid)) {
427 unPostMaintInt(i);
428 maintIntPosted[i] = false;
429 }
430 }
431 }
432}
433
434AddrRangeList
435VGic::getAddrRanges() const
436{
437 AddrRangeList ranges;
438 ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE));
439 ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE));
440 return ranges;
441}
442
443void
444VGic::serialize(CheckpointOut &cp) const
445{
446 Tick interrupt_time[VGIC_CPU_MAX];
447 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
448 interrupt_time[cpu] = 0;
449 if (postVIntEvent[cpu]->scheduled()) {
450 interrupt_time[cpu] = postVIntEvent[cpu]->when();
451 }
452 }
453
454 DPRINTF(Checkpoint, "Serializing VGIC\n");
455
456 SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
457 SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
458 SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
459 SERIALIZE_SCALAR(vcpuAddr);
460 SERIALIZE_SCALAR(hvAddr);
461 SERIALIZE_SCALAR(pioDelay);
462 SERIALIZE_SCALAR(maintInt);
463
464 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++)
465 vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu));
466}
467
468void
469VGic::vcpuIntData::serialize(CheckpointOut &cp) const
470{
471 uint32_t vctrl_val = vctrl;
472 SERIALIZE_SCALAR(vctrl_val);
473 uint32_t hcr_val = hcr;
474 SERIALIZE_SCALAR(hcr_val);
475 uint64_t eisr_val = eisr;
476 SERIALIZE_SCALAR(eisr_val);
477 uint8_t VMGrp0En_val = VMGrp0En;
478 SERIALIZE_SCALAR(VMGrp0En_val);
479 uint8_t VMGrp1En_val = VMGrp1En;
480 SERIALIZE_SCALAR(VMGrp1En_val);
481 uint8_t VMAckCtl_val = VMAckCtl;
482 SERIALIZE_SCALAR(VMAckCtl_val);
483 uint8_t VMFiqEn_val = VMFiqEn;
484 SERIALIZE_SCALAR(VMFiqEn_val);
485 uint8_t VMCBPR_val = VMCBPR;
486 SERIALIZE_SCALAR(VMCBPR_val);
487 uint8_t VEM_val = VEM;
488 SERIALIZE_SCALAR(VEM_val);
489 uint8_t VMABP_val = VMABP;
490 SERIALIZE_SCALAR(VMABP_val);
491 uint8_t VMBP_val = VMBP;
492 SERIALIZE_SCALAR(VMBP_val);
493 uint8_t VMPriMask_val = VMPriMask;
494 SERIALIZE_SCALAR(VMPriMask_val);
495
496 for (int i = 0; i < NUM_LR; i++) {
497 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
498 paramOut(cp, "lr", LR[i]);
499 }
500}
501
502void VGic::unserialize(CheckpointIn &cp)
503{
504 DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
505
506 Tick interrupt_time[VGIC_CPU_MAX];
507 UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
508 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
509 if (interrupt_time[cpu])
510 schedule(postVIntEvent[cpu], interrupt_time[cpu]);
511
512 vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu));
513 }
514 UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
515 UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
516 UNSERIALIZE_SCALAR(vcpuAddr);
517 UNSERIALIZE_SCALAR(hvAddr);
518 UNSERIALIZE_SCALAR(pioDelay);
519 UNSERIALIZE_SCALAR(maintInt);
520}
521
522void
523VGic::vcpuIntData::unserialize(CheckpointIn &cp)
524{
525 paramIn(cp, "vctrl_val", vctrl);
526 paramIn(cp, "hcr_val", hcr);
527 paramIn(cp, "eisr_val", eisr);
528 paramIn(cp, "VMGrp0En_val", VMGrp0En);
529 paramIn(cp, "VMGrp1En_val", VMGrp1En);
530 paramIn(cp, "VMAckCtl_val", VMAckCtl);
531 paramIn(cp, "VMFiqEn_val", VMFiqEn);
532 paramIn(cp, "VMCBPR_val", VMCBPR);
533 paramIn(cp, "VEM_val", VEM);
534 paramIn(cp, "VMABP_val", VMABP);
535 paramIn(cp, "VMPriMask_val", VMPriMask);
536
537 for (int i = 0; i < NUM_LR; i++) {
538 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
539 paramIn(cp, "lr", LR[i]);
540 }
541}
542
543VGic *
544VGicParams::create()
545{
546 return new VGic(this);
547}
381VGic::postMaintInt(uint32_t cpu)
382{
383 DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu);
384 // Linux DT configures this as Level.
385 gic->sendPPInt(maintInt, cpu);
386}
387
388void
389VGic::unPostMaintInt(uint32_t cpu)
390{
391 DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu);
392 gic->clearPPInt(maintInt, cpu);
393}
394
395/* Update state (in general); something concerned with ctx_id has changed.
396 * This may raise a maintenance interrupt.
397 */
398void
399VGic::updateIntState(ContextID ctx_id)
400{
401 // @todo This should update APRs!
402
403 // Build EISR contents:
404 // (Cached so that regs can read them without messing about again)
405 struct vcpuIntData *tvid = &vcpuData[ctx_id];
406
407 tvid->eisr = 0;
408 for (int i = 0; i < NUM_LR; i++) {
409 if (!tvid->LR[i].State && tvid->LR[i].EOI) {
410 tvid->eisr |= 1 << i;
411 }
412 }
413
414 assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
415 for (int i = 0; i < sys->numRunningContexts(); i++) {
416 struct vcpuIntData *vid = &vcpuData[i];
417 // Are any LRs active that weren't before?
418 if (!vIntPosted[i]) {
419 if (lrPending(vid) && vid->vctrl.En) {
420 vIntPosted[i] = true;
421 postVInt(i, curTick() + 1);
422 }
423 } else if (!lrPending(vid)) {
424 vIntPosted[i] = false;
425 unPostVInt(i);
426 }
427
428 // Any maintenance ints to send?
429 if (!maintIntPosted[i]) {
430 if (vid->hcr.En && getMISR(vid)) {
431 maintIntPosted[i] = true;
432 postMaintInt(i);
433 }
434 } else {
435 if (!vid->hcr.En || !getMISR(vid)) {
436 unPostMaintInt(i);
437 maintIntPosted[i] = false;
438 }
439 }
440 }
441}
442
443AddrRangeList
444VGic::getAddrRanges() const
445{
446 AddrRangeList ranges;
447 ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE));
448 ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE));
449 return ranges;
450}
451
452void
453VGic::serialize(CheckpointOut &cp) const
454{
455 Tick interrupt_time[VGIC_CPU_MAX];
456 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
457 interrupt_time[cpu] = 0;
458 if (postVIntEvent[cpu]->scheduled()) {
459 interrupt_time[cpu] = postVIntEvent[cpu]->when();
460 }
461 }
462
463 DPRINTF(Checkpoint, "Serializing VGIC\n");
464
465 SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
466 SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
467 SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
468 SERIALIZE_SCALAR(vcpuAddr);
469 SERIALIZE_SCALAR(hvAddr);
470 SERIALIZE_SCALAR(pioDelay);
471 SERIALIZE_SCALAR(maintInt);
472
473 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++)
474 vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu));
475}
476
477void
478VGic::vcpuIntData::serialize(CheckpointOut &cp) const
479{
480 uint32_t vctrl_val = vctrl;
481 SERIALIZE_SCALAR(vctrl_val);
482 uint32_t hcr_val = hcr;
483 SERIALIZE_SCALAR(hcr_val);
484 uint64_t eisr_val = eisr;
485 SERIALIZE_SCALAR(eisr_val);
486 uint8_t VMGrp0En_val = VMGrp0En;
487 SERIALIZE_SCALAR(VMGrp0En_val);
488 uint8_t VMGrp1En_val = VMGrp1En;
489 SERIALIZE_SCALAR(VMGrp1En_val);
490 uint8_t VMAckCtl_val = VMAckCtl;
491 SERIALIZE_SCALAR(VMAckCtl_val);
492 uint8_t VMFiqEn_val = VMFiqEn;
493 SERIALIZE_SCALAR(VMFiqEn_val);
494 uint8_t VMCBPR_val = VMCBPR;
495 SERIALIZE_SCALAR(VMCBPR_val);
496 uint8_t VEM_val = VEM;
497 SERIALIZE_SCALAR(VEM_val);
498 uint8_t VMABP_val = VMABP;
499 SERIALIZE_SCALAR(VMABP_val);
500 uint8_t VMBP_val = VMBP;
501 SERIALIZE_SCALAR(VMBP_val);
502 uint8_t VMPriMask_val = VMPriMask;
503 SERIALIZE_SCALAR(VMPriMask_val);
504
505 for (int i = 0; i < NUM_LR; i++) {
506 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
507 paramOut(cp, "lr", LR[i]);
508 }
509}
510
511void VGic::unserialize(CheckpointIn &cp)
512{
513 DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
514
515 Tick interrupt_time[VGIC_CPU_MAX];
516 UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
517 for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
518 if (interrupt_time[cpu])
519 schedule(postVIntEvent[cpu], interrupt_time[cpu]);
520
521 vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu));
522 }
523 UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
524 UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
525 UNSERIALIZE_SCALAR(vcpuAddr);
526 UNSERIALIZE_SCALAR(hvAddr);
527 UNSERIALIZE_SCALAR(pioDelay);
528 UNSERIALIZE_SCALAR(maintInt);
529}
530
531void
532VGic::vcpuIntData::unserialize(CheckpointIn &cp)
533{
534 paramIn(cp, "vctrl_val", vctrl);
535 paramIn(cp, "hcr_val", hcr);
536 paramIn(cp, "eisr_val", eisr);
537 paramIn(cp, "VMGrp0En_val", VMGrp0En);
538 paramIn(cp, "VMGrp1En_val", VMGrp1En);
539 paramIn(cp, "VMAckCtl_val", VMAckCtl);
540 paramIn(cp, "VMFiqEn_val", VMFiqEn);
541 paramIn(cp, "VMCBPR_val", VMCBPR);
542 paramIn(cp, "VEM_val", VEM);
543 paramIn(cp, "VMABP_val", VMABP);
544 paramIn(cp, "VMPriMask_val", VMPriMask);
545
546 for (int i = 0; i < NUM_LR; i++) {
547 ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
548 paramIn(cp, "lr", LR[i]);
549 }
550}
551
552VGic *
553VGicParams::create()
554{
555 return new VGic(this);
556}