gic.cc (11943:0a924b294735) gic.cc (12100:5f19ea125548)
1/*
2 * Copyright (c) 2015-2017 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: Andreas Sandberg
38 * Curtis Dunham
39 */
40
41#include "arch/arm/kvm/gic.hh"
42
43#include <linux/kvm.h>
44
45#include "arch/arm/kvm/base_cpu.hh"
46#include "debug/GIC.hh"
47#include "debug/Interrupt.hh"
48#include "params/MuxingKvmGic.hh"
49
50KvmKernelGicV2::KvmKernelGicV2(KvmVM &_vm, Addr cpu_addr, Addr dist_addr,
51 unsigned it_lines)
52 : cpuRange(RangeSize(cpu_addr, KVM_VGIC_V2_CPU_SIZE)),
53 distRange(RangeSize(dist_addr, KVM_VGIC_V2_DIST_SIZE)),
54 vm(_vm),
55 kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2))
56{
57 kdev.setAttr<uint64_t>(
58 KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr);
59 kdev.setAttr<uint64_t>(
60 KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, cpu_addr);
61
62 kdev.setAttr<uint32_t>(KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, it_lines);
63}
64
65KvmKernelGicV2::~KvmKernelGicV2()
66{
67}
68
69void
70KvmKernelGicV2::setSPI(unsigned spi)
71{
72 setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, true);
73}
74
75void
76KvmKernelGicV2::clearSPI(unsigned spi)
77{
78 setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, false);
79}
80
81void
82KvmKernelGicV2::setPPI(unsigned vcpu, unsigned ppi)
83{
84 setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, true);
85}
86
87void
88KvmKernelGicV2::clearPPI(unsigned vcpu, unsigned ppi)
89{
90 setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, false);
91}
92
93void
94KvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq,
95 bool high)
96{
97 assert(type <= KVM_ARM_IRQ_TYPE_MASK);
98 assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
99 assert(irq <= KVM_ARM_IRQ_NUM_MASK);
100 const uint32_t line(
101 (type << KVM_ARM_IRQ_TYPE_SHIFT) |
102 (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) |
103 (irq << KVM_ARM_IRQ_NUM_SHIFT));
104
105 vm.setIRQLine(line, high);
106}
107
108uint32_t
109KvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
110{
111 uint64_t reg;
112
113 assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
114 const uint32_t attr(
115 (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
116 (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
117
118 kdev.getAttrPtr(group, attr, &reg);
119 return (uint32_t) reg;
120}
121
122void
123KvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
124 unsigned value)
125{
126 uint64_t reg = value;
127
128 assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
129 const uint32_t attr(
130 (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
131 (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
132
133 kdev.setAttrPtr(group, attr, &reg);
134}
135
136uint32_t
137KvmKernelGicV2::readDistributor(ContextID ctx, Addr daddr)
138{
139 auto vcpu = vm.contextIdToVCpuId(ctx);
140 return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
141}
142
143uint32_t
144KvmKernelGicV2::readCpu(ContextID ctx, Addr daddr)
145{
146 auto vcpu = vm.contextIdToVCpuId(ctx);
147 return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
148}
149
150void
151KvmKernelGicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data)
152{
153 auto vcpu = vm.contextIdToVCpuId(ctx);
154 setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
155}
156
157void
158KvmKernelGicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
159{
160 auto vcpu = vm.contextIdToVCpuId(ctx);
161 setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
162}
163
164
165
166MuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams *p)
167 : Pl390(p),
168 system(*p->system),
169 kernelGic(nullptr),
170 usingKvm(false)
171{
172 if (auto vm = system.getKvmVM()) {
173 kernelGic = new KvmKernelGicV2(*vm, p->cpu_addr, p->dist_addr,
174 p->it_lines);
175 }
176}
177
178MuxingKvmGic::~MuxingKvmGic()
179{
180}
181
182void
183MuxingKvmGic::loadState(CheckpointIn &cp)
184{
185 Pl390::loadState(cp);
186}
187
188void
189MuxingKvmGic::startup()
190{
191 Pl390::startup();
1/*
2 * Copyright (c) 2015-2017 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: Andreas Sandberg
38 * Curtis Dunham
39 */
40
41#include "arch/arm/kvm/gic.hh"
42
43#include <linux/kvm.h>
44
45#include "arch/arm/kvm/base_cpu.hh"
46#include "debug/GIC.hh"
47#include "debug/Interrupt.hh"
48#include "params/MuxingKvmGic.hh"
49
50KvmKernelGicV2::KvmKernelGicV2(KvmVM &_vm, Addr cpu_addr, Addr dist_addr,
51 unsigned it_lines)
52 : cpuRange(RangeSize(cpu_addr, KVM_VGIC_V2_CPU_SIZE)),
53 distRange(RangeSize(dist_addr, KVM_VGIC_V2_DIST_SIZE)),
54 vm(_vm),
55 kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2))
56{
57 kdev.setAttr<uint64_t>(
58 KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr);
59 kdev.setAttr<uint64_t>(
60 KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, cpu_addr);
61
62 kdev.setAttr<uint32_t>(KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, it_lines);
63}
64
65KvmKernelGicV2::~KvmKernelGicV2()
66{
67}
68
69void
70KvmKernelGicV2::setSPI(unsigned spi)
71{
72 setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, true);
73}
74
75void
76KvmKernelGicV2::clearSPI(unsigned spi)
77{
78 setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, false);
79}
80
81void
82KvmKernelGicV2::setPPI(unsigned vcpu, unsigned ppi)
83{
84 setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, true);
85}
86
87void
88KvmKernelGicV2::clearPPI(unsigned vcpu, unsigned ppi)
89{
90 setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, false);
91}
92
93void
94KvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq,
95 bool high)
96{
97 assert(type <= KVM_ARM_IRQ_TYPE_MASK);
98 assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
99 assert(irq <= KVM_ARM_IRQ_NUM_MASK);
100 const uint32_t line(
101 (type << KVM_ARM_IRQ_TYPE_SHIFT) |
102 (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) |
103 (irq << KVM_ARM_IRQ_NUM_SHIFT));
104
105 vm.setIRQLine(line, high);
106}
107
108uint32_t
109KvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
110{
111 uint64_t reg;
112
113 assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
114 const uint32_t attr(
115 (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
116 (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
117
118 kdev.getAttrPtr(group, attr, &reg);
119 return (uint32_t) reg;
120}
121
122void
123KvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
124 unsigned value)
125{
126 uint64_t reg = value;
127
128 assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
129 const uint32_t attr(
130 (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
131 (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
132
133 kdev.setAttrPtr(group, attr, &reg);
134}
135
136uint32_t
137KvmKernelGicV2::readDistributor(ContextID ctx, Addr daddr)
138{
139 auto vcpu = vm.contextIdToVCpuId(ctx);
140 return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
141}
142
143uint32_t
144KvmKernelGicV2::readCpu(ContextID ctx, Addr daddr)
145{
146 auto vcpu = vm.contextIdToVCpuId(ctx);
147 return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
148}
149
150void
151KvmKernelGicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data)
152{
153 auto vcpu = vm.contextIdToVCpuId(ctx);
154 setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
155}
156
157void
158KvmKernelGicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
159{
160 auto vcpu = vm.contextIdToVCpuId(ctx);
161 setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
162}
163
164
165
166MuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams *p)
167 : Pl390(p),
168 system(*p->system),
169 kernelGic(nullptr),
170 usingKvm(false)
171{
172 if (auto vm = system.getKvmVM()) {
173 kernelGic = new KvmKernelGicV2(*vm, p->cpu_addr, p->dist_addr,
174 p->it_lines);
175 }
176}
177
178MuxingKvmGic::~MuxingKvmGic()
179{
180}
181
182void
183MuxingKvmGic::loadState(CheckpointIn &cp)
184{
185 Pl390::loadState(cp);
186}
187
188void
189MuxingKvmGic::startup()
190{
191 Pl390::startup();
192 usingKvm = (kernelGic != nullptr) && validKvmEnvironment();
192 usingKvm = (kernelGic != nullptr) && system.validKvmEnvironment();
193 if (usingKvm)
194 fromPl390ToKvm();
195}
196
197DrainState
198MuxingKvmGic::drain()
199{
200 if (usingKvm)
201 fromKvmToPl390();
202 return Pl390::drain();
203}
204
205void
206MuxingKvmGic::drainResume()
207{
208 Pl390::drainResume();
193 if (usingKvm)
194 fromPl390ToKvm();
195}
196
197DrainState
198MuxingKvmGic::drain()
199{
200 if (usingKvm)
201 fromKvmToPl390();
202 return Pl390::drain();
203}
204
205void
206MuxingKvmGic::drainResume()
207{
208 Pl390::drainResume();
209 bool use_kvm = (kernelGic != nullptr) && validKvmEnvironment();
209 bool use_kvm = (kernelGic != nullptr) && system.validKvmEnvironment();
210 if (use_kvm != usingKvm) {
211 // Should only occur due to CPU switches
212 if (use_kvm) // from simulation to KVM emulation
213 fromPl390ToKvm();
214 // otherwise, drain() already sync'd the state back to the Pl390
215
216 usingKvm = use_kvm;
217 }
218}
219
220void
221MuxingKvmGic::serialize(CheckpointOut &cp) const
222{
223 // drain() already ensured Pl390 updated with KvmGic state if necessary
224 Pl390::serialize(cp);
225}
226
227void
228MuxingKvmGic::unserialize(CheckpointIn &cp)
229{
230 Pl390::unserialize(cp);
231}
232
233Tick
234MuxingKvmGic::read(PacketPtr pkt)
235{
236 if (!usingKvm)
237 return Pl390::read(pkt);
238
239 panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
240}
241
242Tick
243MuxingKvmGic::write(PacketPtr pkt)
244{
245 if (!usingKvm)
246 return Pl390::write(pkt);
247
248 panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
249}
250
251void
252MuxingKvmGic::sendInt(uint32_t num)
253{
254 if (!usingKvm)
255 return Pl390::sendInt(num);
256
257 DPRINTF(Interrupt, "Set SPI %d\n", num);
258 kernelGic->setSPI(num);
259}
260
261void
262MuxingKvmGic::clearInt(uint32_t num)
263{
264 if (!usingKvm)
265 return Pl390::clearInt(num);
266
267 DPRINTF(Interrupt, "Clear SPI %d\n", num);
268 kernelGic->clearSPI(num);
269}
270
271void
272MuxingKvmGic::sendPPInt(uint32_t num, uint32_t cpu)
273{
274 if (!usingKvm)
275 return Pl390::sendPPInt(num, cpu);
276 DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
277 kernelGic->setPPI(cpu, num);
278}
279
280void
281MuxingKvmGic::clearPPInt(uint32_t num, uint32_t cpu)
282{
283 if (!usingKvm)
284 return Pl390::clearPPInt(num, cpu);
285
286 DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
287 kernelGic->clearPPI(cpu, num);
288}
289
210 if (use_kvm != usingKvm) {
211 // Should only occur due to CPU switches
212 if (use_kvm) // from simulation to KVM emulation
213 fromPl390ToKvm();
214 // otherwise, drain() already sync'd the state back to the Pl390
215
216 usingKvm = use_kvm;
217 }
218}
219
220void
221MuxingKvmGic::serialize(CheckpointOut &cp) const
222{
223 // drain() already ensured Pl390 updated with KvmGic state if necessary
224 Pl390::serialize(cp);
225}
226
227void
228MuxingKvmGic::unserialize(CheckpointIn &cp)
229{
230 Pl390::unserialize(cp);
231}
232
233Tick
234MuxingKvmGic::read(PacketPtr pkt)
235{
236 if (!usingKvm)
237 return Pl390::read(pkt);
238
239 panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
240}
241
242Tick
243MuxingKvmGic::write(PacketPtr pkt)
244{
245 if (!usingKvm)
246 return Pl390::write(pkt);
247
248 panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
249}
250
251void
252MuxingKvmGic::sendInt(uint32_t num)
253{
254 if (!usingKvm)
255 return Pl390::sendInt(num);
256
257 DPRINTF(Interrupt, "Set SPI %d\n", num);
258 kernelGic->setSPI(num);
259}
260
261void
262MuxingKvmGic::clearInt(uint32_t num)
263{
264 if (!usingKvm)
265 return Pl390::clearInt(num);
266
267 DPRINTF(Interrupt, "Clear SPI %d\n", num);
268 kernelGic->clearSPI(num);
269}
270
271void
272MuxingKvmGic::sendPPInt(uint32_t num, uint32_t cpu)
273{
274 if (!usingKvm)
275 return Pl390::sendPPInt(num, cpu);
276 DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
277 kernelGic->setPPI(cpu, num);
278}
279
280void
281MuxingKvmGic::clearPPInt(uint32_t num, uint32_t cpu)
282{
283 if (!usingKvm)
284 return Pl390::clearPPInt(num, cpu);
285
286 DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
287 kernelGic->clearPPI(cpu, num);
288}
289
290bool
291MuxingKvmGic::validKvmEnvironment() const
292{
293 if (system.threadContexts.empty())
294 return false;
295
296 for (auto tc : system.threadContexts) {
297 if (dynamic_cast<BaseArmKvmCPU*>(tc->getCpuPtr()) == nullptr) {
298 return false;
299 }
300 }
301 return true;
302}
303
304void
305MuxingKvmGic::copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
306 ContextID ctx, Addr daddr)
307{
308 auto val = from->readDistributor(ctx, daddr);
309 DPRINTF(GIC, "copy dist 0x%x 0x%08x\n", daddr, val);
310 to->writeDistributor(ctx, daddr, val);
311}
312
313void
314MuxingKvmGic::copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
315 ContextID ctx, Addr daddr)
316{
317 auto val = from->readCpu(ctx, daddr);
318 DPRINTF(GIC, "copy cpu 0x%x 0x%08x\n", daddr, val);
319 to->writeCpu(ctx, daddr, val);
320}
321
322void
323MuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
324 Addr daddr, size_t size)
325{
326 for (int ctx = 0; ctx < system._numContexts; ++ctx)
327 for (auto a = daddr; a < daddr + size; a += 4)
328 copyDistRegister(from, to, ctx, a);
329}
330
331void
332MuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
333 Addr daddr, size_t size)
334{
335 for (int ctx = 0; ctx < system._numContexts; ++ctx)
336 for (auto a = daddr; a < daddr + size; a += 4)
337 to->writeDistributor(ctx, a, 0xFFFFFFFF);
338}
339
340void
341MuxingKvmGic::copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
342 Addr daddr, size_t size)
343{
344 for (auto a = daddr; a < daddr + size; a += 4)
345 copyDistRegister(from, to, 0, a);
346}
347
348void
349MuxingKvmGic::clearDistRange(BaseGicRegisters* to,
350 Addr daddr, size_t size)
351{
352 for (auto a = daddr; a < daddr + size; a += 4)
353 to->writeDistributor(0, a, 0xFFFFFFFF);
354}
355
356void
357MuxingKvmGic::copyGicState(BaseGicRegisters* from, BaseGicRegisters* to)
358{
359 Addr set, clear;
360 size_t size;
361
362 /// CPU state (GICC_*)
363 // Copy CPU Interface Control Register (CTLR),
364 // Interrupt Priority Mask Register (PMR), and
365 // Binary Point Register (BPR)
366 for (int ctx = 0; ctx < system._numContexts; ++ctx) {
367 copyCpuRegister(from, to, ctx, GICC_CTLR);
368 copyCpuRegister(from, to, ctx, GICC_PMR);
369 copyCpuRegister(from, to, ctx, GICC_BPR);
370 }
371
372
373 /// Distributor state (GICD_*)
374 // Copy Distributor Control Register (CTLR)
375 copyDistRegister(from, to, 0, GICD_CTLR);
376
377 // Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
378 set = Pl390::GICD_ISENABLER.start();
379 clear = Pl390::GICD_ICENABLER.start();
380 size = Pl390::itLines / 8;
381 clearBankedDistRange(to, clear, 4);
382 copyBankedDistRange(from, to, set, 4);
383
384 set += 4, clear += 4, size -= 4;
385 clearDistRange(to, clear, size);
386 copyDistRange(from, to, set, size);
387
388 // Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
389 set = Pl390::GICD_ISPENDR.start();
390 clear = Pl390::GICD_ICPENDR.start();
391 size = Pl390::itLines / 8;
392 clearBankedDistRange(to, clear, 4);
393 copyBankedDistRange(from, to, set, 4);
394
395 set += 4, clear += 4, size -= 4;
396 clearDistRange(to, clear, size);
397 copyDistRange(from, to, set, size);
398
399 // Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
400 set = Pl390::GICD_ISACTIVER.start();
401 clear = Pl390::GICD_ICACTIVER.start();
402 size = Pl390::itLines / 8;
403 clearBankedDistRange(to, clear, 4);
404 copyBankedDistRange(from, to, set, 4);
405
406 set += 4, clear += 4, size -= 4;
407 clearDistRange(to, clear, size);
408 copyDistRange(from, to, set, size);
409
410 // Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
411 set = Pl390::GICD_IPRIORITYR.start();
412 copyBankedDistRange(from, to, set, 32);
413
414 set += 32;
415 size = Pl390::itLines - 32;
416 copyDistRange(from, to, set, size);
417
418 // Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
419 set = Pl390::GICD_ITARGETSR.start() + 32;
420 size = Pl390::itLines - 32;
421 copyDistRange(from, to, set, size);
422
423 // Copy interrupt configuration registers (ICFGRn)
424 set = Pl390::GICD_ICFGR.start();
425 size = Pl390::itLines / 4;
426 copyDistRange(from, to, set, size);
427}
428
429void
430MuxingKvmGic::fromPl390ToKvm()
431{
432 copyGicState(static_cast<Pl390*>(this), kernelGic);
433}
434
435void
436MuxingKvmGic::fromKvmToPl390()
437{
438 copyGicState(kernelGic, static_cast<Pl390*>(this));
439
440 // the values read for the Interrupt Priority Mask Register (PMR)
441 // have been shifted by three bits due to its having been emulated by
442 // a VGIC with only 5 PMR bits in its VMCR register. Presently the
443 // Linux kernel does not repair this inaccuracy, so we correct it here.
444 for (int cpu = 0; cpu < system._numContexts; ++cpu) {
445 cpuPriority[cpu] <<= 3;
446 assert((cpuPriority[cpu] & ~0xff) == 0);
447 }
448}
449
450MuxingKvmGic *
451MuxingKvmGicParams::create()
452{
453 return new MuxingKvmGic(this);
454}
290void
291MuxingKvmGic::copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
292 ContextID ctx, Addr daddr)
293{
294 auto val = from->readDistributor(ctx, daddr);
295 DPRINTF(GIC, "copy dist 0x%x 0x%08x\n", daddr, val);
296 to->writeDistributor(ctx, daddr, val);
297}
298
299void
300MuxingKvmGic::copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
301 ContextID ctx, Addr daddr)
302{
303 auto val = from->readCpu(ctx, daddr);
304 DPRINTF(GIC, "copy cpu 0x%x 0x%08x\n", daddr, val);
305 to->writeCpu(ctx, daddr, val);
306}
307
308void
309MuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
310 Addr daddr, size_t size)
311{
312 for (int ctx = 0; ctx < system._numContexts; ++ctx)
313 for (auto a = daddr; a < daddr + size; a += 4)
314 copyDistRegister(from, to, ctx, a);
315}
316
317void
318MuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
319 Addr daddr, size_t size)
320{
321 for (int ctx = 0; ctx < system._numContexts; ++ctx)
322 for (auto a = daddr; a < daddr + size; a += 4)
323 to->writeDistributor(ctx, a, 0xFFFFFFFF);
324}
325
326void
327MuxingKvmGic::copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
328 Addr daddr, size_t size)
329{
330 for (auto a = daddr; a < daddr + size; a += 4)
331 copyDistRegister(from, to, 0, a);
332}
333
334void
335MuxingKvmGic::clearDistRange(BaseGicRegisters* to,
336 Addr daddr, size_t size)
337{
338 for (auto a = daddr; a < daddr + size; a += 4)
339 to->writeDistributor(0, a, 0xFFFFFFFF);
340}
341
342void
343MuxingKvmGic::copyGicState(BaseGicRegisters* from, BaseGicRegisters* to)
344{
345 Addr set, clear;
346 size_t size;
347
348 /// CPU state (GICC_*)
349 // Copy CPU Interface Control Register (CTLR),
350 // Interrupt Priority Mask Register (PMR), and
351 // Binary Point Register (BPR)
352 for (int ctx = 0; ctx < system._numContexts; ++ctx) {
353 copyCpuRegister(from, to, ctx, GICC_CTLR);
354 copyCpuRegister(from, to, ctx, GICC_PMR);
355 copyCpuRegister(from, to, ctx, GICC_BPR);
356 }
357
358
359 /// Distributor state (GICD_*)
360 // Copy Distributor Control Register (CTLR)
361 copyDistRegister(from, to, 0, GICD_CTLR);
362
363 // Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
364 set = Pl390::GICD_ISENABLER.start();
365 clear = Pl390::GICD_ICENABLER.start();
366 size = Pl390::itLines / 8;
367 clearBankedDistRange(to, clear, 4);
368 copyBankedDistRange(from, to, set, 4);
369
370 set += 4, clear += 4, size -= 4;
371 clearDistRange(to, clear, size);
372 copyDistRange(from, to, set, size);
373
374 // Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
375 set = Pl390::GICD_ISPENDR.start();
376 clear = Pl390::GICD_ICPENDR.start();
377 size = Pl390::itLines / 8;
378 clearBankedDistRange(to, clear, 4);
379 copyBankedDistRange(from, to, set, 4);
380
381 set += 4, clear += 4, size -= 4;
382 clearDistRange(to, clear, size);
383 copyDistRange(from, to, set, size);
384
385 // Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
386 set = Pl390::GICD_ISACTIVER.start();
387 clear = Pl390::GICD_ICACTIVER.start();
388 size = Pl390::itLines / 8;
389 clearBankedDistRange(to, clear, 4);
390 copyBankedDistRange(from, to, set, 4);
391
392 set += 4, clear += 4, size -= 4;
393 clearDistRange(to, clear, size);
394 copyDistRange(from, to, set, size);
395
396 // Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
397 set = Pl390::GICD_IPRIORITYR.start();
398 copyBankedDistRange(from, to, set, 32);
399
400 set += 32;
401 size = Pl390::itLines - 32;
402 copyDistRange(from, to, set, size);
403
404 // Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
405 set = Pl390::GICD_ITARGETSR.start() + 32;
406 size = Pl390::itLines - 32;
407 copyDistRange(from, to, set, size);
408
409 // Copy interrupt configuration registers (ICFGRn)
410 set = Pl390::GICD_ICFGR.start();
411 size = Pl390::itLines / 4;
412 copyDistRange(from, to, set, size);
413}
414
415void
416MuxingKvmGic::fromPl390ToKvm()
417{
418 copyGicState(static_cast<Pl390*>(this), kernelGic);
419}
420
421void
422MuxingKvmGic::fromKvmToPl390()
423{
424 copyGicState(kernelGic, static_cast<Pl390*>(this));
425
426 // the values read for the Interrupt Priority Mask Register (PMR)
427 // have been shifted by three bits due to its having been emulated by
428 // a VGIC with only 5 PMR bits in its VMCR register. Presently the
429 // Linux kernel does not repair this inaccuracy, so we correct it here.
430 for (int cpu = 0; cpu < system._numContexts; ++cpu) {
431 cpuPriority[cpu] <<= 3;
432 assert((cpuPriority[cpu] & ~0xff) == 0);
433 }
434}
435
436MuxingKvmGic *
437MuxingKvmGicParams::create()
438{
439 return new MuxingKvmGic(this);
440}