gem5  v19.0.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 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  */
39 
40 #include "arch/arm/kvm/arm_cpu.hh"
41 
42 #include <linux/kvm.h>
43 
44 #include <algorithm>
45 #include <cerrno>
46 #include <memory>
47 
48 #include "arch/arm/interrupts.hh"
49 #include "arch/registers.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 using namespace ArmISA;
57 
58 #define EXTRACT_FIELD(val, mask, shift) \
59  (((val) & (mask)) >> (shift))
60 
61 #define REG_IS_ARM(id) \
62  (((id) & KVM_REG_ARCH_MASK) == KVM_REG_ARM)
63 
64 #define REG_IS_32BIT(id) \
65  (((id) & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32)
66 
67 #define REG_IS_64BIT(id) \
68  (((id) & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64)
69 
70 #define REG_IS_CP(id, cp) \
71  (((id) & KVM_REG_ARM_COPROC_MASK) == (cp))
72 
73 #define REG_IS_CORE(id) REG_IS_CP((id), KVM_REG_ARM_CORE)
74 
75 #define REG_IS_VFP(id) REG_IS_CP((id), KVM_REG_ARM_VFP)
76 #define REG_VFP_REG(id) ((id) & KVM_REG_ARM_VFP_MASK)
77 // HACK: These aren't really defined in any of the headers, so we'll
78 // assume some reasonable values for now.
79 #define REG_IS_VFP_REG(id) (REG_VFP_REG(id) < 0x100)
80 #define REG_IS_VFP_CTRL(id) (REG_VFP_REG(id) >= 0x100)
81 
82 #define REG_IS_DEMUX(id) REG_IS_CP((id), KVM_REG_ARM_DEMUX)
83 
84 
85 // There is no constant in the kernel headers defining the mask to use
86 // to get the core register index. We'll just do what they do
87 // internally.
88 #define REG_CORE_IDX(id) \
89  (~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE))
90 
91 #define REG_CP(id) \
92  EXTRACT_FIELD(id, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_SHIFT)
93 
94 #define REG_CRN(id) \
95  EXTRACT_FIELD(id, KVM_REG_ARM_32_CRN_MASK, KVM_REG_ARM_32_CRN_SHIFT)
96 
97 #define REG_OPC1(id) \
98  EXTRACT_FIELD(id, KVM_REG_ARM_OPC1_MASK, KVM_REG_ARM_OPC1_SHIFT)
99 
100 #define REG_CRM(id) \
101  EXTRACT_FIELD(id, KVM_REG_ARM_CRM_MASK, KVM_REG_ARM_CRM_SHIFT)
102 
103 #define REG_OPC2(id) \
104  EXTRACT_FIELD(id, KVM_REG_ARM_32_OPC2_MASK, KVM_REG_ARM_32_OPC2_SHIFT)
105 
106 #define REG_CP32(cpnum, crn, opc1, crm, opc2) ( \
107  (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
108  ((cpnum) << KVM_REG_ARM_COPROC_SHIFT) | \
109  ((crn) << KVM_REG_ARM_32_CRN_SHIFT) | \
110  ((opc1) << KVM_REG_ARM_OPC1_SHIFT) | \
111  ((crm) << KVM_REG_ARM_CRM_SHIFT) | \
112  ((opc2) << KVM_REG_ARM_32_OPC2_SHIFT))
113 
114 #define REG_CP64(cpnum, opc1, crm) ( \
115  (KVM_REG_ARM | KVM_REG_SIZE_U64) | \
116  ((cpnum) << KVM_REG_ARM_COPROC_SHIFT) | \
117  ((opc1) << KVM_REG_ARM_OPC1_SHIFT) | \
118  ((crm) << KVM_REG_ARM_CRM_SHIFT))
119 
120 #define REG_CORE32(kname) ( \
121  (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
122  (KVM_REG_ARM_CORE) | \
123  (KVM_REG_ARM_CORE_REG(kname)))
124 
125 #define REG_VFP32(regno) ( \
126  (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
127  KVM_REG_ARM_VFP | (regno))
128 
129 #define REG_VFP64(regno) ( \
130  (KVM_REG_ARM | KVM_REG_SIZE_U64) | \
131  KVM_REG_ARM_VFP | (regno))
132 
133 #define REG_DEMUX32(dmxid, val) ( \
134  (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
135  (dmxid) | (val))
136 
137 // Some of the co-processor registers are invariants and must have the
138 // same value on both the host and the guest. We need to keep a list
139 // of these to prevent gem5 from fiddling with them on the guest.
140 static uint64_t invariant_reg_vector[] = {
141  REG_CP32(15, 0, 0, 0, 0), // MIDR
142  REG_CP32(15, 0, 0, 0, 1), // CTR
143  REG_CP32(15, 0, 0, 0, 2), // TCMTR
144  REG_CP32(15, 0, 0, 0, 3), // TLBTR
145  REG_CP32(15, 0, 0, 0, 6), // REVIDR
146 
147  REG_CP32(15, 0, 0, 1, 0), // ID_PFR0
148  REG_CP32(15, 0, 0, 1, 1), // ID_PFR1
149  REG_CP32(15, 0, 0, 1, 2), // ID_DFR0
150  REG_CP32(15, 0, 0, 1, 3), // ID_AFR0
151  REG_CP32(15, 0, 0, 1, 4), // ID_MMFR0
152  REG_CP32(15, 0, 0, 1, 5), // ID_MMFR1
153  REG_CP32(15, 0, 0, 1, 6), // ID_MMFR2
154  REG_CP32(15, 0, 0, 1, 7), // ID_MMFR3
155 
156  REG_CP32(15, 0, 0, 2, 0), // ID_ISAR0
157  REG_CP32(15, 0, 0, 2, 1), // ID_ISAR1
158  REG_CP32(15, 0, 0, 2, 2), // ID_ISAR2
159  REG_CP32(15, 0, 0, 2, 3), // ID_ISAR3
160  REG_CP32(15, 0, 0, 2, 4), // ID_ISAR4
161  REG_CP32(15, 0, 0, 2, 5), // ID_ISAR5
162 
163  REG_CP32(15, 0, 1, 0, 0), // CSSIDR
164  REG_CP32(15, 0, 1, 0, 1), // CLIDR
165  REG_CP32(15, 0, 1, 0, 7), // AIDR
166 
167  REG_VFP32(KVM_REG_ARM_VFP_MVFR0),
168  REG_VFP32(KVM_REG_ARM_VFP_MVFR1),
169  REG_VFP32(KVM_REG_ARM_VFP_FPSID),
170 
171  REG_DEMUX32(KVM_REG_ARM_DEMUX_ID_CCSIDR, 0),
172 };
173 
174 const static uint64_t KVM_REG64_TTBR0(REG_CP64(15, 0, 2));
175 const static uint64_t KVM_REG64_TTBR1(REG_CP64(15, 1, 2));
176 
177 #define INTERRUPT_ID(type, vcpu, irq) ( \
178  ((type) << KVM_ARM_IRQ_TYPE_SHIFT) | \
179  ((vcpu) << KVM_ARM_IRQ_VCPU_SHIFT) | \
180  ((irq) << KVM_ARM_IRQ_NUM_SHIFT))
181 
182 #define INTERRUPT_VCPU_IRQ(vcpu) \
183  INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ)
184 
185 #define INTERRUPT_VCPU_FIQ(vcpu) \
186  INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ)
187 
188 
189 #define COUNT_OF(l) (sizeof(l) / sizeof(*l))
190 
191 const std::set<uint64_t> ArmKvmCPU::invariant_regs(
194 
195 
197  { REG_CORE32(usr_regs.ARM_r0), INTREG_R0, "R0" },
198  { REG_CORE32(usr_regs.ARM_r1), INTREG_R1, "R1" },
199  { REG_CORE32(usr_regs.ARM_r2), INTREG_R2, "R2" },
200  { REG_CORE32(usr_regs.ARM_r3), INTREG_R3, "R3" },
201  { REG_CORE32(usr_regs.ARM_r4), INTREG_R4, "R4" },
202  { REG_CORE32(usr_regs.ARM_r5), INTREG_R5, "R5" },
203  { REG_CORE32(usr_regs.ARM_r6), INTREG_R6, "R6" },
204  { REG_CORE32(usr_regs.ARM_r7), INTREG_R7, "R7" },
205  { REG_CORE32(usr_regs.ARM_r8), INTREG_R8, "R8" },
206  { REG_CORE32(usr_regs.ARM_r9), INTREG_R9, "R9" },
207  { REG_CORE32(usr_regs.ARM_r10), INTREG_R10, "R10" },
208  { REG_CORE32(usr_regs.ARM_fp), INTREG_R11, "R11" },
209  { REG_CORE32(usr_regs.ARM_ip), INTREG_R12, "R12" },
210  { REG_CORE32(usr_regs.ARM_sp), INTREG_R13, "R13(USR)" },
211  { REG_CORE32(usr_regs.ARM_lr), INTREG_R14, "R14(USR)" },
212 
213  { REG_CORE32(svc_regs[0]), INTREG_SP_SVC, "R13(SVC)" },
214  { REG_CORE32(svc_regs[1]), INTREG_LR_SVC, "R14(SVC)" },
215 
216  { REG_CORE32(abt_regs[0]), INTREG_SP_ABT, "R13(ABT)" },
217  { REG_CORE32(abt_regs[1]), INTREG_LR_ABT, "R14(ABT)" },
218 
219  { REG_CORE32(und_regs[0]), INTREG_SP_UND, "R13(UND)" },
220  { REG_CORE32(und_regs[1]), INTREG_LR_UND, "R14(UND)" },
221 
222  { REG_CORE32(irq_regs[0]), INTREG_SP_IRQ, "R13(IRQ)" },
223  { REG_CORE32(irq_regs[1]), INTREG_LR_IRQ, "R14(IRQ)" },
224 
225 
226  { REG_CORE32(fiq_regs[0]), INTREG_R8_FIQ, "R8(FIQ)" },
227  { REG_CORE32(fiq_regs[1]), INTREG_R9_FIQ, "R9(FIQ)" },
228  { REG_CORE32(fiq_regs[2]), INTREG_R10_FIQ, "R10(FIQ)" },
229  { REG_CORE32(fiq_regs[3]), INTREG_R11_FIQ, "R11(FIQ)" },
230  { REG_CORE32(fiq_regs[4]), INTREG_R12_FIQ, "R12(FIQ)" },
231  { REG_CORE32(fiq_regs[5]), INTREG_R13_FIQ, "R13(FIQ)" },
232  { REG_CORE32(fiq_regs[6]), INTREG_R14_FIQ, "R14(FIQ)" },
233  { 0, NUM_INTREGS, NULL }
234 };
235 
237  { REG_CORE32(usr_regs.ARM_cpsr), MISCREG_CPSR, "CPSR" },
238  { REG_CORE32(svc_regs[2]), MISCREG_SPSR_SVC, "SPSR(SVC)" },
239  { REG_CORE32(abt_regs[2]), MISCREG_SPSR_ABT, "SPSR(ABT)" },
240  { REG_CORE32(und_regs[2]), MISCREG_SPSR_UND, "SPSR(UND)" },
241  { REG_CORE32(irq_regs[2]), MISCREG_SPSR_IRQ, "SPSR(IRQ)" },
242  { REG_CORE32(fiq_regs[2]), MISCREG_SPSR_FIQ, "SPSR(FIQ)" },
243  { 0, NUM_MISCREGS }
244 };
245 
246 ArmKvmCPU::ArmKvmCPU(ArmKvmCPUParams *params)
247  : BaseKvmCPU(params),
248  irqAsserted(false), fiqAsserted(false)
249 {
250 }
251 
253 {
254 }
255 
256 void
258 {
260 
261  /* TODO: This needs to be moved when we start to support VMs with
262  * multiple threads since kvmArmVCpuInit requires that all CPUs in
263  * the VM have been created.
264  */
265  /* TODO: The CPU type needs to be configurable once KVM on ARM
266  * starts to support more CPUs.
267  */
268  kvmArmVCpuInit(KVM_ARM_TARGET_CORTEX_A15);
269 }
270 
271 Tick
273 {
274  auto interrupt = static_cast<ArmISA::Interrupts *>(interrupts[0]);
275  const bool simFIQ(interrupt->checkRaw(INT_FIQ));
276  const bool simIRQ(interrupt->checkRaw(INT_IRQ));
277 
278  if (fiqAsserted != simFIQ) {
279  fiqAsserted = simFIQ;
280  DPRINTF(KvmInt, "KVM: Update FIQ state: %i\n", simFIQ);
282  }
283  if (irqAsserted != simIRQ) {
284  irqAsserted = simIRQ;
285  DPRINTF(KvmInt, "KVM: Update IRQ state: %i\n", simIRQ);
287  }
288 
289  return BaseKvmCPU::kvmRun(ticks);
290 }
291 
292 void
294 {
297 }
298 
299 void
301 {
302  DPRINTF(KvmContext, "Updating KVM state...\n");
303 
306 }
307 
308 void
310 {
311  DPRINTF(KvmContext, "Updating gem5 state...\n");
312 
315 }
316 
317 Tick
319 {
321  const uint32_t reg_ip(tc->readIntRegFlat(INTREG_R12));
322  const uint8_t func((reg_ip >> 8) & 0xFF);
323 
324  DPRINTF(Kvm, "KVM Hypercall: %#x/%#x\n", func, subfunc);
325  const uint64_t ret =
326  PseudoInst::pseudoInst<PseudoInstABI>(getContext(0), func);
327 
328  // Just set the return value using the KVM API instead of messing
329  // with the context. We could have used the context, but that
330  // would have required us to request a full context sync.
331  setOneReg(REG_CORE32(usr_regs.ARM_r0), ret & 0xFFFFFFFF);
332  setOneReg(REG_CORE32(usr_regs.ARM_r1), (ret >> 32) & 0xFFFFFFFF);
333 
334  return 0;
335 }
336 
339 {
340  if (_regIndexList.size() == 0) {
341  std::unique_ptr<struct kvm_reg_list> regs;
342  uint64_t i(1);
343 
344  do {
345  i <<= 1;
346  regs.reset((struct kvm_reg_list *)
347  operator new(sizeof(struct kvm_reg_list) +
348  i * sizeof(uint64_t)));
349  regs->n = i;
350  } while (!getRegList(*regs));
351  _regIndexList.assign(regs->reg,
352  regs->reg + regs->n);
353  }
354 
355  return _regIndexList;
356 }
357 
358 void
360 {
361  struct kvm_vcpu_init init;
362 
363  memset(&init, 0, sizeof(init));
364 
365  init.target = target;
366 
367  kvmArmVCpuInit(init);
368 }
369 
370 void
371 ArmKvmCPU::kvmArmVCpuInit(const struct kvm_vcpu_init &init)
372 {
373  if (ioctl(KVM_ARM_VCPU_INIT, (void *)&init) == -1)
374  panic("KVM: Failed to initialize vCPU\n");
375 }
376 
378 ArmKvmCPU::decodeCoProcReg(uint64_t id) const
379 {
380  const unsigned cp(REG_CP(id));
381  const bool is_reg32(REG_IS_32BIT(id));
382  const bool is_reg64(REG_IS_64BIT(id));
383 
384  // CP numbers larger than 15 are reserved for KVM extensions
385  if (cp > 15)
386  return NUM_MISCREGS;
387 
388  const unsigned crm(REG_CRM(id));
389  const unsigned crn(REG_CRN(id));
390  const unsigned opc1(REG_OPC1(id));
391  const unsigned opc2(REG_OPC2(id));
392 
393  if (is_reg32) {
394  switch (cp) {
395  case 14:
396  return decodeCP14Reg(crn, opc1, crm, opc2);
397 
398  case 15:
399  return decodeCP15Reg(crn, opc1, crm, opc2);
400 
401  default:
402  return NUM_MISCREGS;
403  }
404  } else if (is_reg64) {
405  return NUM_MISCREGS;
406  } else {
407  warn("Unhandled register length, register (0x%x) ignored.\n");
408  return NUM_MISCREGS;
409  }
410 }
411 
413 ArmKvmCPU::decodeVFPCtrlReg(uint64_t id) const
414 {
415  if (!REG_IS_ARM(id) || !REG_IS_VFP(id) || !REG_IS_VFP_CTRL(id))
416  return NUM_MISCREGS;
417 
418  const unsigned vfp_reg(REG_VFP_REG(id));
419  switch (vfp_reg) {
420  case KVM_REG_ARM_VFP_FPSID: return MISCREG_FPSID;
421  case KVM_REG_ARM_VFP_FPSCR: return MISCREG_FPSCR;
422  case KVM_REG_ARM_VFP_MVFR0: return MISCREG_MVFR0;
423  case KVM_REG_ARM_VFP_MVFR1: return MISCREG_MVFR1;
424  case KVM_REG_ARM_VFP_FPEXC: return MISCREG_FPEXC;
425 
426  case KVM_REG_ARM_VFP_FPINST:
427  case KVM_REG_ARM_VFP_FPINST2:
428  warn_once("KVM: FPINST not implemented.\n");
429  return NUM_MISCREGS;
430 
431  default:
432  return NUM_MISCREGS;
433  }
434 }
435 
436 bool
438 {
439  /* Mask away the value field from multiplexed registers, we assume
440  * that entire groups of multiplexed registers can be treated as
441  * invariant. */
442  if (REG_IS_ARM(id) && REG_IS_DEMUX(id))
443  id &= ~KVM_REG_ARM_DEMUX_VAL_MASK;
444 
445  return invariant_regs.find(id) != invariant_regs.end();
446 }
447 
448 bool
449 ArmKvmCPU::getRegList(struct kvm_reg_list &regs) const
450 {
451  if (ioctl(KVM_GET_REG_LIST, (void *)&regs) == -1) {
452  if (errno == E2BIG) {
453  return false;
454  } else {
455  panic("KVM: Failed to get vCPU register list (errno: %i)\n",
456  errno);
457  }
458  } else {
459  return true;
460  }
461 }
462 
463 void
465 {
466  /* Print core registers */
467  uint32_t pc(getOneRegU32(REG_CORE32(usr_regs.ARM_pc)));
468  inform("PC: 0x%x\n", pc);
469 
470  for (const KvmIntRegInfo *ri(kvmIntRegs);
471  ri->idx != NUM_INTREGS; ++ri) {
472 
473  uint32_t value(getOneRegU32(ri->id));
474  inform("%s: 0x%x\n", ri->name, value);
475  }
476 
477  for (const KvmCoreMiscRegInfo *ri(kvmCoreMiscRegs);
478  ri->idx != NUM_MISCREGS; ++ri) {
479 
480  uint32_t value(getOneRegU32(ri->id));
481  inform("%s: 0x%x\n", miscRegName[ri->idx], value);
482  }
483 }
484 
485 void
487 {
488  /* Print co-processor registers */
489  const RegIndexVector &reg_ids(getRegList());;
490  for (RegIndexVector::const_iterator it(reg_ids.begin());
491  it != reg_ids.end(); ++it) {
492  uint64_t id(*it);
493 
494  if (REG_IS_ARM(id) && REG_CP(id) <= 15) {
495  dumpKvmStateCoProc(id);
496  } else if (REG_IS_ARM(id) && REG_IS_VFP(id)) {
497  dumpKvmStateVFP(id);
498  } else if (REG_IS_ARM(id) && REG_IS_DEMUX(id)) {
499  switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
500  case KVM_REG_ARM_DEMUX_ID_CCSIDR:
501  inform("CCSIDR [0x%x]: %s\n",
502  EXTRACT_FIELD(id,
503  KVM_REG_ARM_DEMUX_VAL_MASK,
504  KVM_REG_ARM_DEMUX_VAL_SHIFT),
505  getAndFormatOneReg(id));
506  break;
507  default:
508  inform("DEMUX [0x%x, 0x%x]: %s\n",
509  EXTRACT_FIELD(id,
510  KVM_REG_ARM_DEMUX_ID_MASK,
511  KVM_REG_ARM_DEMUX_ID_SHIFT),
512  EXTRACT_FIELD(id,
513  KVM_REG_ARM_DEMUX_VAL_MASK,
514  KVM_REG_ARM_DEMUX_VAL_SHIFT),
515  getAndFormatOneReg(id));
516  break;
517  }
518  } else if (!REG_IS_CORE(id)) {
519  inform("0x%x: %s\n", id, getAndFormatOneReg(id));
520  }
521  }
522 }
523 
524 void
526 {
527  assert(REG_IS_ARM(id));
528  assert(REG_CP(id) <= 15);
529 
530  if (REG_IS_32BIT(id)) {
531  // 32-bit co-proc registers
532  MiscRegIndex idx(decodeCoProcReg(id));
533  uint32_t value(getOneRegU32(id));
534 
535  if (idx != NUM_MISCREGS &&
536  !(idx >= MISCREG_CP15_UNIMP_START && idx < MISCREG_CP15_END)) {
537  const char *name(miscRegName[idx]);
538  const unsigned m5_ne(tc->readMiscRegNoEffect(idx));
539  const unsigned m5_e(tc->readMiscReg(idx));
540  inform("CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: "
541  "[%s]: 0x%x/0x%x\n",
542  REG_CP(id), REG_CRN(id), REG_OPC1(id), REG_CRM(id),
543  REG_OPC2(id), isInvariantReg(id),
544  name, value, m5_e);
545  if (m5_e != m5_ne) {
546  inform("readMiscReg: %x, readMiscRegNoEffect: %x\n",
547  m5_e, m5_ne);
548  }
549  } else {
550  const char *name(idx != NUM_MISCREGS ? miscRegName[idx] : "-");
551  inform("CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: [%s]: "
552  "0x%x\n",
553  REG_CP(id), REG_CRN(id), REG_OPC1(id), REG_CRM(id),
554  REG_OPC2(id), isInvariantReg(id), name, value);
555  }
556  } else {
557  inform("CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i "
558  "len: 0x%x]: %s\n",
559  REG_CP(id), REG_CRN(id), REG_OPC1(id), REG_CRM(id),
560  REG_OPC2(id), isInvariantReg(id),
561  EXTRACT_FIELD(id, KVM_REG_SIZE_MASK, KVM_REG_SIZE_SHIFT),
562  getAndFormatOneReg(id));
563  }
564 }
565 
566 void
568 {
569  assert(REG_IS_ARM(id));
570  assert(REG_IS_VFP(id));
571 
572  if (REG_IS_VFP_REG(id)) {
573  const unsigned idx(id & KVM_REG_ARM_VFP_MASK);
574  inform("VFP reg %i: %s", idx, getAndFormatOneReg(id));
575  } else if (REG_IS_VFP_CTRL(id)) {
577  if (idx != NUM_MISCREGS) {
578  inform("VFP [%s]: %s", miscRegName[idx], getAndFormatOneReg(id));
579  } else {
580  inform("VFP [0x%x]: %s", id, getAndFormatOneReg(id));
581  }
582  } else {
583  inform("VFP [0x%x]: %s", id, getAndFormatOneReg(id));
584  }
585 }
586 
587 void
589 {
590  for (const KvmIntRegInfo *ri(kvmIntRegs);
591  ri->idx != NUM_INTREGS; ++ri) {
592 
593  uint64_t value(tc->readIntRegFlat(ri->idx));
594  DPRINTF(KvmContext, "kvm(%s) := 0x%x\n", ri->name, value);
595  setOneReg(ri->id, value);
596  }
597 
598  DPRINTF(KvmContext, "kvm(PC) := 0x%x\n", tc->instAddr());
599  setOneReg(REG_CORE32(usr_regs.ARM_pc), tc->instAddr());
600 
601  for (const KvmCoreMiscRegInfo *ri(kvmCoreMiscRegs);
602  ri->idx != NUM_MISCREGS; ++ri) {
603 
604  uint64_t value(tc->readMiscReg(ri->idx));
605  DPRINTF(KvmContext, "kvm(%s) := 0x%x\n", ri->name, value);
606  setOneReg(ri->id, value);
607  }
608 
609  if (DTRACE(KvmContext))
611 }
612 
613 void
615 {
616  static bool warned(false); // We can't use warn_once since we want
617  // to show /all/ registers
618 
619  const RegIndexVector &regs(getRegList());
620 
621  for (RegIndexVector::const_iterator it(regs.begin());
622  it != regs.end();
623  ++it) {
624 
625  if (!REG_IS_ARM(*it)) {
626  if (!warned)
627  warn("Skipping non-ARM register: 0x%x\n", *it);
628  } else if (isInvariantReg(*it)) {
629  DPRINTF(Kvm, "Skipping invariant register: 0x%x\n", *it);
630  } else if (REG_IS_CORE(*it)) {
631  // Core registers are handled in updateKvmStateCore
632  continue;
633  } else if (REG_CP(*it) <= 15) {
634  updateKvmStateCoProc(*it, !warned);
635  } else if (REG_IS_VFP(*it)) {
636  updateKvmStateVFP(*it, !warned);
637  } else {
638  if (!warned) {
639  warn("Skipping register with unknown CP (%i) id: 0x%x\n",
640  REG_CP(*it), *it);
641  }
642  }
643 
644  }
645 
646  warned = true;
647  if (DTRACE(KvmContext))
649 }
650 
651 void
652 ArmKvmCPU::updateKvmStateCoProc(uint64_t id, bool show_warnings)
653 {
655 
656  assert(REG_IS_ARM(id));
657  assert(REG_CP(id) <= 15);
658 
659  if (id == KVM_REG64_TTBR0 || id == KVM_REG64_TTBR1) {
660  // HACK HACK HACK: Workaround for 64-bit TTBRx
661  reg = (id == KVM_REG64_TTBR0 ? MISCREG_TTBR0 : MISCREG_TTBR1);
662  if (show_warnings)
663  hack("KVM: 64-bit TTBBRx workaround\n");
664  }
665 
666  if (reg == NUM_MISCREGS) {
667  if (show_warnings) {
668  warn("KVM: Ignoring unknown KVM co-processor register (0x%.8x):\n",
669  id);
670  warn("\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
671  " opc2: %i]\n",
672  id, REG_CP(id), REG_IS_64BIT(id), REG_CRN(id),
673  REG_OPC1(id), REG_CRM(id), REG_OPC2(id));
674  }
675  } else if (reg >= MISCREG_CP15_UNIMP_START && reg < MISCREG_CP15_END) {
676  if (show_warnings)
677  warn("KVM: Co-processor reg. %s not implemented by gem5.\n",
678  miscRegName[reg]);
679  } else {
680  setOneReg(id, tc->readMiscRegNoEffect(reg));
681  }
682 }
683 
684 
685 void
686 ArmKvmCPU::updateKvmStateVFP(uint64_t id, bool show_warnings)
687 {
688  assert(REG_IS_ARM(id));
689  assert(REG_IS_VFP(id));
690 
691  if (REG_IS_VFP_REG(id)) {
692  if (!REG_IS_64BIT(id)) {
693  if (show_warnings)
694  warn("Unexpected VFP register length (reg: 0x%x).\n", id);
695  return;
696  }
697  const unsigned idx(id & KVM_REG_ARM_VFP_MASK);
698  const unsigned idx_base(idx << 1);
699  const unsigned idx_hi(idx_base + 1);
700  const unsigned idx_lo(idx_base + 0);
701  uint64_t value(
702  ((uint64_t)tc->readFloatRegFlat(idx_hi) << 32) |
703  tc->readFloatRegFlat(idx_lo));
704 
705  setOneReg(id, value);
706  } else if (REG_IS_VFP_CTRL(id)) {
708  if (idx == NUM_MISCREGS) {
709  if (show_warnings)
710  warn("Unhandled VFP control register: 0x%x\n", id);
711  return;
712  }
713  if (!REG_IS_32BIT(id)) {
714  if (show_warnings)
715  warn("Ignoring VFP control register (%s) with "
716  "unexpected size.\n",
717  miscRegName[idx]);
718  return;
719  }
720  setOneReg(id, (uint32_t)tc->readMiscReg(idx));
721  } else {
722  if (show_warnings)
723  warn("Unhandled VFP register: 0x%x\n", id);
724  }
725 }
726 
727 void
729 {
730  for (const KvmIntRegInfo *ri(kvmIntRegs);
731  ri->idx != NUM_INTREGS; ++ri) {
732 
733  tc->setIntRegFlat(ri->idx, getOneRegU32(ri->id));
734  }
735 
736  for (const KvmCoreMiscRegInfo *ri(kvmCoreMiscRegs);
737  ri->idx != NUM_MISCREGS; ++ri) {
738 
739  tc->setMiscRegNoEffect(ri->idx, getOneRegU32(ri->id));
740  }
741 
742  /* We want the simulator to execute all side-effects of the CPSR
743  * update since this updates PC state and register maps.
744  */
746 
747  // We update the PC state after we have updated the CPSR the
748  // contents of the CPSR affects how the npc is updated.
749  PCState pc(tc->pcState());
750  pc.set(getOneRegU32(REG_CORE32(usr_regs.ARM_pc)));
751  tc->pcState(pc);
752 
753  if (DTRACE(KvmContext))
755 }
756 
757 void
759 {
760  static bool warned(false); // We can't use warn_once since we want
761  // to show /all/ registers
762 
763  const RegIndexVector &reg_ids(getRegList());;
764  for (RegIndexVector::const_iterator it(reg_ids.begin());
765  it != reg_ids.end(); ++it) {
766 
767  if (!REG_IS_ARM(*it)) {
768  if (!warned)
769  warn("Skipping non-ARM register: 0x%x\n", *it);
770  } else if (REG_IS_CORE(*it)) {
771  // Core registers are handled in updateKvmStateCore
772  } else if (REG_CP(*it) <= 15) {
773  updateTCStateCoProc(*it, !warned);
774  } else if (REG_IS_VFP(*it)) {
775  updateTCStateVFP(*it, !warned);
776  } else {
777  if (!warned) {
778  warn("Skipping register with unknown CP (%i) id: 0x%x\n",
779  REG_CP(*it), *it);
780  }
781  }
782  }
783 
784  warned = true;
785 
786  if (DTRACE(KvmContext))
788 }
789 
790 void
791 ArmKvmCPU::updateTCStateCoProc(uint64_t id, bool show_warnings)
792 {
794 
795  assert(REG_IS_ARM(id));
796  assert(REG_CP(id) <= 15);
797 
798  if (id == KVM_REG64_TTBR0 || id == KVM_REG64_TTBR1) {
799  // HACK HACK HACK: We don't currently support 64-bit TTBR0/TTBR1
800  hack_once("KVM: 64-bit TTBRx workaround\n");
803  (uint32_t)(getOneRegU64(id) & 0xFFFFFFFF));
804  } else if (reg == MISCREG_TTBCR) {
805  uint32_t value(getOneRegU64(id));
806  if (value & 0x80000000)
807  panic("KVM: Guest tried to enable LPAE.\n");
808  tc->setMiscRegNoEffect(reg, value);
809  } else if (reg == NUM_MISCREGS) {
810  if (show_warnings) {
811  warn("KVM: Ignoring unknown KVM co-processor register:\n", id);
812  warn("\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
813  " opc2: %i]\n",
814  id, REG_CP(id), REG_IS_64BIT(id), REG_CRN(id),
815  REG_OPC1(id), REG_CRM(id), REG_OPC2(id));
816  }
817  } else if (reg >= MISCREG_CP15_UNIMP_START && reg < MISCREG_CP15_END) {
818  if (show_warnings)
819  warn_once("KVM: Co-processor reg. %s not implemented by gem5.\n",
820  miscRegName[reg]);
821  } else {
823  }
824 }
825 
826 void
827 ArmKvmCPU::updateTCStateVFP(uint64_t id, bool show_warnings)
828 {
829  assert(REG_IS_ARM(id));
830  assert(REG_IS_VFP(id));
831 
832  if (REG_IS_VFP_REG(id)) {
833  if (!REG_IS_64BIT(id)) {
834  if (show_warnings)
835  warn("Unexpected VFP register length (reg: 0x%x).\n", id);
836  return;
837  }
838  const unsigned idx(id & KVM_REG_ARM_VFP_MASK);
839  const unsigned idx_base(idx << 1);
840  const unsigned idx_hi(idx_base + 1);
841  const unsigned idx_lo(idx_base + 0);
842  uint64_t value(getOneRegU64(id));
843 
844  tc->setFloatRegFlat(idx_hi, (value >> 32) & 0xFFFFFFFF);
845  tc->setFloatRegFlat(idx_lo, value & 0xFFFFFFFF);
846  } else if (REG_IS_VFP_CTRL(id)) {
848  if (idx == NUM_MISCREGS) {
849  if (show_warnings)
850  warn("Unhandled VFP control register: 0x%x\n", id);
851  return;
852  }
853  if (!REG_IS_32BIT(id)) {
854  if (show_warnings)
855  warn("Ignoring VFP control register (%s) with "
856  "unexpected size.\n",
857  miscRegName[idx]);
858  return;
859  }
860  tc->setMiscReg(idx, getOneRegU64(id));
861  } else {
862  if (show_warnings)
863  warn("Unhandled VFP register: 0x%x\n", id);
864  }
865 }
866 
867 ArmKvmCPU *
868 ArmKvmCPUParams::create()
869 {
870  return new ArmKvmCPU(this);
871 }
#define REG_IS_CORE(id)
Definition: arm_cpu.cc:73
void kvmArmVCpuInit(uint32_t target)
Definition: arm_cpu.cc:359
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
#define DPRINTF(x,...)
Definition: trace.hh:229
void updateTCStateCore()
Definition: arm_cpu.cc:728
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
Tick onKvmExitHypercall()
Definition: arm_cpu.cc:318
MiscRegIndex
Definition: miscregs.hh:57
Bitfield< 5, 3 > reg
Definition: types.hh:89
#define REG_CP64(cpnum, opc1, crm)
Definition: arm_cpu.cc:114
Bitfield< 7 > i
void updateKvmStateVFP(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:686
void dumpKvmStateVFP(uint64_t id)
Definition: arm_cpu.cc:567
virtual TheISA::PCState pcState() const =0
void updateKvmStateCore()
Definition: arm_cpu.cc:588
virtual void setMiscRegNoEffect(RegIndex misc_reg, RegVal val)=0
std::vector< BaseInterrupts * > interrupts
Definition: base.hh:222
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
Definition: base.cc:724
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread&#39;s state...
Definition: base.hh:151
void updateKvmState()
Update the KVM state from the current thread context.
Definition: arm_cpu.cc:300
#define REG_CP32(cpnum, crn, opc1, crm, opc2)
Definition: arm_cpu.cc:106
bool irqAsserted
Cached state of the IRQ line.
Definition: arm_cpu.hh:152
#define EXTRACT_FIELD(val, mask, shift)
Definition: arm_cpu.cc:58
Definition: ccregs.hh:42
#define COUNT_OF(l)
Definition: arm_cpu.cc:189
const char *const miscRegName[]
Definition: miscregs.hh:1021
#define REG_CP(id)
Definition: arm_cpu.cc:91
Base class for KVM based CPU models.
Definition: base.hh:79
void dumpKvmStateCoProc(uint64_t id)
Definition: arm_cpu.cc:525
Definition: cprintf.cc:42
static KvmCoreMiscRegInfo kvmCoreMiscRegs[]
Definition: arm_cpu.hh:123
#define REG_IS_64BIT(id)
Definition: arm_cpu.cc:67
static KvmIntRegInfo kvmIntRegs[]
Definition: arm_cpu.hh:122
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: base.cc:109
const MiscRegIndex idx
gem5 index
Definition: arm_cpu.hh:85
ThreadContext is the external interface to all thread state for anything outside of the CPU...
#define REG_IS_VFP_REG(id)
Definition: arm_cpu.cc:79
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
Definition: vm.cc:502
const long vcpuID
KVM internal ID of the vCPU.
Definition: base.hh:638
Bitfield< 33 > id
static const uint64_t KVM_REG64_TTBR0(REG_CP64(15, 0, 2))
#define REG_VFP32(regno)
Definition: arm_cpu.cc:125
#define inform(...)
Definition: logging.hh:213
#define hack(...)
Definition: logging.hh:214
static const uint64_t KVM_REG64_TTBR1(REG_CP64(15, 1, 2))
Bitfield< 4 > pc
#define DTRACE(x)
Definition: trace.hh:227
#define REG_IS_VFP(id)
Definition: arm_cpu.cc:75
const IntRegIndex idx
gem5 index
Definition: arm_cpu.hh:76
KvmVM & vm
Definition: base.hh:153
#define hack_once(...)
Definition: logging.hh:218
ThreadContext * getContext(int tn) override
Given a thread num get tho thread context for it.
Definition: base.cc:585
void setOneReg(uint64_t id, const void *addr)
Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
Definition: base.cc:881
uint64_t Tick
Tick count type.
Definition: types.hh:63
uint32_t getOneRegU32(uint64_t id) const
Definition: base.hh:378
void dump()
Definition: arm_cpu.cc:293
Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
Definition: arm_cpu.cc:272
std::string getAndFormatOneReg(uint64_t id) const
Get and format one register for printout.
Definition: base.cc:915
#define INTERRUPT_VCPU_FIQ(vcpu)
Definition: arm_cpu.cc:185
void updateThreadContext()
Update the current thread context with the KVM state.
Definition: arm_cpu.cc:309
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:167
virtual void setFloatRegFlat(RegIndex idx, RegVal val)=0
void updateTCStateVFP(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:827
void dumpKvmStateCore()
Definition: arm_cpu.cc:464
virtual Addr instAddr() const =0
#define REG_IS_ARM(id)
Definition: arm_cpu.cc:61
virtual const std::string name() const
Definition: sim_object.hh:120
virtual ~ArmKvmCPU()
Definition: arm_cpu.cc:252
void updateKvmStateCoProc(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:652
static uint64_t invariant_reg_vector[]
Definition: arm_cpu.cc:140
#define warn_once(...)
Definition: logging.hh:216
#define INTERRUPT_VCPU_IRQ(vcpu)
Definition: arm_cpu.cc:182
const RegIndexVector & getRegList() const
Get a list of registers supported by getOneReg() and setOneReg().
Definition: arm_cpu.cc:338
#define REG_CRM(id)
Definition: arm_cpu.cc:100
#define REG_CORE32(kname)
Definition: arm_cpu.cc:120
ArmISA::MiscRegIndex decodeVFPCtrlReg(uint64_t id) const
Definition: arm_cpu.cc:413
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
ArmISA::MiscRegIndex decodeCoProcReg(uint64_t id) const
Definition: arm_cpu.cc:378
void startup()
startup() is the final initialization call before simulation.
Definition: arm_cpu.cc:257
GenericISA::SimplePCState< MachInst > PCState
Definition: types.hh:43
#define REG_VFP_REG(id)
Definition: arm_cpu.cc:76
#define REG_CRN(id)
Definition: arm_cpu.cc:94
ArmKvmCPU(ArmKvmCPUParams *params)
Definition: arm_cpu.cc:246
virtual RegVal readIntRegFlat(RegIndex idx) const =0
Flat register interfaces.
bool fiqAsserted
Cached state of the FIQ line.
Definition: arm_cpu.hh:154
int ioctl(int request, long p1) const
vCPU ioctl interface.
Definition: base.cc:1174
Bitfield< 7, 5 > opc2
Definition: types.hh:116
void updateKvmStateMisc()
Definition: arm_cpu.cc:614
void startup() override
startup() is the final initialization call before simulation.
Definition: base.cc:120
#define warn(...)
Definition: logging.hh:212
#define REG_IS_VFP_CTRL(id)
Definition: arm_cpu.cc:80
virtual RegVal readFloatRegFlat(RegIndex idx) const =0
#define REG_DEMUX32(dmxid, val)
Definition: arm_cpu.cc:133
virtual void setIntRegFlat(RegIndex idx, RegVal val)=0
KVM parent interface.
Definition: vm.hh:74
RegIndexVector _regIndexList
Cached copy of the list of co-processor registers supported by KVM.
Definition: arm_cpu.hh:160
ARM implementation of a KVM-based hardware virtualized CPU.
Definition: arm_cpu.hh:61
MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
Definition: miscregs.cc:132
virtual RegVal readMiscReg(RegIndex misc_reg)=0
MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
Definition: miscregs.cc:55
void updateTCStateMisc()
Definition: arm_cpu.cc:758
void dumpKvmStateMisc()
Definition: arm_cpu.cc:486
uint64_t getOneRegU64(uint64_t id) const
Definition: base.hh:373
#define REG_IS_32BIT(id)
Definition: arm_cpu.cc:64
void updateTCStateCoProc(uint64_t id, bool show_warnings)
Definition: arm_cpu.cc:791
#define REG_OPC1(id)
Definition: arm_cpu.cc:97
bool isInvariantReg(uint64_t id)
Determine if a register is invariant.
Definition: arm_cpu.cc:437
#define REG_OPC2(id)
Definition: arm_cpu.cc:103
#define REG_IS_DEMUX(id)
Definition: arm_cpu.cc:82

Generated on Fri Feb 28 2020 16:26:57 for gem5 by doxygen 1.8.13