gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
39
40#include <linux/kvm.h>
41
42#include <algorithm>
43#include <cerrno>
44#include <memory>
45#include <set>
46
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
56namespace gem5
57{
58
59using namespace ArmISA;
60
61namespace
62{
63
64constexpr uint64_t
65extractField(uint64_t val, uint64_t mask, size_t shift)
66{
67 return (val & mask) >> shift;
68}
69
70constexpr bool
71regIsArm(uint64_t id)
72{
73 return (id & KVM_REG_ARCH_MASK) == KVM_REG_ARM;
74}
75
76constexpr bool
77regIs32Bit(uint64_t id)
78{
79 return (id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32;
80}
81
82constexpr bool
83regIs64Bit(uint64_t id)
84{
85 return (id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64;
86}
87
88constexpr bool
89regIsCp(uint64_t id, uint64_t cp)
90{
91 return (id & KVM_REG_ARM_COPROC_MASK) == cp;
92}
93
94constexpr bool
95regIsCore(uint64_t id)
96{
97 return regIsCp(id, KVM_REG_ARM_CORE);
98}
99
100constexpr bool
101regIsVfp(uint64_t id)
102{
103 return regIsCp(id, KVM_REG_ARM_VFP);
104}
105
106constexpr uint64_t
107regVfpReg(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.
114constexpr bool
115regIsVfpReg(uint64_t id)
116{
117 return regVfpReg(id) < 0x100;
118}
119constexpr bool
120regIsVfpCtrl(uint64_t id)
121{
122 return regVfpReg(id) >= 0x100;
123}
124
125constexpr bool
126regIsDemux(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.
135constexpr uint64_t
136regCoreIdx(uint64_t id)
137{
138 return ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
139}
140
141constexpr uint64_t
142regCp(uint64_t id)
143{
144 return extractField(id, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_SHIFT);
145}
146
147constexpr uint64_t
148regCrn(uint64_t id)
149{
150 return extractField(id, KVM_REG_ARM_32_CRN_MASK, KVM_REG_ARM_32_CRN_SHIFT);
151}
152
153constexpr uint64_t
154regOpc1(uint64_t id)
155{
156 return extractField(id, KVM_REG_ARM_OPC1_MASK, KVM_REG_ARM_OPC1_SHIFT);
157}
158
159constexpr uint64_t
160regCrm(uint64_t id)
161{
162 return extractField(id, KVM_REG_ARM_CRM_MASK, KVM_REG_ARM_CRM_SHIFT);
163}
164
165constexpr uint64_t
166regOpc2(uint64_t id)
167{
168 return extractField(id, KVM_REG_ARM_32_OPC2_MASK,
169 KVM_REG_ARM_32_OPC2_SHIFT);
170}
171
172constexpr uint64_t
173regCp32(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
184constexpr uint64_t
185regCp64(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
193constexpr KvmIntRegInfo
194regCore32(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
200constexpr uint64_t
201regVfp32(uint64_t regno)
202{
203 return KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | regno;
204}
205
206constexpr uint64_t
207regVfp64(uint64_t regno)
208{
209 return KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | regno;
210}
211
212constexpr uint64_t
213regDemux32(uint64_t dmxid, uint64_t val)
214{
215 return KVM_REG_ARM | KVM_REG_SIZE_U32 | dmxid | val;
216}
217
218constexpr uint64_t
219interruptId(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
226constexpr uint64_t
227interruptVcpuIrq(uint64_t vcpu)
228{
229 return interruptId(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ);
230}
231
232constexpr uint64_t
233interruptVcpuFiq(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.
243static 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
279const static uint64_t KVM_REG64_TTBR0(regCp64(15, 0, 2));
280const static uint64_t KVM_REG64_TTBR1(regCp64(15, 1, 2));
281
282
283const 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
327ArmKvmCPU::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
342ArmKvmCPU::ArmKvmCPU(const ArmKvmCPUParams &params)
343 : BaseKvmCPU(params),
344 irqAsserted(false), fiqAsserted(false)
345{
346}
347
351
352void
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
367Tick
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
388void
394
395void
397{
398 DPRINTF(KvmContext, "Updating KVM state...\n");
399
402}
403
404void
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
435void
437{
438 struct kvm_vcpu_init init;
439
440 memset(&init, 0, sizeof(init));
441
442 init.target = target;
443
445}
446
447void
448ArmKvmCPU::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
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
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
513bool
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
525bool
526ArmKvmCPU::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
540void
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
562void
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) {
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),
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),
590 break;
591 }
592 } else if (!regIsCore(id)) {
593 inform("0x%x: %s\n", id, getAndFormatOneReg(id));
594 }
595 }
596}
597
598void
600{
601 assert(regIsArm(id));
602 assert(regCp(id) <= 15);
603
604 if (regIs32Bit(id)) {
605 // 32-bit co-proc registers
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),
637 }
638}
639
640void
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)) {
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
661void
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
687void
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
725void
726ArmKvmCPU::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",
753 } else {
755 }
756}
757
758
759void
760ArmKvmCPU::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)) {
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
800void
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
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
830void
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
863void
864ArmKvmCPU::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",
894 } else {
896 }
897}
898
899void
900ArmKvmCPU::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)) {
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:210
bool checkRaw(InterruptTypes interrupt) const
Check the state of a particular interrupt, ignoring CPSR masks.
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:224
Base class for KVM based CPU models.
Definition base.hh:88
long vcpuID
KVM internal ID of the vCPU.
Definition base.hh:660
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition base.cc:128
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:919
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:137
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
Definition base.cc:720
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:885
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state.
Definition base.hh:158
void set(Addr val) override
Force this PC to reflect a particular value, resetting all its other fields around it.
Definition pcstate.hh:378
KVM parent interface.
Definition vm.hh:81
Target & as()
Definition pcstate.hh:73
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
Definition pcstate.hh:108
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 void setReg(const RegId &reg, RegVal val)
virtual const PCStateBase & pcState() const =0
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:1188
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define hack_once(...)
Definition logging.hh:264
#define hack(...)
Definition logging.hh:258
#define warn(...)
Definition logging.hh:256
#define warn_once(...)
Definition logging.hh:260
#define inform(...)
Definition logging.hh:257
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:535
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
@ MISCREG_FPEXC
Definition misc.hh:81
@ MISCREG_MVFR1
Definition misc.hh:79
@ MISCREG_FPSID
Definition misc.hh:77
@ MISCREG_TTBCR
Definition misc.hh:266
@ MISCREG_SPSR_SVC
Definition misc.hh:71
@ MISCREG_SPSR_UND
Definition misc.hh:75
@ MISCREG_SPSR_IRQ
Definition misc.hh:70
@ MISCREG_SPSR_ABT
Definition misc.hh:73
@ MISCREG_CPSR
Definition misc.hh:67
@ MISCREG_TTBR1
Definition misc.hh:263
@ MISCREG_FPSCR
Definition misc.hh:78
@ MISCREG_TTBR0
Definition misc.hh:260
@ MISCREG_MVFR0
Definition misc.hh:80
@ MISCREG_SPSR_FIQ
Definition misc.hh:69
MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
Definition misc.cc:521
const char *const miscRegName[]
Definition misc.hh:1815
Bitfield< 6, 5 > shift
Definition types.hh:117
Bitfield< 4 > pc
Bitfield< 0 > p
Bitfield< 1 > ri
Definition misc.hh:125
Bitfield< 5, 3 > reg
Definition types.hh:92
Bitfield< 63 > val
Definition misc.hh:804
constexpr RegClass floatRegClass
Definition float.hh:143
const FlagsType init
This Stat is Initialized.
Definition info.hh:55
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
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 ArmISA::MiscRegIndex idx
gem5 index
Definition arm_cpu.hh:89
const RegIndex idx
gem5 index
Definition arm_cpu.hh:79
const std::string & name()
Definition trace.cc:48

Generated on Tue Jun 18 2024 16:23:56 for gem5 by doxygen 1.11.0