gem5  v22.1.0.0
gic.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2017, 2021 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 
38 #include "arch/arm/kvm/gic.hh"
39 
40 #include <linux/kvm.h>
41 
42 #include "arch/arm/kvm/base_cpu.hh"
43 #include "arch/arm/regs/misc.hh"
44 #include "debug/GIC.hh"
45 #include "debug/Interrupt.hh"
46 #include "params/MuxingKvmGicV2.hh"
47 
48 namespace gem5
49 {
50 
51 KvmKernelGic::KvmKernelGic(KvmVM &_vm, uint32_t dev, unsigned it_lines)
52  : vm(_vm),
53  kdev(vm.createDevice(dev))
54 {
55  // Tell the VM that we will emulate the GIC in the kernel. This
56  // disables IRQ and FIQ handling in the KVM CPU model.
58 
59  kdev.setAttr<uint32_t>(KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, it_lines);
60 }
61 
63 {
64 }
65 
66 void
67 KvmKernelGic::setSPI(unsigned spi)
68 {
69  setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, true);
70 }
71 
72 void
74 {
75  setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, false);
76 }
77 
78 void
79 KvmKernelGic::setPPI(unsigned vcpu, unsigned ppi)
80 {
81  setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, true);
82 }
83 
84 void
85 KvmKernelGic::clearPPI(unsigned vcpu, unsigned ppi)
86 {
87  setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, false);
88 }
89 
90 void
91 KvmKernelGic::setIntState(unsigned type, unsigned vcpu, unsigned irq,
92  bool high)
93 {
94  const unsigned vcpu_index = vcpu & 0xff;
95  const unsigned vcpu2_index = (vcpu >> 8) & 0xff;
96 
97  static const bool vcpu2_enabled = vm.kvm->capIRQLineLayout2();
98  uint32_t kvm_vcpu = (vcpu_index << KVM_ARM_IRQ_VCPU_SHIFT);
99 
100 #if defined(KVM_ARM_IRQ_VCPU2_SHIFT)
101  if (vcpu2_enabled)
102  kvm_vcpu |= vcpu2_index << KVM_ARM_IRQ_VCPU2_SHIFT;
103 #endif
104 
105  panic_if((!vcpu2_enabled && vcpu2_index) || kvm_vcpu > 0xffff,
106  "VCPU out of range");
107 
108  assert(type <= KVM_ARM_IRQ_TYPE_MASK);
109  assert(irq <= KVM_ARM_IRQ_NUM_MASK);
110  const uint32_t line(
111  kvm_vcpu |
112  (type << KVM_ARM_IRQ_TYPE_SHIFT) |
113  (irq << KVM_ARM_IRQ_NUM_SHIFT));
114 
115  vm.setIRQLine(line, high);
116 }
117 
119  const MuxingKvmGicV2Params &p)
120  : KvmKernelGic(_vm, KVM_DEV_TYPE_ARM_VGIC_V2, p.it_lines),
121  cpuRange(RangeSize(p.cpu_addr, KVM_VGIC_V2_CPU_SIZE)),
122  distRange(RangeSize(p.dist_addr, KVM_VGIC_V2_DIST_SIZE))
123 {
124  kdev.setAttr<uint64_t>(
125  KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, p.dist_addr);
126  kdev.setAttr<uint64_t>(
127  KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, p.cpu_addr);
128 }
129 
130 uint32_t
131 KvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
132 {
133  uint64_t reg;
134 
135  assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
136  const uint64_t attr(
137  ((uint64_t)vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
138  (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
139 
140  kdev.getAttrPtr(group, attr, &reg);
141  return (uint32_t) reg;
142 }
143 
144 void
145 KvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
146  unsigned value)
147 {
148  uint64_t reg = value;
149 
150  assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
151  const uint64_t attr(
152  ((uint64_t)vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
153  (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
154 
155  kdev.setAttrPtr(group, attr, &reg);
156 }
157 
158 uint32_t
160 {
161  auto vcpu = vm.contextIdToVCpuId(ctx);
162  return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
163 }
164 
165 uint32_t
167 {
168  auto vcpu = vm.contextIdToVCpuId(ctx);
169  return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
170 }
171 
172 void
174 {
175  auto vcpu = vm.contextIdToVCpuId(ctx);
176  setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
177 }
178 
179 void
181 {
182  auto vcpu = vm.contextIdToVCpuId(ctx);
183  setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
184 }
185 
186 #ifndef SZ_64K
187 #define SZ_64K 0x00000040
188 #endif
189 
191  const MuxingKvmGicV3Params &p)
192  : KvmKernelGic(_vm, KVM_DEV_TYPE_ARM_VGIC_V3, p.it_lines),
193  redistRange(RangeSize(p.redist_addr, KVM_VGIC_V3_REDIST_SIZE)),
194  distRange(RangeSize(p.dist_addr, KVM_VGIC_V3_DIST_SIZE))
195 {
196  kdev.setAttr<uint64_t>(
197  KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_DIST, p.dist_addr);
198  kdev.setAttr<uint64_t>(
199  KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST, p.redist_addr);
200 }
201 
202 void
204 {
205  kdev.setAttr<uint64_t>(
206  KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, 0);
207 }
208 
209 template <typename Ret>
210 Ret
211 KvmKernelGicV3::getGicReg(unsigned group, unsigned mpidr, unsigned offset)
212 {
213  Ret reg;
214 
215  assert(mpidr <= KVM_DEV_ARM_VGIC_V3_MPIDR_MASK);
216  const uint64_t attr(
217  ((uint64_t)mpidr << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT) |
218  (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
219 
220  kdev.getAttrPtr(group, attr, &reg);
221  return reg;
222 }
223 
224 template <typename Arg>
225 void
226 KvmKernelGicV3::setGicReg(unsigned group, unsigned mpidr, unsigned offset,
227  Arg value)
228 {
229  Arg reg = value;
230 
231  assert(mpidr <= KVM_DEV_ARM_VGIC_V3_MPIDR_MASK);
232  const uint64_t attr(
233  ((uint64_t)mpidr << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT) |
234  (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
235 
236  kdev.setAttrPtr(group, attr, &reg);
237 }
238 
239 uint32_t
241 {
242  return getGicReg<uint32_t>(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, 0, daddr);
243 }
244 
245 uint32_t
246 KvmKernelGicV3::readRedistributor(const ArmISA::Affinity &aff, Addr daddr)
247 {
248  return getGicReg<uint32_t>(KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, aff, daddr);
249 }
250 
251 RegVal
252 KvmKernelGicV3::readCpu(const ArmISA::Affinity &aff,
253  ArmISA::MiscRegIndex misc_reg)
254 {
255  auto sys_reg = ArmISA::encodeAArch64SysReg(misc_reg).packed();
256  return getGicReg<RegVal>(KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, aff, sys_reg);
257 }
258 
259 void
261 {
262  setGicReg<uint32_t>(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, 0, daddr, data);
263 }
264 
265 void
266 KvmKernelGicV3::writeRedistributor(const ArmISA::Affinity &aff, Addr daddr,
267  uint32_t data)
268 {
269  setGicReg<uint32_t>(KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, aff, daddr, data);
270 }
271 
272 void
273 KvmKernelGicV3::writeCpu(const ArmISA::Affinity &aff,
274  ArmISA::MiscRegIndex misc_reg,
275  RegVal data)
276 {
277  auto sys_reg = ArmISA::encodeAArch64SysReg(misc_reg).packed();
278  setGicReg<RegVal>(KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, aff, sys_reg, data);
279 }
280 
281 template <class Types>
283  : SimGic(p),
284  system(*p.system),
285  kernelGic(nullptr),
286  usingKvm(false)
287 {
288  auto vm = system.getKvmVM();
289  if (vm && !p.simulate_gic) {
290  kernelGic = new KvmGic(*vm, p);
291  }
292 }
293 
294 template <class Types>
295 void
297 {
298  SimGic::startup();
299 
300  if (kernelGic) {
301  kernelGic->init();
302 
303  KvmVM *vm = system.getKvmVM();
304  if (vm && vm->validEnvironment()) {
305  usingKvm = true;
306  fromGicToKvm();
307  }
308  }
309 }
310 
311 template <class Types>
314 {
315  if (usingKvm)
316  fromKvmToGic();
317  return SimGic::drain();
318 }
319 
320 template <class Types>
321 void
323 {
324  SimGic::drainResume();
325 
326  KvmVM *vm = system.getKvmVM();
327  bool use_kvm = kernelGic && vm && vm->validEnvironment();
328  if (use_kvm != usingKvm) {
329  // Should only occur due to CPU switches
330  if (use_kvm) // from simulation to KVM emulation
331  fromGicToKvm();
332  // otherwise, drain() already sync'd the state back to the GicV2
333 
334  usingKvm = use_kvm;
335  }
336 }
337 
338 template <class Types>
339 Tick
341 {
342  if (!usingKvm)
343  return SimGic::read(pkt);
344 
345  panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
346 }
347 
348 template <class Types>
349 Tick
351 {
352  if (!usingKvm)
353  return SimGic::write(pkt);
354 
355  panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
356 }
357 
358 template <class Types>
359 void
361 {
362  if (!usingKvm)
363  return SimGic::sendInt(num);
364 
365  DPRINTF(Interrupt, "Set SPI %d\n", num);
366  kernelGic->setSPI(num);
367 }
368 
369 template <class Types>
370 void
372 {
373  if (!usingKvm)
374  return SimGic::clearInt(num);
375 
376  DPRINTF(Interrupt, "Clear SPI %d\n", num);
377  kernelGic->clearSPI(num);
378 }
379 
380 template <class Types>
381 void
382 MuxingKvmGic<Types>::sendPPInt(uint32_t num, uint32_t cpu)
383 {
384  if (!usingKvm)
385  return SimGic::sendPPInt(num, cpu);
386  DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
387  kernelGic->setPPI(cpu, num);
388 }
389 
390 template <class Types>
391 void
392 MuxingKvmGic<Types>::clearPPInt(uint32_t num, uint32_t cpu)
393 {
394  if (!usingKvm)
395  return SimGic::clearPPInt(num, cpu);
396 
397  DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
398  kernelGic->clearPPI(cpu, num);
399 }
400 
401 template <class Types>
402 bool
404 {
405  // During Kvm->Gic state transfer, writes to the Gic will call
406  // updateIntState() which can post an interrupt. Since we're only
407  // using the Gic model for holding state in this circumstance, we
408  // short-circuit this behavior, as the GicV2 is not actually active.
409  return usingKvm;
410 }
411 
412 template <class Types>
413 void
415 {
416  this->copyGicState(static_cast<SimGic*>(this),
417  static_cast<KvmGic*>(kernelGic));
418 }
419 
420 template <class Types>
421 void
423 {
424  this->copyGicState(static_cast<KvmGic*>(kernelGic),
425  static_cast<SimGic*>(this));
426 
427  // the values read for the Interrupt Priority Mask Register (PMR)
428  // have been shifted by three bits due to its having been emulated by
429  // a VGIC with only 5 PMR bits in its VMCR register. Presently the
430  // Linux kernel does not repair this inaccuracy, so we correct it here.
431  if constexpr(std::is_same<SimGic, GicV2>::value) {
432  for (int cpu = 0; cpu < system.threads.size(); ++cpu) {
433  this->cpuPriority[cpu] <<= 3;
434  assert((this->cpuPriority[cpu] & ~0xff) == 0);
435  }
436  }
437 }
438 
439 template class MuxingKvmGic<GicV2Types>;
440 template class MuxingKvmGic<GicV3Types>;
441 
442 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
void getAttrPtr(uint32_t group, uint64_t attr, void *data) const
Definition: device.cc:63
void setAttrPtr(uint32_t group, uint64_t attr, const void *data) const
Definition: device.cc:84
void setAttr(uint32_t group, uint64_t attr, const T &data) const
Get the value of an attribute.
Definition: device.hh:95
uint32_t readCpu(ContextID ctx, Addr daddr) override
Definition: gic.cc:166
void setGicReg(unsigned group, unsigned vcpu, unsigned offset, unsigned value)
Set value of GIC register "from" a cpu.
Definition: gic.cc:145
void writeCpu(ContextID ctx, Addr daddr, uint32_t data) override
Definition: gic.cc:180
uint32_t readDistributor(ContextID ctx, Addr daddr) override
Definition: gic.cc:159
uint32_t getGicReg(unsigned group, unsigned vcpu, unsigned offset)
Get value of GIC register "from" a cpu.
Definition: gic.cc:131
void writeDistributor(ContextID ctx, Addr daddr, uint32_t data) override
Definition: gic.cc:173
KvmKernelGicV2(KvmVM &vm, const MuxingKvmGicV2Params &params)
Instantiate a KVM in-kernel GICv2 model.
Definition: gic.cc:118
RegVal readCpu(const ArmISA::Affinity &aff, ArmISA::MiscRegIndex misc_reg) override
Definition: gic.cc:252
void writeRedistributor(const ArmISA::Affinity &aff, Addr daddr, uint32_t data) override
Definition: gic.cc:266
void init() override
Definition: gic.cc:203
void writeDistributor(Addr daddr, uint32_t data) override
Definition: gic.cc:260
Ret getGicReg(unsigned group, unsigned mpidr, unsigned offset)
Get value of GIC register "from" a cpu.
Definition: gic.cc:211
uint32_t readRedistributor(const ArmISA::Affinity &aff, Addr daddr) override
Definition: gic.cc:246
void writeCpu(const ArmISA::Affinity &aff, ArmISA::MiscRegIndex misc_reg, RegVal data) override
Definition: gic.cc:273
uint32_t readDistributor(Addr daddr) override
Definition: gic.cc:240
void setGicReg(unsigned group, unsigned mpidr, unsigned offset, Arg value)
Set value of GIC register "from" a cpu.
Definition: gic.cc:226
KvmKernelGicV3(KvmVM &vm, const MuxingKvmGicV3Params &params)
Instantiate a KVM in-kernel GICv3 model.
Definition: gic.cc:190
KVM in-kernel GIC abstraction.
Definition: gic.hh:62
void setPPI(unsigned vcpu, unsigned ppi)
Raise a private peripheral interrupt.
Definition: gic.cc:79
void setSPI(unsigned spi)
Raise a shared peripheral interrupt.
Definition: gic.cc:67
KvmKernelGic(KvmVM &vm, uint32_t dev, unsigned it_lines)
Instantiate a KVM in-kernel GIC model.
Definition: gic.cc:51
void clearPPI(unsigned vcpu, unsigned ppi)
Clear a private peripheral interrupt.
Definition: gic.cc:85
KvmDevice kdev
Kernel interface to the GIC.
Definition: gic.hh:137
void setIntState(unsigned type, unsigned vcpu, unsigned irq, bool high)
Update the kernel's VGIC interrupt state.
Definition: gic.cc:91
void clearSPI(unsigned spi)
Clear a shared peripheral interrupt.
Definition: gic.cc:73
KvmVM & vm
KVM VM in the parent system.
Definition: gic.hh:134
virtual ~KvmKernelGic()
Definition: gic.cc:62
KVM VM container.
Definition: vm.hh:302
long contextIdToVCpuId(ContextID ctx) const
Get the VCPUID for a given context.
Definition: vm.cc:566
Kvm * kvm
Global KVM interface.
Definition: vm.hh:421
bool capIRQLineLayout2() const
Support for ARM IRQ line layout 2.
Definition: vm.cc:208
System & system
System this interrupt controller belongs to.
Definition: gic.hh:295
void sendInt(uint32_t num) override
Definition: gic.cc:360
Tick write(PacketPtr pkt) override
Definition: gic.cc:350
KvmKernelGic * kernelGic
Kernel GIC device.
Definition: gic.hh:298
MuxingKvmGic(const Params &p)
Definition: gic.cc:282
typename Types::KvmGic KvmGic
Definition: gic.hh:269
bool blockIntUpdate() const override
Definition: gic.cc:403
void fromKvmToGic()
Definition: gic.cc:422
void startup() override
Definition: gic.cc:296
Tick read(PacketPtr pkt) override
Definition: gic.cc:340
DrainState drain() override
Definition: gic.cc:313
void clearInt(uint32_t num) override
Definition: gic.cc:371
void clearPPInt(uint32_t num, uint32_t cpu) override
Definition: gic.cc:392
void drainResume() override
Definition: gic.cc:322
typename Types::Params Params
Definition: gic.hh:270
typename Types::SimGic SimGic
Definition: gic.hh:268
void fromGicToKvm()
Multiplexing implementation.
Definition: gic.cc:414
void sendPPInt(uint32_t num, uint32_t cpu) override
Definition: gic.cc:382
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
KvmVM * getKvmVM() const
Get a pointer to the Kernel Virtual Machine (KVM) SimObject, if present.
Definition: system.hh:336
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
Definition: vm.cc:525
void enableKernelIRQChip()
Tell the VM and VCPUs to use an in-kernel IRQ chip for interrupt delivery.
Definition: vm.hh:372
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:815
DrainState
Object drain/handover states.
Definition: drain.hh:75
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
MiscRegNum64 encodeAArch64SysReg(MiscRegIndex misc_reg)
Definition: misc.cc:2001
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 0 > vm
Definition: misc_types.hh:291
Bitfield< 1 > irq
Definition: misc_types.hh:337
MiscRegIndex
Definition: misc.hh:64
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 5, 3 > reg
Definition: types.hh:92
Bitfield< 15 > system
Definition: misc.hh:1004
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
high
Definition: intmath.hh:176
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
uint64_t Tick
Tick count type.
Definition: types.hh:58
int ContextID
Globally unique thread context ID.
Definition: types.hh:239
uint64_t RegVal
Definition: types.hh:173
uint32_t packed() const
Definition: misc.hh:1661

Generated on Wed Dec 21 2022 10:22:24 for gem5 by doxygen 1.9.1