gem5  v22.1.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
arm_cpu.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, 2020 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/arm_cpu.hh"
39 
40 #include <linux/kvm.h>
41 
42 #include <algorithm>
43 #include <cerrno>
44 #include <memory>
45 #include <set>
46 
47 #include "arch/arm/interrupts.hh"
48 #include "arch/arm/regs/int.hh"
49 #include "arch/arm/regs/misc.hh"
50 #include "cpu/kvm/base.hh"
51 #include "debug/Kvm.hh"
52 #include "debug/KvmContext.hh"
53 #include "debug/KvmInt.hh"
54 #include "sim/pseudo_inst.hh"
55 
56 namespace gem5
57 {
58 
59 using namespace ArmISA;
60 
61 namespace
62 {
63 
64 constexpr uint64_t
65 extractField(uint64_t val, uint64_t mask, size_t shift)
66 {
67  return (val & mask) >> shift;
68 }
69 
70 constexpr bool
71 regIsArm(uint64_t id)
72 {
73  return (id & KVM_REG_ARCH_MASK) == KVM_REG_ARM;
74 }
75 
76 constexpr bool
77 regIs32Bit(uint64_t id)
78 {
79  return (id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32;
80 }
81 
82 constexpr bool
83 regIs64Bit(uint64_t id)
84 {
85  return (id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64;
86 }
87 
88 constexpr bool
89 regIsCp(uint64_t id, uint64_t cp)
90 {
91  return (id & KVM_REG_ARM_COPROC_MASK) == cp;
92 }
93 
94 constexpr bool
95 regIsCore(uint64_t id)
96 {
97  return regIsCp(id, KVM_REG_ARM_CORE);
98 }
99 
100 constexpr bool
101 regIsVfp(uint64_t id)
102 {
103  return regIsCp(id, KVM_REG_ARM_VFP);
104 }
105 
106 constexpr uint64_t
107 regVfpReg(uint64_t id)
108 {
109  return id & KVM_REG_ARM_VFP_MASK;
110 }
111 
112 // HACK: These aren't really defined in any of the headers, so we'll
113 // assume some reasonable values for now.
114 constexpr bool
115 regIsVfpReg(uint64_t id)
116 {
117  return regVfpReg(id) < 0x100;
118 }
119 constexpr bool
120 regIsVfpCtrl(uint64_t id)
121 {
122  return regVfpReg(id) >= 0x100;
123 }
124 
125 constexpr bool
126 regIsDemux(uint64_t id)
127 {
128  return regIsCp(id, KVM_REG_ARM_DEMUX);
129 }
130 
131 
132 // There is no constant in the kernel headers defining the mask to use
133 // to get the core register index. We'll just do what they do
134 // internally.
135 constexpr uint64_t
136 regCoreIdx(uint64_t id)
137 {
138  return ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
139 }
140 
141 constexpr uint64_t
142 regCp(uint64_t id)
143 {
144  return extractField(id, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_SHIFT);
145 }
146 
147 constexpr uint64_t
148 regCrn(uint64_t id)
149 {
150  return extractField(id, KVM_REG_ARM_32_CRN_MASK, KVM_REG_ARM_32_CRN_SHIFT);
151 }
152 
153 constexpr uint64_t
154 regOpc1(uint64_t id)
155 {
156  return extractField(id, KVM_REG_ARM_OPC1_MASK, KVM_REG_ARM_OPC1_SHIFT);
157 }
158 
159 constexpr uint64_t
160 regCrm(uint64_t id)
161 {
162  return extractField(id, KVM_REG_ARM_CRM_MASK, KVM_REG_ARM_CRM_SHIFT);
163 }
164 
165 constexpr uint64_t
166 regOpc2(uint64_t id)
167 {
168  return extractField(id, KVM_REG_ARM_32_OPC2_MASK,
169  KVM_REG_ARM_32_OPC2_SHIFT);
170 }
171 
172 constexpr uint64_t
173 regCp32(uint64_t cpnum, uint64_t crn, uint64_t opc1, uint64_t crm,
174  uint64_t opc2)
175 {
176  return KVM_REG_ARM | KVM_REG_SIZE_U32 |
177  (cpnum << KVM_REG_ARM_COPROC_SHIFT) |
178  (crn << KVM_REG_ARM_32_CRN_SHIFT) |
179  (opc1 << KVM_REG_ARM_OPC1_SHIFT) |
180  (crm << KVM_REG_ARM_CRM_SHIFT) |
181  (opc2 << KVM_REG_ARM_32_OPC2_SHIFT);
182 }
183 
184 constexpr uint64_t
185 regCp64(uint64_t cpnum, uint64_t opc1, uint64_t crm)
186 {
187  return KVM_REG_ARM | KVM_REG_SIZE_U64 |
188  (cpnum << KVM_REG_ARM_COPROC_SHIFT) |
189  (opc1 << KVM_REG_ARM_OPC1_SHIFT) |
190  (crm << KVM_REG_ARM_CRM_SHIFT);
191 }
192 
193 constexpr KvmIntRegInfo
194 regCore32(off_t offset, RegIndex idx, const char *name)
195 {
196  return { KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE | offset,
197  idx, name };
198 }
199 
200 constexpr uint64_t
201 regVfp32(uint64_t regno)
202 {
203  return KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | regno;
204 }
205 
206 constexpr uint64_t
207 regVfp64(uint64_t regno)
208 {
209  return KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | regno;
210 }
211 
212 constexpr uint64_t
213 regDemux32(uint64_t dmxid, uint64_t val)
214 {
215  return KVM_REG_ARM | KVM_REG_SIZE_U32 | dmxid | val;
216 }
217 
218 constexpr uint64_t
219 interruptId(uint64_t type, uint64_t vcpu, uint64_t irq)
220 {
221  return (type << KVM_ARM_IRQ_TYPE_SHIFT) |
222  (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) |
223  (irq << KVM_ARM_IRQ_NUM_SHIFT);
224 }
225 
226 constexpr uint64_t
227 interruptVcpuIrq(uint64_t vcpu)
228 {
229  return interruptId(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ);
230 }
231 
232 constexpr uint64_t
233 interruptVcpuFiq(uint64_t vcpu)
234 {
235  return interruptId(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ);
236 }
237 
238 } // anonymous namespace
239 
240 // Some of the co-processor registers are invariants and must have the
241 // same value on both the host and the guest. We need to keep a list
242 // of these to prevent gem5 from fiddling with them on the guest.
243 static uint64_t invariant_reg_vector[] = {
244  regCp32(15, 0, 0, 0, 0), // MIDR
245  regCp32(15, 0, 0, 0, 1), // CTR
246  regCp32(15, 0, 0, 0, 2), // TCMTR
247  regCp32(15, 0, 0, 0, 3), // TLBTR
248  regCp32(15, 0, 0, 0, 6), // REVIDR
249 
250  regCp32(15, 0, 0, 1, 0), // ID_PFR0
251  regCp32(15, 0, 0, 1, 1), // ID_PFR1
252  regCp32(15, 0, 0, 1, 2), // ID_DFR0
253  regCp32(15, 0, 0, 1, 3), // ID_AFR0
254  regCp32(15, 0, 0, 1, 4), // ID_MMFR0
255  regCp32(15, 0, 0, 1, 5), // ID_MMFR1
256  regCp32(15, 0, 0, 1, 6), // ID_MMFR2
257  regCp32(15, 0, 0, 1, 7), // ID_MMFR3
258 
259  regCp32(15, 0, 0, 2, 0), // ID_ISAR0
260  regCp32(15, 0, 0, 2, 1), // ID_ISAR1
261  regCp32(15, 0, 0, 2, 2), // ID_ISAR2
262  regCp32(15, 0, 0, 2, 3), // ID_ISAR3
263  regCp32(15, 0, 0, 2, 4), // ID_ISAR4
264  regCp32(15, 0, 0, 2, 5), // ID_ISAR5
265  regCp32(15, 0, 0, 2, 6), // ID_MMFR4
266  regCp32(15, 0, 0, 2, 7), // ID_ISAR6
267 
268  regCp32(15, 0, 1, 0, 0), // CSSIDR
269  regCp32(15, 0, 1, 0, 1), // CLIDR
270  regCp32(15, 0, 1, 0, 7), // AIDR
271 
272  regVfp32(KVM_REG_ARM_VFP_MVFR0),
273  regVfp32(KVM_REG_ARM_VFP_MVFR1),
274  regVfp32(KVM_REG_ARM_VFP_FPSID),
275 
276  regDemux32(KVM_REG_ARM_DEMUX_ID_CCSIDR, 0),
277 };
278 
279 const static uint64_t KVM_REG64_TTBR0(regCp64(15, 0, 2));
280 const static uint64_t KVM_REG64_TTBR1(regCp64(15, 1, 2));
281 
282 
283 const std::set<uint64_t> ArmKvmCPU::invariant_regs(
284  std::begin(invariant_reg_vector), std::end(invariant_reg_vector));
285 
286 
288  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r0), int_reg::R0, "R0"),
289  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r1), int_reg::R1, "R1"),
290  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r2), int_reg::R2, "R2"),
291  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r3), int_reg::R3, "R3"),
292  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r4), int_reg::R4, "R4"),
293  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r5), int_reg::R5, "R5"),
294  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r6), int_reg::R6, "R6"),
295  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r7), int_reg::R7, "R7"),
296  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r8), int_reg::R8, "R8"),
297  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r9), int_reg::R9, "R9"),
298  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r10), int_reg::R10, "R10"),
299  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_fp), int_reg::R11, "R11"),
300  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_ip), int_reg::R12, "R12"),
301  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_sp), int_reg::R13, "R13(USR)"),
302  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_lr), int_reg::R14, "R14(USR)"),
303 
304  regCore32(KVM_REG_ARM_CORE_REG(svc_regs[0]), int_reg::SpSvc, "R13(SVC)"),
305  regCore32(KVM_REG_ARM_CORE_REG(svc_regs[1]), int_reg::LrSvc, "R14(SVC)"),
306 
307  regCore32(KVM_REG_ARM_CORE_REG(abt_regs[0]), int_reg::SpAbt, "R13(ABT)"),
308  regCore32(KVM_REG_ARM_CORE_REG(abt_regs[1]), int_reg::LrAbt, "R14(ABT)"),
309 
310  regCore32(KVM_REG_ARM_CORE_REG(und_regs[0]), int_reg::SpUnd, "R13(UND)"),
311  regCore32(KVM_REG_ARM_CORE_REG(und_regs[1]), int_reg::LrUnd, "R14(UND)"),
312 
313  regCore32(KVM_REG_ARM_CORE_REG(irq_regs[0]), int_reg::SpIrq, "R13(IRQ)"),
314  regCore32(KVM_REG_ARM_CORE_REG(irq_regs[1]), int_reg::LrIrq, "R14(IRQ)"),
315 
316 
317  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[0]), int_reg::R8Fiq, "R8(FIQ)"),
318  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[1]), int_reg::R9Fiq, "R9(FIQ)"),
319  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[2]), int_reg::R10Fiq, "R10(FIQ)"),
320  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[3]), int_reg::R11Fiq, "R11(FIQ)"),
321  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[4]), int_reg::R12Fiq, "R12(FIQ)"),
322  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[5]), int_reg::R13Fiq, "R13(FIQ)"),
323  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[6]), int_reg::R14Fiq, "R14(FIQ)"),
324  { 0, int_reg::NumRegs, NULL }
325 };
326 
327 ArmKvmCPU::KvmCoreMiscRegInfo ArmKvmCPU::kvmCoreMiscRegs[] = {
328  regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr), MISCREG_CPSR, "CPSR"),
329  regCore32(KVM_REG_ARM_CORE_REG(svc_regs[2]), MISCREG_SPSR_SVC,
330  "SPSR(SVC)"),
331  regCore32(KVM_REG_ARM_CORE_REG(abt_regs[2]), MISCREG_SPSR_ABT,
332  "SPSR(ABT)"),
333  regCore32(KVM_REG_ARM_CORE_REG(und_regs[2]), MISCREG_SPSR_UND,
334  "SPSR(UND)"),
335  regCore32(KVM_REG_ARM_CORE_REG(irq_regs[2]), MISCREG_SPSR_IRQ,
336  "SPSR(IRQ)"),
337  regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[2]), MISCREG_SPSR_FIQ,
338  "SPSR(FIQ)"),
339  { 0, NUM_MISCREGS }
340 };
341 
342 ArmKvmCPU::ArmKvmCPU(const ArmKvmCPUParams &params)
343  : BaseKvmCPU(params),
344  irqAsserted(false), fiqAsserted(false)
345 {
346 }
347 
349 {
350 }
351 
352 void
354 {
356 
357  /* TODO: This needs to be moved when we start to support VMs with
358  * multiple threads since kvmArmVCpuInit requires that all CPUs in
359  * the VM have been created.
360  */
361  /* TODO: The CPU type needs to be configurable once KVM on ARM
362  * starts to support more CPUs.
363  */
364  kvmArmVCpuInit(KVM_ARM_TARGET_CORTEX_A15);
365 }
366 
367 Tick
369 {
370  auto interrupt = static_cast<ArmISA::Interrupts *>(interrupts[0]);
371  const bool simFIQ = interrupt->checkRaw(INT_FIQ);
372  const bool simIRQ = interrupt->checkRaw(INT_IRQ);
373 
374  if (fiqAsserted != simFIQ) {
375  fiqAsserted = simFIQ;
376  DPRINTF(KvmInt, "KVM: Update FIQ state: %i\n", simFIQ);
377  vm->setIRQLine(interruptVcpuFiq(vcpuID), simFIQ);
378  }
379  if (irqAsserted != simIRQ) {
380  irqAsserted = simIRQ;
381  DPRINTF(KvmInt, "KVM: Update IRQ state: %i\n", simIRQ);
382  vm->setIRQLine(interruptVcpuIrq(vcpuID), simIRQ);
383  }
384 
385  return BaseKvmCPU::kvmRun(ticks);
386 }
387 
388 void
390 {
393 }
394 
395 void
397 {
398  DPRINTF(KvmContext, "Updating KVM state...\n");
399 
402 }
403 
404 void
406 {
407  DPRINTF(KvmContext, "Updating gem5 state...\n");
408 
411 }
412 
415 {
416  if (_regIndexList.size() == 0) {
417  std::unique_ptr<struct kvm_reg_list, void(*)(void *p)>
418  regs(nullptr, [](void *p) { operator delete(p); });
419  uint64_t i = 1;
420 
421  do {
422  i <<= 1;
423  regs.reset((struct kvm_reg_list *)
424  operator new(sizeof(struct kvm_reg_list) +
425  i * sizeof(uint64_t)));
426  regs->n = i;
427  } while (!getRegList(*regs));
428  _regIndexList.assign(regs->reg,
429  regs->reg + regs->n);
430  }
431 
432  return _regIndexList;
433 }
434 
435 void
437 {
438  struct kvm_vcpu_init init;
439 
440  memset(&init, 0, sizeof(init));
441 
442  init.target = target;
443 
445 }
446 
447 void
448 ArmKvmCPU::kvmArmVCpuInit(const struct kvm_vcpu_init &init)
449 {
450  if (ioctl(KVM_ARM_VCPU_INIT, (void *)&init) == -1)
451  panic("KVM: Failed to initialize vCPU\n");
452 }
453 
455 ArmKvmCPU::decodeCoProcReg(uint64_t id) const
456 {
457  const unsigned cp = regCp(id);
458  const bool is_reg32 = regIs32Bit(id);
459  const bool is_reg64 = regIs64Bit(id);
460 
461  // CP numbers larger than 15 are reserved for KVM extensions
462  if (cp > 15)
463  return NUM_MISCREGS;
464 
465  const unsigned crm = regCrm(id);
466  const unsigned crn = regCrn(id);
467  const unsigned opc1 = regOpc1(id);
468  const unsigned opc2 = regOpc2(id);
469 
470  if (is_reg32) {
471  switch (cp) {
472  case 14:
473  return decodeCP14Reg(crn, opc1, crm, opc2);
474 
475  case 15:
476  return decodeCP15Reg(crn, opc1, crm, opc2);
477 
478  default:
479  return NUM_MISCREGS;
480  }
481  } else if (is_reg64) {
482  return NUM_MISCREGS;
483  } else {
484  warn("Unhandled register length, register (0x%x) ignored.\n");
485  return NUM_MISCREGS;
486  }
487 }
488 
490 ArmKvmCPU::decodeVFPCtrlReg(uint64_t id) const
491 {
492  if (!regIsArm(id) || !regIsVfp(id) || !regIsVfpCtrl(id))
493  return NUM_MISCREGS;
494 
495  const unsigned vfp_reg = regVfpReg(id);
496  switch (vfp_reg) {
497  case KVM_REG_ARM_VFP_FPSID: return MISCREG_FPSID;
498  case KVM_REG_ARM_VFP_FPSCR: return MISCREG_FPSCR;
499  case KVM_REG_ARM_VFP_MVFR0: return MISCREG_MVFR0;
500  case KVM_REG_ARM_VFP_MVFR1: return MISCREG_MVFR1;
501  case KVM_REG_ARM_VFP_FPEXC: return MISCREG_FPEXC;
502 
503  case KVM_REG_ARM_VFP_FPINST:
504  case KVM_REG_ARM_VFP_FPINST2:
505  warn_once("KVM: FPINST not implemented.\n");
506  return NUM_MISCREGS;
507 
508  default:
509  return NUM_MISCREGS;
510  }
511 }
512 
513 bool
515 {
516  /* Mask away the value field from multiplexed registers, we assume
517  * that entire groups of multiplexed registers can be treated as
518  * invariant. */
519  if (regIsArm(id) && regIsDemux(id))
520  id &= ~KVM_REG_ARM_DEMUX_VAL_MASK;
521 
522  return invariant_regs.find(id) != invariant_regs.end();
523 }
524 
525 bool
526 ArmKvmCPU::getRegList(struct kvm_reg_list &regs) const
527 {
528  if (ioctl(KVM_GET_REG_LIST, (void *)&regs) == -1) {
529  if (errno == E2BIG) {
530  return false;
531  } else {
532  panic("KVM: Failed to get vCPU register list (errno: %i)\n",
533  errno);
534  }
535  } else {
536  return true;
537  }
538 }
539 
540 void
542 {
543  /* Print core registers */
544  uint32_t pc = getOneRegU32(REG_CORE32(usr_regs.ARM_pc));
545  inform("PC: 0x%x\n", pc);
546 
547  for (const KvmIntRegInfo *ri(kvmIntRegs);
548  ri->idx != int_reg::NumRegs; ++ri) {
549 
550  uint32_t value(getOneRegU32(ri->id));
551  inform("%s: 0x%x\n", ri->name, value);
552  }
553 
555  ri->idx != NUM_MISCREGS; ++ri) {
556 
557  uint32_t value(getOneRegU32(ri->id));
558  inform("%s: 0x%x\n", miscRegName[ri->idx], value);
559  }
560 }
561 
562 void
564 {
565  /* Print co-processor registers */
566  const RegIndexVector &reg_ids = getRegList();
567  for (RegIndexVector::const_iterator it(reg_ids.begin());
568  it != reg_ids.end(); ++it) {
569  uint64_t id = *it;
570 
571  if (regIsArm(id) && regCp(id) <= 15) {
572  dumpKvmStateCoProc(id);
573  } else if (regIsArm(id) && regIsVfp(id)) {
574  dumpKvmStateVFP(id);
575  } else if (regIsArm(id) && regIsDemux(id)) {
576  switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
577  case KVM_REG_ARM_DEMUX_ID_CCSIDR:
578  inform("CCSIDR [0x%x]: %s\n",
579  extractField(id, KVM_REG_ARM_DEMUX_VAL_MASK,
580  KVM_REG_ARM_DEMUX_VAL_SHIFT),
581  getAndFormatOneReg(id));
582  break;
583  default:
584  inform("DEMUX [0x%x, 0x%x]: %s\n",
585  extractField(id, KVM_REG_ARM_DEMUX_ID_MASK,
586  KVM_REG_ARM_DEMUX_ID_SHIFT),
587  extractField(id, KVM_REG_ARM_DEMUX_VAL_MASK,
588  KVM_REG_ARM_DEMUX_VAL_SHIFT),
589  getAndFormatOneReg(id));
590  break;
591  }
592  } else if (!regIsCore(id)) {
593  inform("0x%x: %s\n", id, getAndFormatOneReg(id));
594  }
595  }
596 }
597 
598 void
600 {
601  assert(regIsArm(id));
602  assert(regCp(id) <= 15);
603 
604  if (regIs32Bit(id)) {
605  // 32-bit co-proc registers
606  MiscRegIndex idx = decodeCoProcReg(id);
607  uint32_t value = getOneRegU32(id);
608 
609  if (idx != NUM_MISCREGS &&
610  !(idx >= MISCREG_CP15_UNIMP_START && idx < MISCREG_CP15_END)) {
611  const char *name = miscRegName[idx];
612  const unsigned m5_ne = tc->readMiscRegNoEffect(idx);
613  const unsigned m5_e = tc->readMiscReg(idx);
614  inform("CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: "
615  "[%s]: 0x%x/0x%x\n",
616  regCp(id), regCrn(id), regOpc1(id), regCrm(id),
617  regOpc2(id), isInvariantReg(id),
618  name, value, m5_e);
619  if (m5_e != m5_ne) {
620  inform("readMiscReg: %x, readMiscRegNoEffect: %x\n",
621  m5_e, m5_ne);
622  }
623  } else {
624  const char *name = idx != NUM_MISCREGS ? miscRegName[idx] : "-";
625  inform("CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: "
626  "[%s]: 0x%x\n",
627  regCp(id), regCrn(id), regOpc1(id), regCrm(id),
628  regOpc2(id), isInvariantReg(id), name, value);
629  }
630  } else {
631  inform("CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i "
632  "len: 0x%x]: %s\n",
633  regCp(id), regCrn(id), regOpc1(id), regCrm(id),
634  regOpc2(id), isInvariantReg(id),
635  extractField(id, KVM_REG_SIZE_MASK, KVM_REG_SIZE_SHIFT),
636  getAndFormatOneReg(id));
637  }
638 }
639 
640 void
642 {
643  assert(regIsArm(id));
644  assert(regIsVfp(id));
645 
646  if (regIsVfpReg(id)) {
647  const unsigned idx = id & KVM_REG_ARM_VFP_MASK;
648  inform("VFP reg %i: %s", idx, getAndFormatOneReg(id));
649  } else if (regIsVfpCtrl(id)) {
650  MiscRegIndex idx = decodeVFPCtrlReg(id);
651  if (idx != NUM_MISCREGS) {
652  inform("VFP [%s]: %s", miscRegName[idx], getAndFormatOneReg(id));
653  } else {
654  inform("VFP [0x%x]: %s", id, getAndFormatOneReg(id));
655  }
656  } else {
657  inform("VFP [0x%x]: %s", id, getAndFormatOneReg(id));
658  }
659 }
660 
661 void
663 {
664  for (const KvmIntRegInfo *ri(kvmIntRegs);
665  ri->idx != init_reg::NumRegs; ++ri) {
666 
667  uint64_t value = tc->getReg(flatIntRegClass[ri->idx]);
668  DPRINTF(KvmContext, "kvm(%s) := 0x%x\n", ri->name, value);
669  setOneReg(ri->id, value);
670  }
671 
672  DPRINTF(KvmContext, "kvm(PC) := 0x%x\n", tc->pcState().instAddr());
673  setOneReg(REG_CORE32(usr_regs.ARM_pc), tc->pcState().instAddr());
674 
676  ri->idx != NUM_MISCREGS; ++ri) {
677 
678  uint64_t value = tc->readMiscReg(ri->idx);
679  DPRINTF(KvmContext, "kvm(%s) := 0x%x\n", ri->name, value);
680  setOneReg(ri->id, value);
681  }
682 
683  if (debug::KvmContext)
685 }
686 
687 void
689 {
690  static bool warned = false; // We can't use warn_once since we want
691  // to show /all/ registers
692 
693  const RegIndexVector &regs = getRegList();
694 
695  for (RegIndexVector::const_iterator it(regs.begin());
696  it != regs.end();
697  ++it) {
698 
699  if (!regIsArm(*it)) {
700  if (!warned)
701  warn("Skipping non-ARM register: 0x%x\n", *it);
702  } else if (isInvariantReg(*it)) {
703  DPRINTF(Kvm, "Skipping invariant register: 0x%x\n", *it);
704  } else if (regIsCore(*it)) {
705  // Core registers are handled in updateKvmStateCore
706  continue;
707  } else if (regCp(*it) <= 15) {
708  updateKvmStateCoProc(*it, !warned);
709  } else if (regIsVfp(*it)) {
710  updateKvmStateVFP(*it, !warned);
711  } else {
712  if (!warned) {
713  warn("Skipping register with unknown CP (%i) id: 0x%x\n",
714  regCp(*it), *it);
715  }
716  }
717 
718  }
719 
720  warned = true;
721  if (debug::KvmContext)
723 }
724 
725 void
726 ArmKvmCPU::updateKvmStateCoProc(uint64_t id, bool show_warnings)
727 {
729 
730  assert(regIsArm(id));
731  assert(regCp(id) <= 15);
732 
733  if (id == KVM_REG64_TTBR0 || id == KVM_REG64_TTBR1) {
734  // HACK HACK HACK: Workaround for 64-bit TTBRx
736  if (show_warnings)
737  hack("KVM: 64-bit TTBBRx workaround\n");
738  }
739 
740  if (reg == NUM_MISCREGS) {
741  if (show_warnings) {
742  warn("KVM: Ignoring unknown KVM co-processor register (0x%.8x):\n",
743  id);
744  warn("\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
745  " opc2: %i]\n",
746  id, regCp(id), regIs64Bit(id), regCrn(id),
747  regOpc1(id), regCrm(id), regOpc2(id));
748  }
749  } else if (reg >= MISCREG_CP15_UNIMP_START && reg < MISCREG_CP15_END) {
750  if (show_warnings)
751  warn("KVM: Co-processor reg. %s not implemented by gem5.\n",
752  miscRegName[reg]);
753  } else {
755  }
756 }
757 
758 
759 void
760 ArmKvmCPU::updateKvmStateVFP(uint64_t id, bool show_warnings)
761 {
762  assert(regIsArm(id));
763  assert(regIsVfp(id));
764 
765  if (regIsVfpReg(id)) {
766  if (!regIs64Bit(id)) {
767  if (show_warnings)
768  warn("Unexpected VFP register length (reg: 0x%x).\n", id);
769  return;
770  }
771  const unsigned idx = id & KVM_REG_ARM_VFP_MASK;
772  const unsigned idx_base = idx << 1;
773  const unsigned idx_hi = idx_base + 1;
774  const unsigned idx_lo = idx_base + 0;
775  uint64_t value = (tc->getReg(floatRegClass[idx_hi]) << 32) |
776  tc->getReg(floatRegClass[idx_lo]);
777 
778  setOneReg(id, value);
779  } else if (regIsVfpCtrl(id)) {
780  MiscRegIndex idx = decodeVFPCtrlReg(id);
781  if (idx == NUM_MISCREGS) {
782  if (show_warnings)
783  warn("Unhandled VFP control register: 0x%x\n", id);
784  return;
785  }
786  if (!regIs32Bit(id)) {
787  if (show_warnings)
788  warn("Ignoring VFP control register (%s) with "
789  "unexpected size.\n",
790  miscRegName[idx]);
791  return;
792  }
793  setOneReg(id, (uint32_t)tc->readMiscReg(idx));
794  } else {
795  if (show_warnings)
796  warn("Unhandled VFP register: 0x%x\n", id);
797  }
798 }
799 
800 void
802 {
803  for (const KvmIntRegInfo *ri(kvmIntRegs);
804  ri->idx != int_reg::NumRegs; ++ri) {
805 
806  tc->setReg(intRegClass[ri->idx], getOneRegU32(ri->id));
807  }
808 
810  ri->idx != NUM_MISCREGS; ++ri) {
811 
812  tc->setMiscRegNoEffect(ri->idx, getOneRegU32(ri->id));
813  }
814 
815  /* We want the simulator to execute all side-effects of the CPSR
816  * update since this updates PC state and register maps.
817  */
819 
820  // We update the PC state after we have updated the CPSR the
821  // contents of the CPSR affects how the npc is updated.
822  PCState pc = tc->pcState().as<PCState>();
823  pc.set(getOneRegU32(REG_CORE32(usr_regs.ARM_pc)));
824  tc->pcState(pc);
825 
826  if (debug::KvmContext)
828 }
829 
830 void
832 {
833  static bool warned(false); // We can't use warn_once since we want
834  // to show /all/ registers
835 
836  const RegIndexVector &reg_ids = getRegList();
837  for (RegIndexVector::const_iterator it(reg_ids.begin());
838  it != reg_ids.end(); ++it) {
839 
840  if (!regIsArm(*it)) {
841  if (!warned)
842  warn("Skipping non-ARM register: 0x%x\n", *it);
843  } else if (regIsCore(*it)) {
844  // Core registers are handled in updateKvmStateCore
845  } else if (regCp(*it) <= 15) {
846  updateTCStateCoProc(*it, !warned);
847  } else if (regIsVfp(*it)) {
848  updateTCStateVFP(*it, !warned);
849  } else {
850  if (!warned) {
851  warn("Skipping register with unknown CP (%i) id: 0x%x\n",
852  regCp(*it), *it);
853  }
854  }
855  }
856 
857  warned = true;
858 
859  if (debug::KvmContext)
861 }
862 
863 void
864 ArmKvmCPU::updateTCStateCoProc(uint64_t id, bool show_warnings)
865 {
867 
868  assert(regIsArm(id));
869  assert(regCp(id) <= 15);
870 
871  if (id == KVM_REG64_TTBR0 || id == KVM_REG64_TTBR1) {
872  // HACK HACK HACK: We don't currently support 64-bit TTBR0/TTBR1
873  hack_once("KVM: 64-bit TTBRx workaround\n");
876  (uint32_t)(getOneRegU64(id) & 0xFFFFFFFF));
877  } else if (reg == MISCREG_TTBCR) {
878  uint32_t value = getOneRegU64(id);
879  if (value & 0x80000000)
880  panic("KVM: Guest tried to enable LPAE.\n");
881  tc->setMiscRegNoEffect(reg, value);
882  } else if (reg == NUM_MISCREGS) {
883  if (show_warnings) {
884  warn("KVM: Ignoring unknown KVM co-processor register:\n", id);
885  warn("\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
886  " opc2: %i]\n",
887  id, regCp(id), regIs64Bit(id), regCrn(id),
888  regOpc1(id), regCrm(id), regOpc2(id));
889  }
890  } else if (reg >= MISCREG_CP15_UNIMP_START && reg < MISCREG_CP15_END) {
891  if (show_warnings)
892  warn_once("KVM: Co-processor reg. %s not implemented by gem5.\n",
893  miscRegName[reg]);
894  } else {
896  }
897 }
898 
899 void
900 ArmKvmCPU::updateTCStateVFP(uint64_t id, bool show_warnings)
901 {
902  assert(regIsArm(id));
903  assert(regIsVfp(id));
904 
905  if (regIsVfpReg(id)) {
906  if (!regIs64Bit(id)) {
907  if (show_warnings)
908  warn("Unexpected VFP register length (reg: 0x%x).\n", id);
909  return;
910  }
911  const unsigned idx = id & KVM_REG_ARM_VFP_MASK;
912  const unsigned idx_base = idx << 1;
913  const unsigned idx_hi = idx_base + 1;
914  const unsigned idx_lo = idx_base + 0;
915  uint64_t value = getOneRegU64(id);
916 
917  tc->setReg(floatRegClass[idx_hi], (value >> 32) & 0xFFFFFFFF);
918  tc->setReg(floatRegClass[idx_lo], value & 0xFFFFFFFF);
919  } else if (regIsVfpCtrl(id)) {
920  MiscRegIndex idx = decodeVFPCtrlReg(id);
921  if (idx == NUM_MISCREGS) {
922  if (show_warnings)
923  warn("Unhandled VFP control register: 0x%x\n", id);
924  return;
925  }
926  if (!regIs32Bit(id)) {
927  if (show_warnings)
928  warn("Ignoring VFP control register (%s) with "
929  "unexpected size.\n",
930  miscRegName[idx]);
931  return;
932  }
933  tc->setMiscReg(idx, getOneRegU64(id));
934  } else {
935  if (show_warnings)
936  warn("Unhandled VFP register: 0x%x\n", id);
937  }
938 }
939 
940 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
bool checkRaw(InterruptTypes interrupt) const
Check the state of a particular interrupt, ignoring CPSR masks.
Definition: interrupts.hh:226
static const std::set< uint64_t > invariant_regs
List of co-processor registers that KVM requires to be identical on both the host and the guest.
Definition: arm_cpu.hh:174
void dumpKvmStateCore()
Definition: arm_cpu.cc:541
ArmISA::MiscRegIndex decodeVFPCtrlReg(uint64_t id) const
Definition: arm_cpu.cc:490
void updateTCStateMisc()
Definition: arm_cpu.cc:831
void updateKvmState()
Update the KVM state from the current thread context.
Definition: arm_cpu.cc:396
void dumpKvmStateMisc()
Definition: arm_cpu.cc:563
void dumpKvmStateCoProc(uint64_t id)
Definition: arm_cpu.cc:599
static KvmIntRegInfo kvmIntRegs[]
Definition: arm_cpu.hh:129
bool isInvariantReg(uint64_t id)
Determine if a register is invariant.
Definition: arm_cpu.cc:514
void dumpKvmStateVFP(uint64_t id)
Definition: arm_cpu.cc:641
void updateKvmStateCore()
Definition: arm_cpu.cc:662
void startup()
startup() is the final initialization call before simulation.
Definition: arm_cpu.cc:353
void updateKvmStateVFP(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:760
ArmKvmCPU(const ArmKvmCPUParams &params)
Definition: arm_cpu.cc:342
void updateTCStateVFP(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:900
void updateKvmStateMisc()
Definition: arm_cpu.cc:688
bool irqAsserted
Cached state of the IRQ line.
Definition: arm_cpu.hh:159
Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
Definition: arm_cpu.cc:368
bool fiqAsserted
Cached state of the FIQ line.
Definition: arm_cpu.hh:161
RegIndexVector _regIndexList
Cached copy of the list of co-processor registers supported by KVM.
Definition: arm_cpu.hh:167
void updateTCStateCore()
Definition: arm_cpu.cc:801
ArmISA::MiscRegIndex decodeCoProcReg(uint64_t id) const
Definition: arm_cpu.cc:455
static KvmCoreMiscRegInfo kvmCoreMiscRegs[]
Definition: arm_cpu.hh:130
void updateTCStateCoProc(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:864
const RegIndexVector & getRegList() const
Get a list of registers supported by getOneReg() and setOneReg().
Definition: arm_cpu.cc:414
void updateThreadContext()
Update the current thread context with the KVM state.
Definition: arm_cpu.cc:405
void updateKvmStateCoProc(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:726
virtual ~ArmKvmCPU()
Definition: arm_cpu.cc:348
void kvmArmVCpuInit(uint32_t target)
Definition: arm_cpu.cc:436
std::vector< BaseInterrupts * > interrupts
Definition: base.hh:220
Base class for KVM based CPU models.
Definition: base.hh:88
long vcpuID
KVM internal ID of the vCPU.
Definition: base.hh:657
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: base.cc:109
uint64_t getOneRegU64(uint64_t id) const
Definition: base.hh:390
std::string getAndFormatOneReg(uint64_t id) const
Get and format one register for printout.
Definition: base.cc:889
uint32_t getOneRegU32(uint64_t id) const
Definition: base.hh:395
void startup() override
startup() is the final initialization call before simulation.
Definition: base.cc:118
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
Definition: base.cc:699
KvmVM * vm
Definition: base.hh:160
void setOneReg(uint64_t id, const void *addr)
Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
Definition: base.cc:855
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state.
Definition: base.hh:158
KVM parent interface.
Definition: vm.hh:81
virtual std::string name() const
Definition: named.hh:47
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition: pcstate.hh:107
Target & as()
Definition: pcstate.hh:72
virtual RegVal readMiscReg(RegIndex misc_reg)=0
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
virtual RegVal getReg(const RegId &reg) const
virtual void setMiscRegNoEffect(RegIndex misc_reg, RegVal val)=0
virtual const PCStateBase & pcState() const =0
virtual void setReg(const RegId &reg, RegVal val)
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
Definition: vm.cc:525
int ioctl(int request, long p1) const
vCPU ioctl interface.
Definition: base.cc:1158
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define hack_once(...)
Definition: logging.hh:254
#define hack(...)
Definition: logging.hh:248
#define warn(...)
Definition: logging.hh:246
#define warn_once(...)
Definition: logging.hh:250
#define inform(...)
Definition: logging.hh:247
constexpr RegId R4
Definition: int.hh:190
constexpr RegId R9
Definition: int.hh:195
constexpr RegId R6
Definition: int.hh:192
constexpr RegId R9Fiq
Definition: int.hh:221
constexpr RegId R12
Definition: int.hh:198
constexpr RegId R14Fiq
Definition: int.hh:226
constexpr RegId R7
Definition: int.hh:193
constexpr RegId R3
Definition: int.hh:189
constexpr RegId R11Fiq
Definition: int.hh:223
constexpr RegId R8
Definition: int.hh:194
constexpr RegId R8Fiq
Definition: int.hh:220
constexpr RegId R13Fiq
Definition: int.hh:225
constexpr RegId R11
Definition: int.hh:197
constexpr RegId R5
Definition: int.hh:191
constexpr RegId R14
Definition: int.hh:200
constexpr RegId R10
Definition: int.hh:196
constexpr RegId R2
Definition: int.hh:188
constexpr RegId R1
Definition: int.hh:187
constexpr auto & SpSvc
Definition: int.hh:278
constexpr RegId R0
Definition: int.hh:186
constexpr RegId R10Fiq
Definition: int.hh:222
constexpr RegId R12Fiq
Definition: int.hh:224
constexpr RegId R13
Definition: int.hh:199
constexpr RegClass flatIntRegClass
Definition: int.hh:178
Bitfield< 3, 0 > mask
Definition: pcstate.hh:63
Bitfield< 7 > i
Definition: misc_types.hh:67
MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
Definition: misc.cc:533
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 7, 5 > opc2
Definition: types.hh:106
constexpr RegClass intRegClass
Definition: int.hh:173
Bitfield< 1 > irq
Definition: misc_types.hh:337
MiscRegIndex
Definition: misc.hh:64
@ MISCREG_FPEXC
Definition: misc.hh:79
@ MISCREG_MVFR1
Definition: misc.hh:77
@ NUM_MISCREGS
Definition: misc.hh:1100
@ MISCREG_FPSID
Definition: misc.hh:75
@ MISCREG_TTBCR
Definition: misc.hh:265
@ MISCREG_SPSR_SVC
Definition: misc.hh:69
@ MISCREG_SPSR_UND
Definition: misc.hh:73
@ MISCREG_SPSR_IRQ
Definition: misc.hh:68
@ MISCREG_SPSR_ABT
Definition: misc.hh:71
@ MISCREG_CPSR
Definition: misc.hh:65
@ MISCREG_TTBR1
Definition: misc.hh:262
@ MISCREG_FPSCR
Definition: misc.hh:76
@ MISCREG_TTBR0
Definition: misc.hh:259
@ MISCREG_MVFR0
Definition: misc.hh:78
@ MISCREG_SPSR_FIQ
Definition: misc.hh:67
MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
Definition: misc.cc:519
const char *const miscRegName[]
Definition: misc.hh:1697
Bitfield< 6, 5 > shift
Definition: types.hh:117
Bitfield< 4 > pc
Bitfield< 1 > ri
Definition: misc.hh:125
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 5, 3 > reg
Definition: types.hh:92
Bitfield< 63 > val
Definition: misc.hh:776
constexpr RegClass floatRegClass
Definition: float.hh:143
const FlagsType init
This Stat is Initialized.
Definition: info.hh:56
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint16_t RegIndex
Definition: types.hh:176
static uint64_t invariant_reg_vector[]
Definition: arm_cpu.cc:243
static const uint64_t KVM_REG64_TTBR0(regCp64(15, 0, 2))
uint64_t Tick
Tick count type.
Definition: types.hh:58
static const uint64_t KVM_REG64_TTBR1(regCp64(15, 1, 2))
const std::string & name()
Definition: trace.cc:49

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