2 * Copyright (c) 2015-2017 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.
37 * Authors: Andreas Sandberg
41 #include "arch/arm/kvm/gic.hh"
43 #include <linux/kvm.h>
45 #include "arch/arm/kvm/base_cpu.hh"
46 #include "debug/GIC.hh"
47 #include "debug/Interrupt.hh"
48 #include "params/MuxingKvmGic.hh"
50 KvmKernelGicV2::KvmKernelGicV2(KvmVM
&_vm
, Addr cpu_addr
, Addr dist_addr
,
52 : cpuRange(RangeSize(cpu_addr
, KVM_VGIC_V2_CPU_SIZE
)),
53 distRange(RangeSize(dist_addr
, KVM_VGIC_V2_DIST_SIZE
)),
55 kdev(vm
.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2
))
57 // Tell the VM that we will emulate the GIC in the kernel. This
58 // disables IRQ and FIQ handling in the KVM CPU model.
59 vm
.enableKernelIRQChip();
61 kdev
.setAttr
<uint64_t>(
62 KVM_DEV_ARM_VGIC_GRP_ADDR
, KVM_VGIC_V2_ADDR_TYPE_DIST
, dist_addr
);
63 kdev
.setAttr
<uint64_t>(
64 KVM_DEV_ARM_VGIC_GRP_ADDR
, KVM_VGIC_V2_ADDR_TYPE_CPU
, cpu_addr
);
66 kdev
.setAttr
<uint32_t>(KVM_DEV_ARM_VGIC_GRP_NR_IRQS
, 0, it_lines
);
69 KvmKernelGicV2::~KvmKernelGicV2()
74 KvmKernelGicV2::setSPI(unsigned spi
)
76 setIntState(KVM_ARM_IRQ_TYPE_SPI
, 0, spi
, true);
80 KvmKernelGicV2::clearSPI(unsigned spi
)
82 setIntState(KVM_ARM_IRQ_TYPE_SPI
, 0, spi
, false);
86 KvmKernelGicV2::setPPI(unsigned vcpu
, unsigned ppi
)
88 setIntState(KVM_ARM_IRQ_TYPE_PPI
, vcpu
, ppi
, true);
92 KvmKernelGicV2::clearPPI(unsigned vcpu
, unsigned ppi
)
94 setIntState(KVM_ARM_IRQ_TYPE_PPI
, vcpu
, ppi
, false);
98 KvmKernelGicV2::setIntState(unsigned type
, unsigned vcpu
, unsigned irq
,
101 assert(type
<= KVM_ARM_IRQ_TYPE_MASK
);
102 assert(vcpu
<= KVM_ARM_IRQ_VCPU_MASK
);
103 assert(irq
<= KVM_ARM_IRQ_NUM_MASK
);
105 (type
<< KVM_ARM_IRQ_TYPE_SHIFT
) |
106 (vcpu
<< KVM_ARM_IRQ_VCPU_SHIFT
) |
107 (irq
<< KVM_ARM_IRQ_NUM_SHIFT
));
109 vm
.setIRQLine(line
, high
);
113 KvmKernelGicV2::getGicReg(unsigned group
, unsigned vcpu
, unsigned offset
)
117 assert(vcpu
<= KVM_ARM_IRQ_VCPU_MASK
);
119 (vcpu
<< KVM_DEV_ARM_VGIC_CPUID_SHIFT
) |
120 (offset
<< KVM_DEV_ARM_VGIC_OFFSET_SHIFT
));
122 kdev
.getAttrPtr(group
, attr
, ®
);
123 return (uint32_t) reg
;
127 KvmKernelGicV2::setGicReg(unsigned group
, unsigned vcpu
, unsigned offset
,
130 uint64_t reg
= value
;
132 assert(vcpu
<= KVM_ARM_IRQ_VCPU_MASK
);
134 (vcpu
<< KVM_DEV_ARM_VGIC_CPUID_SHIFT
) |
135 (offset
<< KVM_DEV_ARM_VGIC_OFFSET_SHIFT
));
137 kdev
.setAttrPtr(group
, attr
, ®
);
141 KvmKernelGicV2::readDistributor(ContextID ctx
, Addr daddr
)
143 auto vcpu
= vm
.contextIdToVCpuId(ctx
);
144 return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS
, vcpu
, daddr
);
148 KvmKernelGicV2::readCpu(ContextID ctx
, Addr daddr
)
150 auto vcpu
= vm
.contextIdToVCpuId(ctx
);
151 return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS
, vcpu
, daddr
);
155 KvmKernelGicV2::writeDistributor(ContextID ctx
, Addr daddr
, uint32_t data
)
157 auto vcpu
= vm
.contextIdToVCpuId(ctx
);
158 setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS
, vcpu
, daddr
, data
);
162 KvmKernelGicV2::writeCpu(ContextID ctx
, Addr daddr
, uint32_t data
)
164 auto vcpu
= vm
.contextIdToVCpuId(ctx
);
165 setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS
, vcpu
, daddr
, data
);
170 MuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams
*p
)
176 if (auto vm
= system
.getKvmVM()) {
177 kernelGic
= new KvmKernelGicV2(*vm
, p
->cpu_addr
, p
->dist_addr
,
182 MuxingKvmGic::~MuxingKvmGic()
187 MuxingKvmGic::loadState(CheckpointIn
&cp
)
189 Pl390::loadState(cp
);
193 MuxingKvmGic::startup()
196 usingKvm
= (kernelGic
!= nullptr) && system
.validKvmEnvironment();
202 MuxingKvmGic::drain()
206 return Pl390::drain();
210 MuxingKvmGic::drainResume()
212 Pl390::drainResume();
213 bool use_kvm
= (kernelGic
!= nullptr) && system
.validKvmEnvironment();
214 if (use_kvm
!= usingKvm
) {
215 // Should only occur due to CPU switches
216 if (use_kvm
) // from simulation to KVM emulation
218 // otherwise, drain() already sync'd the state back to the Pl390
225 MuxingKvmGic::serialize(CheckpointOut
&cp
) const
227 // drain() already ensured Pl390 updated with KvmGic state if necessary
228 Pl390::serialize(cp
);
232 MuxingKvmGic::unserialize(CheckpointIn
&cp
)
234 Pl390::unserialize(cp
);
238 MuxingKvmGic::read(PacketPtr pkt
)
241 return Pl390::read(pkt
);
243 panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
247 MuxingKvmGic::write(PacketPtr pkt
)
250 return Pl390::write(pkt
);
252 panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
256 MuxingKvmGic::sendInt(uint32_t num
)
259 return Pl390::sendInt(num
);
261 DPRINTF(Interrupt
, "Set SPI %d\n", num
);
262 kernelGic
->setSPI(num
);
266 MuxingKvmGic::clearInt(uint32_t num
)
269 return Pl390::clearInt(num
);
271 DPRINTF(Interrupt
, "Clear SPI %d\n", num
);
272 kernelGic
->clearSPI(num
);
276 MuxingKvmGic::sendPPInt(uint32_t num
, uint32_t cpu
)
279 return Pl390::sendPPInt(num
, cpu
);
280 DPRINTF(Interrupt
, "Set PPI %d:%d\n", cpu
, num
);
281 kernelGic
->setPPI(cpu
, num
);
285 MuxingKvmGic::clearPPInt(uint32_t num
, uint32_t cpu
)
288 return Pl390::clearPPInt(num
, cpu
);
290 DPRINTF(Interrupt
, "Clear PPI %d:%d\n", cpu
, num
);
291 kernelGic
->clearPPI(cpu
, num
);
295 MuxingKvmGic::copyDistRegister(BaseGicRegisters
* from
, BaseGicRegisters
* to
,
296 ContextID ctx
, Addr daddr
)
298 auto val
= from
->readDistributor(ctx
, daddr
);
299 DPRINTF(GIC
, "copy dist 0x%x 0x%08x\n", daddr
, val
);
300 to
->writeDistributor(ctx
, daddr
, val
);
304 MuxingKvmGic::copyCpuRegister(BaseGicRegisters
* from
, BaseGicRegisters
* to
,
305 ContextID ctx
, Addr daddr
)
307 auto val
= from
->readCpu(ctx
, daddr
);
308 DPRINTF(GIC
, "copy cpu 0x%x 0x%08x\n", daddr
, val
);
309 to
->writeCpu(ctx
, daddr
, val
);
313 MuxingKvmGic::copyBankedDistRange(BaseGicRegisters
* from
, BaseGicRegisters
* to
,
314 Addr daddr
, size_t size
)
316 for (int ctx
= 0; ctx
< system
._numContexts
; ++ctx
)
317 for (auto a
= daddr
; a
< daddr
+ size
; a
+= 4)
318 copyDistRegister(from
, to
, ctx
, a
);
322 MuxingKvmGic::clearBankedDistRange(BaseGicRegisters
* to
,
323 Addr daddr
, size_t size
)
325 for (int ctx
= 0; ctx
< system
._numContexts
; ++ctx
)
326 for (auto a
= daddr
; a
< daddr
+ size
; a
+= 4)
327 to
->writeDistributor(ctx
, a
, 0xFFFFFFFF);
331 MuxingKvmGic::copyDistRange(BaseGicRegisters
* from
, BaseGicRegisters
* to
,
332 Addr daddr
, size_t size
)
334 for (auto a
= daddr
; a
< daddr
+ size
; a
+= 4)
335 copyDistRegister(from
, to
, 0, a
);
339 MuxingKvmGic::clearDistRange(BaseGicRegisters
* to
,
340 Addr daddr
, size_t size
)
342 for (auto a
= daddr
; a
< daddr
+ size
; a
+= 4)
343 to
->writeDistributor(0, a
, 0xFFFFFFFF);
347 MuxingKvmGic::copyGicState(BaseGicRegisters
* from
, BaseGicRegisters
* to
)
352 /// CPU state (GICC_*)
353 // Copy CPU Interface Control Register (CTLR),
354 // Interrupt Priority Mask Register (PMR), and
355 // Binary Point Register (BPR)
356 for (int ctx
= 0; ctx
< system
._numContexts
; ++ctx
) {
357 copyCpuRegister(from
, to
, ctx
, GICC_CTLR
);
358 copyCpuRegister(from
, to
, ctx
, GICC_PMR
);
359 copyCpuRegister(from
, to
, ctx
, GICC_BPR
);
363 /// Distributor state (GICD_*)
364 // Copy Distributor Control Register (CTLR)
365 copyDistRegister(from
, to
, 0, GICD_CTLR
);
367 // Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
368 set
= Pl390::GICD_ISENABLER
.start();
369 clear
= Pl390::GICD_ICENABLER
.start();
370 size
= Pl390::itLines
/ 8;
371 clearBankedDistRange(to
, clear
, 4);
372 copyBankedDistRange(from
, to
, set
, 4);
374 set
+= 4, clear
+= 4, size
-= 4;
375 clearDistRange(to
, clear
, size
);
376 copyDistRange(from
, to
, set
, size
);
378 // Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
379 set
= Pl390::GICD_ISPENDR
.start();
380 clear
= Pl390::GICD_ICPENDR
.start();
381 size
= Pl390::itLines
/ 8;
382 clearBankedDistRange(to
, clear
, 4);
383 copyBankedDistRange(from
, to
, set
, 4);
385 set
+= 4, clear
+= 4, size
-= 4;
386 clearDistRange(to
, clear
, size
);
387 copyDistRange(from
, to
, set
, size
);
389 // Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
390 set
= Pl390::GICD_ISACTIVER
.start();
391 clear
= Pl390::GICD_ICACTIVER
.start();
392 size
= Pl390::itLines
/ 8;
393 clearBankedDistRange(to
, clear
, 4);
394 copyBankedDistRange(from
, to
, set
, 4);
396 set
+= 4, clear
+= 4, size
-= 4;
397 clearDistRange(to
, clear
, size
);
398 copyDistRange(from
, to
, set
, size
);
400 // Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
401 set
= Pl390::GICD_IPRIORITYR
.start();
402 copyBankedDistRange(from
, to
, set
, 32);
405 size
= Pl390::itLines
- 32;
406 copyDistRange(from
, to
, set
, size
);
408 // Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
409 set
= Pl390::GICD_ITARGETSR
.start() + 32;
410 size
= Pl390::itLines
- 32;
411 copyDistRange(from
, to
, set
, size
);
413 // Copy interrupt configuration registers (ICFGRn)
414 set
= Pl390::GICD_ICFGR
.start();
415 size
= Pl390::itLines
/ 4;
416 copyDistRange(from
, to
, set
, size
);
420 MuxingKvmGic::fromPl390ToKvm()
422 copyGicState(static_cast<Pl390
*>(this), kernelGic
);
426 MuxingKvmGic::fromKvmToPl390()
428 copyGicState(kernelGic
, static_cast<Pl390
*>(this));
430 // the values read for the Interrupt Priority Mask Register (PMR)
431 // have been shifted by three bits due to its having been emulated by
432 // a VGIC with only 5 PMR bits in its VMCR register. Presently the
433 // Linux kernel does not repair this inaccuracy, so we correct it here.
434 for (int cpu
= 0; cpu
< system
._numContexts
; ++cpu
) {
435 cpuPriority
[cpu
] <<= 3;
436 assert((cpuPriority
[cpu
] & ~0xff) == 0);
441 MuxingKvmGicParams::create()
443 return new MuxingKvmGic(this);