2 * Copyright (c) 2013 ARM Limited
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.
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.
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.
40 #include "base/trace.hh"
41 #include "debug/Checkpoint.hh"
42 #include "debug/VGIC.hh"
43 #include "dev/arm/base_gic.hh"
44 #include "dev/arm/vgic.hh"
45 #include "dev/terminal.hh"
46 #include "mem/packet.hh"
47 #include "mem/packet_access.hh"
49 VGic::VGic(const Params
*p
)
50 : PioDevice(p
), platform(p
->platform
), gic(p
->gic
), vcpuAddr(p
->vcpu_addr
),
51 hvAddr(p
->hv_addr
), pioDelay(p
->pio_delay
),
54 for (int x
= 0; x
< VGIC_CPU_MAX
; x
++) {
55 postVIntEvent
[x
] = new PostVIntEvent(x
, p
->platform
);
56 maintIntPosted
[x
] = false;
57 vIntPosted
[x
] = false;
59 for (int c
= 0; c
< VGIC_CPU_MAX
; c
++) {
60 memset(&vcpuData
[c
], 0, sizeof(struct vcpuIntData
));
62 assert(sys
->numRunningContexts() <= VGIC_CPU_MAX
);
66 VGic::read(PacketPtr pkt
)
68 Addr addr
= pkt
->getAddr();
70 if (addr
>= vcpuAddr
&& addr
< vcpuAddr
+ GICV_SIZE
)
72 else if (addr
>= hvAddr
&& addr
< hvAddr
+ GICH_REG_SIZE
)
75 panic("Read to unknown address %#x\n", pkt
->getAddr());
79 VGic::write(PacketPtr pkt
)
81 Addr addr
= pkt
->getAddr();
83 if (addr
>= vcpuAddr
&& addr
< vcpuAddr
+ GICV_SIZE
)
84 return writeVCpu(pkt
);
85 else if (addr
>= hvAddr
&& addr
< hvAddr
+ GICH_REG_SIZE
)
86 return writeCtrl(pkt
);
88 panic("Write to unknown address %#x\n", pkt
->getAddr());
92 VGic::readVCpu(PacketPtr pkt
)
94 Addr daddr
= pkt
->getAddr() - vcpuAddr
;
97 int ctx_id
= pkt
->req
->contextId();
98 assert(ctx_id
< VGIC_CPU_MAX
);
99 struct vcpuIntData
*vid
= &vcpuData
[ctx_id
];
101 DPRINTF(VGIC
, "VGIC VCPU read register %#x\n", daddr
);
105 pkt
->set
<uint32_t>(vid
->vctrl
);
108 int i
= findHighestPendingLR(vid
);
109 if (i
< 0 || !vid
->vctrl
.En
) {
110 pkt
->set
<uint32_t>(1023); // "No int" marker
112 ListReg
*lr
= &vid
->LR
[i
];
114 pkt
->set
<uint32_t>(lr
->VirtualID
|
115 (((int)lr
->CpuID
) << 10));
116 // We don't support auto-EOI of HW interrupts via real GIC!
117 // Fortunately, KVM doesn't use this. How about Xen...? Ulp!
119 panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
121 lr
->State
= LR_ACTIVE
;
122 DPRINTF(VGIC
, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
123 lr
->VirtualID
, lr
->CpuID
, i
, lr
->EOI
);
127 panic("VGIC VCPU read of bad address %#x\n", daddr
);
130 updateIntState(ctx_id
);
132 pkt
->makeAtomicResponse();
137 VGic::readCtrl(PacketPtr pkt
)
139 Addr daddr
= pkt
->getAddr() - hvAddr
;
142 int ctx_id
= pkt
->req
->contextId();
144 DPRINTF(VGIC
, "VGIC HVCtrl read register %#x\n", daddr
);
146 /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
147 * Anything > that is 0x200-sized slices of 'per CPU' regs.
149 if (daddr
& ~0x1ff) {
150 ctx_id
= (daddr
>> 9);
152 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr
);
155 assert(ctx_id
< VGIC_CPU_MAX
);
156 struct vcpuIntData
*vid
= &vcpuData
[ctx_id
];
160 pkt
->set
<uint32_t>(vid
->hcr
);
164 pkt
->set
<uint32_t>(0x44000000 | (NUM_LR
- 1));
169 ((uint32_t)vid
->VMPriMask
<< 27) |
170 ((uint32_t)vid
->VMBP
<< 21) |
171 ((uint32_t)vid
->VMABP
<< 18) |
172 ((uint32_t)vid
->VEM
<< 9) |
173 ((uint32_t)vid
->VMCBPR
<< 4) |
174 ((uint32_t)vid
->VMFiqEn
<< 3) |
175 ((uint32_t)vid
->VMAckCtl
<< 2) |
176 ((uint32_t)vid
->VMGrp1En
<< 1) |
177 ((uint32_t)vid
->VMGrp0En
<< 0)
182 pkt
->set
<uint32_t>(getMISR(vid
));
186 pkt
->set
<uint32_t>(vid
->eisr
& 0xffffffff);
190 pkt
->set
<uint32_t>(vid
->eisr
>> 32);
195 for (int i
= 0; i
< ((NUM_LR
< 32) ? NUM_LR
: 32); i
++) {
196 if (!vid
->LR
[i
].State
)
199 pkt
->set
<uint32_t>(bm
);
204 for (int i
= 32; i
< NUM_LR
; i
++) {
205 if (!vid
->LR
[i
].State
)
208 pkt
->set
<uint32_t>(bm
);
212 warn_once("VGIC GICH_APR read!\n");
213 pkt
->set
<uint32_t>(0);
220 pkt
->set
<uint32_t>(vid
->LR
[(daddr
- GICH_LR0
) >> 2]);
224 panic("VGIC HVCtrl read of bad address %#x\n", daddr
);
227 pkt
->makeAtomicResponse();
232 VGic::writeVCpu(PacketPtr pkt
)
234 Addr daddr
= pkt
->getAddr() - vcpuAddr
;
237 int ctx_id
= pkt
->req
->contextId();
238 assert(ctx_id
< VGIC_CPU_MAX
);
239 struct vcpuIntData
*vid
= &vcpuData
[ctx_id
];
241 DPRINTF(VGIC
, "VGIC VCPU write register %#x <= %#x\n", daddr
, pkt
->get
<uint32_t>());
245 vid
->vctrl
= pkt
->get
<uint32_t>();
248 vid
->VMPriMask
= pkt
->get
<uint32_t>();
251 // We don't handle the split EOI-then-DIR mode. Linux (guest)
252 // doesn't need it though.
253 assert(!vid
->vctrl
.EOImode
);
254 uint32_t w
= pkt
->get
<uint32_t>();
255 unsigned int virq
= w
& 0x3ff;
256 unsigned int vcpu
= (w
>> 10) & 7;
257 int i
= findLRForVIRQ(vid
, virq
, vcpu
);
259 DPRINTF(VGIC
, "EOIR: No LR for irq %d(cpu%d)\n", virq
, vcpu
);
261 DPRINTF(VGIC
, "EOIR: Found LR%d for irq %d(cpu%d)\n", i
, virq
, vcpu
);
262 ListReg
*lr
= &vid
->LR
[i
];
264 // Maintenance interrupt -- via eisr -- is flagged when
265 // LRs have EOI=1 and State=INVALID!
269 panic("VGIC VCPU write %#x to unk address %#x\n", pkt
->get
<uint32_t>(), daddr
);
272 // This updates the EISRs and flags IRQs:
273 updateIntState(ctx_id
);
275 pkt
->makeAtomicResponse();
280 VGic::writeCtrl(PacketPtr pkt
)
282 Addr daddr
= pkt
->getAddr() - hvAddr
;
285 int ctx_id
= pkt
->req
->contextId();
287 DPRINTF(VGIC
, "VGIC HVCtrl write register %#x <= %#x\n", daddr
, pkt
->get
<uint32_t>());
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.
292 if (daddr
& ~0x1ff) {
293 ctx_id
= (daddr
>> 9);
295 panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr
);
298 assert(ctx_id
< VGIC_CPU_MAX
);
299 struct vcpuIntData
*vid
= &vcpuData
[ctx_id
];
303 vid
->hcr
= pkt
->get
<uint32_t>();
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;
321 warn_once("VGIC GICH_APR0 written, ignored\n");
328 vid
->LR
[(daddr
- GICH_LR0
) >> 2] = pkt
->get
<uint32_t>();
333 panic("VGIC HVCtrl write to bad address %#x\n", daddr
);
336 updateIntState(ctx_id
);
338 pkt
->makeAtomicResponse();
344 VGic::getMISR(struct vcpuIntData
*vid
)
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);
357 VGic::postVInt(uint32_t cpu
, Tick when
)
359 DPRINTF(VGIC
, "Posting VIRQ to %d\n", cpu
);
360 if (!(postVIntEvent
[cpu
]->scheduled()))
361 eventq
->schedule(postVIntEvent
[cpu
], when
);
365 VGic::unPostVInt(uint32_t cpu
)
367 DPRINTF(VGIC
, "Unposting VIRQ to %d\n", cpu
);
368 platform
->intrctrl
->clear(cpu
, ArmISA::INT_VIRT_IRQ
, 0);
372 VGic::postMaintInt(uint32_t cpu
)
374 DPRINTF(VGIC
, "Posting maintenance PPI to GIC/cpu%d\n", cpu
);
375 // Linux DT configures this as Level.
376 gic
->sendPPInt(maintInt
, cpu
);
380 VGic::unPostMaintInt(uint32_t cpu
)
382 DPRINTF(VGIC
, "Unposting maintenance PPI to GIC/cpu%d\n", cpu
);
383 gic
->clearPPInt(maintInt
, cpu
);
386 /* Update state (in general); something concerned with ctx_id has changed.
387 * This may raise a maintenance interrupt.
390 VGic::updateIntState(int ctx_id
)
392 // @todo This should update APRs!
394 // Build EISR contents:
395 // (Cached so that regs can read them without messing about again)
396 struct vcpuIntData
*tvid
= &vcpuData
[ctx_id
];
399 for (int i
= 0; i
< NUM_LR
; i
++) {
400 if (!tvid
->LR
[i
].State
&& tvid
->LR
[i
].EOI
) {
401 tvid
->eisr
|= 1 << i
;
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);
414 } else if (!lrPending(vid
)) {
415 vIntPosted
[i
] = false;
419 // Any maintenance ints to send?
420 if (!maintIntPosted
[i
]) {
421 if (vid
->hcr
.En
&& getMISR(vid
)) {
422 maintIntPosted
[i
] = true;
426 if (!vid
->hcr
.En
|| !getMISR(vid
)) {
428 maintIntPosted
[i
] = false;
435 VGic::getAddrRanges() const
437 AddrRangeList ranges
;
438 ranges
.push_back(RangeSize(hvAddr
, GICH_REG_SIZE
));
439 ranges
.push_back(RangeSize(vcpuAddr
, GICV_SIZE
));
444 VGic::serialize(std::ostream
&os
)
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();
454 DPRINTF(Checkpoint
, "Serializing VGIC\n");
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
);
464 for (uint32_t cpu
= 0; cpu
< VGIC_CPU_MAX
; cpu
++) {
465 nameOut(os
, csprintf("%s.vcpuData%d", name(), cpu
));
466 uint32_t vctrl_val
= vcpuData
[cpu
].vctrl
;
467 SERIALIZE_SCALAR(vctrl_val
);
468 uint32_t hcr_val
= vcpuData
[cpu
].hcr
;
469 SERIALIZE_SCALAR(hcr_val
);
470 uint64_t eisr_val
= vcpuData
[cpu
].eisr
;
471 SERIALIZE_SCALAR(eisr_val
);
472 uint8_t VMGrp0En_val
= vcpuData
[cpu
].VMGrp0En
;
473 SERIALIZE_SCALAR(VMGrp0En_val
);
474 uint8_t VMGrp1En_val
= vcpuData
[cpu
].VMGrp1En
;
475 SERIALIZE_SCALAR(VMGrp1En_val
);
476 uint8_t VMAckCtl_val
= vcpuData
[cpu
].VMAckCtl
;
477 SERIALIZE_SCALAR(VMAckCtl_val
);
478 uint8_t VMFiqEn_val
= vcpuData
[cpu
].VMFiqEn
;
479 SERIALIZE_SCALAR(VMFiqEn_val
);
480 uint8_t VMCBPR_val
= vcpuData
[cpu
].VMCBPR
;
481 SERIALIZE_SCALAR(VMCBPR_val
);
482 uint8_t VEM_val
= vcpuData
[cpu
].VEM
;
483 SERIALIZE_SCALAR(VEM_val
);
484 uint8_t VMABP_val
= vcpuData
[cpu
].VMABP
;
485 SERIALIZE_SCALAR(VMABP_val
);
486 uint8_t VMBP_val
= vcpuData
[cpu
].VMBP
;
487 SERIALIZE_SCALAR(VMBP_val
);
488 uint8_t VMPriMask_val
= vcpuData
[cpu
].VMPriMask
;
489 SERIALIZE_SCALAR(VMPriMask_val
);
491 for (int i
= 0; i
< NUM_LR
; i
++) {
492 uint32_t lr
= vcpuData
[cpu
].LR
[i
];
493 nameOut(os
, csprintf("%s.vcpuData%d.LR%d", name(), cpu
, i
));
494 SERIALIZE_SCALAR(lr
);
499 void VGic::unserialize(Checkpoint
*cp
, const std::string
§ion
)
501 DPRINTF(Checkpoint
, "Unserializing Arm GIC\n");
503 Tick interrupt_time
[VGIC_CPU_MAX
];
504 UNSERIALIZE_ARRAY(interrupt_time
, VGIC_CPU_MAX
);
505 for (uint32_t cpu
= 0; cpu
< VGIC_CPU_MAX
; cpu
++) {
506 if (interrupt_time
[cpu
])
507 schedule(postVIntEvent
[cpu
], interrupt_time
[cpu
]);
510 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
512 vcpuData
[cpu
].vctrl
= tmp
;
513 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
515 vcpuData
[cpu
].hcr
= tmp
;
516 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
517 "eisr_val", vcpuData
[cpu
].eisr
);
518 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
519 "VMGrp0En_val", vcpuData
[cpu
].VMGrp0En
);
520 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
521 "VMGrp1En_val", vcpuData
[cpu
].VMGrp1En
);
522 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
523 "VMAckCtl_val", vcpuData
[cpu
].VMAckCtl
);
524 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
525 "VMFiqEn_val", vcpuData
[cpu
].VMFiqEn
);
526 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
527 "VMCBPR_val", vcpuData
[cpu
].VMCBPR
);
528 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
529 "VEM_val", vcpuData
[cpu
].VEM
);
530 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
531 "VMABP_val", vcpuData
[cpu
].VMABP
);
532 paramIn(cp
, csprintf("%s.vcpuData%d", section
, cpu
),
533 "VMPriMask_val", vcpuData
[cpu
].VMPriMask
);
535 for (int i
= 0; i
< NUM_LR
; i
++) {
536 paramIn(cp
, csprintf("%s.vcpuData%d.LR%d", section
, cpu
, i
),
538 vcpuData
[cpu
].LR
[i
] = tmp
;
541 UNSERIALIZE_ARRAY(maintIntPosted
, VGIC_CPU_MAX
);
542 UNSERIALIZE_ARRAY(vIntPosted
, VGIC_CPU_MAX
);
543 UNSERIALIZE_SCALAR(vcpuAddr
);
544 UNSERIALIZE_SCALAR(hvAddr
);
545 UNSERIALIZE_SCALAR(pioDelay
);
546 UNSERIALIZE_SCALAR(maintInt
);
552 return new VGic(this);