arm: Delete authors lists from the arm files.
[gem5.git] / src / arch / arm / kvm / armv8_cpu.cc
1 /*
2 * Copyright (c) 2015, 2017, 2019 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/armv8_cpu.hh"
39
40 #include <linux/kvm.h>
41
42 #include "debug/KvmContext.hh"
43 #include "params/ArmV8KvmCPU.hh"
44
45 // Unlike gem5, kvm doesn't count the SP as a normal integer register,
46 // which means we only have 31 normal integer registers.
47 constexpr static unsigned NUM_XREGS = NUM_ARCH_INTREGS - 1;
48 static_assert(NUM_XREGS == 31, "Unexpected number of aarch64 int. regs.");
49
50 // The KVM interface accesses vector registers of 4 single precision
51 // floats instead of individual registers.
52 constexpr static unsigned NUM_QREGS = NumVecV8ArchRegs;
53 static_assert(NUM_QREGS == 32, "Unexpected number of aarch64 vector regs.");
54
55 #define EXTRACT_FIELD(v, name) \
56 (((v) & name ## _MASK) >> name ## _SHIFT)
57
58 #define CORE_REG(name, size) \
59 (KVM_REG_ARM64 | KVM_REG_ARM_CORE | \
60 KVM_REG_SIZE_ ## size | \
61 KVM_REG_ARM_CORE_REG(name))
62
63 #define INT_REG(name) CORE_REG(name, U64)
64 #define SIMD_REG(name) CORE_REG(name, U128)
65
66 #define SYS_MPIDR_EL1 ARM64_SYS_REG(0b11, 0b000, 0b0000, 0b0000, 0b101)
67
68 constexpr uint64_t
69 kvmXReg(const int num)
70 {
71 return INT_REG(regs.regs[0]) +
72 (INT_REG(regs.regs[1]) - INT_REG(regs.regs[0])) * num;
73 }
74
75 constexpr uint64_t
76 kvmFPReg(const int num)
77 {
78 return SIMD_REG(fp_regs.vregs[0]) +
79 (SIMD_REG(fp_regs.vregs[1]) - SIMD_REG(fp_regs.vregs[0])) * num;
80 }
81
82 union KvmFPReg {
83 union {
84 uint32_t i;
85 float f;
86 } s[4];
87
88 union {
89 uint64_t i;
90 double f;
91 } d[2];
92
93 uint8_t data[32];
94 };
95
96 #define FP_REGS_PER_VFP_REG 4
97
98 const std::vector<ArmV8KvmCPU::IntRegInfo> ArmV8KvmCPU::intRegMap = {
99 { INT_REG(regs.sp), INTREG_SP0, "SP(EL0)" },
100 { INT_REG(sp_el1), INTREG_SP1, "SP(EL1)" },
101 };
102
103 const std::vector<ArmV8KvmCPU::MiscRegInfo> ArmV8KvmCPU::miscRegMap = {
104 MiscRegInfo(INT_REG(elr_el1), MISCREG_ELR_EL1, "ELR(EL1)"),
105 MiscRegInfo(INT_REG(spsr[KVM_SPSR_EL1]), MISCREG_SPSR_EL1, "SPSR(EL1)"),
106 MiscRegInfo(INT_REG(spsr[KVM_SPSR_ABT]), MISCREG_SPSR_ABT, "SPSR(ABT)"),
107 MiscRegInfo(INT_REG(spsr[KVM_SPSR_UND]), MISCREG_SPSR_UND, "SPSR(UND)"),
108 MiscRegInfo(INT_REG(spsr[KVM_SPSR_IRQ]), MISCREG_SPSR_IRQ, "SPSR(IRQ)"),
109 MiscRegInfo(INT_REG(spsr[KVM_SPSR_FIQ]), MISCREG_SPSR_FIQ, "SPSR(FIQ)"),
110 MiscRegInfo(CORE_REG(fp_regs.fpsr, U32), MISCREG_FPSR, "FPSR"),
111 MiscRegInfo(CORE_REG(fp_regs.fpcr, U32), MISCREG_FPCR, "FPCR"),
112 };
113
114 const std::set<MiscRegIndex> ArmV8KvmCPU::deviceRegSet = {
115 MISCREG_CNTV_CTL_EL0,
116 MISCREG_CNTV_CVAL_EL0,
117 MISCREG_CNTKCTL_EL1,
118 };
119
120 const std::vector<ArmV8KvmCPU::MiscRegInfo> ArmV8KvmCPU::miscRegIdMap = {
121 MiscRegInfo(SYS_MPIDR_EL1, MISCREG_MPIDR_EL1, "MPIDR(EL1)"),
122 };
123
124 ArmV8KvmCPU::ArmV8KvmCPU(ArmV8KvmCPUParams *params)
125 : BaseArmKvmCPU(params)
126 {
127 }
128
129 ArmV8KvmCPU::~ArmV8KvmCPU()
130 {
131 }
132
133 void
134 ArmV8KvmCPU::startup()
135 {
136 BaseArmKvmCPU::startup();
137
138 // Override ID registers that KVM should "inherit" from gem5.
139 for (const auto &ri : miscRegIdMap) {
140 const uint64_t value(tc->readMiscReg(ri.idx));
141 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
142 setOneReg(ri.kvm, value);
143 }
144 }
145
146 void
147 ArmV8KvmCPU::dump() const
148 {
149 inform("Integer registers:\n");
150 inform(" PC: %s\n", getAndFormatOneReg(INT_REG(regs.pc)));
151 for (int i = 0; i < NUM_XREGS; ++i)
152 inform(" X%i: %s\n", i, getAndFormatOneReg(kvmXReg(i)));
153
154 for (int i = 0; i < NUM_QREGS; ++i)
155 inform(" Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
156
157 for (const auto &ri : intRegMap)
158 inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
159
160 inform(" %s: %s\n", "PSTATE", getAndFormatOneReg(INT_REG(regs.pstate)));
161
162 for (const auto &ri : miscRegMap)
163 inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
164
165 for (const auto &ri : miscRegIdMap)
166 inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
167
168 for (const auto &reg : getRegList()) {
169 const uint64_t arch(reg & KVM_REG_ARCH_MASK);
170 if (arch != KVM_REG_ARM64) {
171 inform("0x%x: %s\n", reg, getAndFormatOneReg(reg));
172 continue;
173 }
174
175 const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK);
176 switch (type) {
177 case KVM_REG_ARM_CORE:
178 // These have already been printed
179 break;
180
181 case KVM_REG_ARM64_SYSREG: {
182 const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0));
183 const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1));
184 const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN));
185 const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM));
186 const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2));
187 const MiscRegIndex idx(
188 decodeAArch64SysReg(op0, op1, crn, crm, op2));
189
190 inform(" %s (op0: %i, op1: %i, crn: %i, crm: %i, op2: %i): %s",
191 miscRegName[idx], op0, op1, crn, crm, op2,
192 getAndFormatOneReg(reg));
193 } break;
194
195 case KVM_REG_ARM_DEMUX: {
196 const uint64_t id(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_ID));
197 const uint64_t val(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_VAL));
198 if (id == KVM_REG_ARM_DEMUX_ID_CCSIDR) {
199 inform(" CSSIDR[%i]: %s\n", val,
200 getAndFormatOneReg(reg));
201 } else {
202 inform(" UNKNOWN[%i:%i]: %s\n", id, val,
203 getAndFormatOneReg(reg));
204 }
205 } break;
206
207 default:
208 inform("0x%x: %s\n", reg, getAndFormatOneReg(reg));
209 }
210 }
211 }
212
213 void
214 ArmV8KvmCPU::updateKvmState()
215 {
216 DPRINTF(KvmContext, "In updateKvmState():\n");
217
218 // update pstate register state
219 CPSR cpsr(tc->readMiscReg(MISCREG_CPSR));
220 cpsr.nz = tc->readCCReg(CCREG_NZ);
221 cpsr.c = tc->readCCReg(CCREG_C);
222 cpsr.v = tc->readCCReg(CCREG_V);
223 if (cpsr.width) {
224 cpsr.ge = tc->readCCReg(CCREG_GE);
225 } else {
226 cpsr.ge = 0;
227 }
228 DPRINTF(KvmContext, " %s := 0x%x\n", "PSTATE", cpsr);
229 setOneReg(INT_REG(regs.pstate), static_cast<uint64_t>(cpsr));
230
231 for (const auto &ri : miscRegMap) {
232 const uint64_t value(tc->readMiscReg(ri.idx));
233 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
234 setOneReg(ri.kvm, value);
235 }
236
237 for (int i = 0; i < NUM_XREGS; ++i) {
238 const uint64_t value(tc->readIntReg(INTREG_X0 + i));
239 DPRINTF(KvmContext, " X%i := 0x%x\n", i, value);
240 setOneReg(kvmXReg(i), value);
241 }
242
243 for (const auto &ri : intRegMap) {
244 const uint64_t value(tc->readIntReg(ri.idx));
245 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
246 setOneReg(ri.kvm, value);
247 }
248
249 for (int i = 0; i < NUM_QREGS; ++i) {
250 KvmFPReg reg;
251 auto v = tc->readVecReg(RegId(VecRegClass, i)).as<VecElem>();
252 for (int j = 0; j < FP_REGS_PER_VFP_REG; j++)
253 reg.s[j].i = v[j];
254
255 setOneReg(kvmFPReg(i), reg.data);
256 DPRINTF(KvmContext, " Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
257 }
258
259 for (const auto &ri : getSysRegMap()) {
260 uint64_t value;
261 if (ri.is_device) {
262 // This system register is backed by a device. This means
263 // we need to lock the device event queue.
264 EventQueue::ScopedMigration migrate(deviceEventQueue());
265
266 value = tc->readMiscReg(ri.idx);
267 } else {
268 value = tc->readMiscReg(ri.idx);
269 }
270
271 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
272 setOneReg(ri.kvm, value);
273 }
274
275 setOneReg(INT_REG(regs.pc), tc->instAddr());
276 DPRINTF(KvmContext, " PC := 0x%x\n", tc->instAddr());
277 }
278
279 void
280 ArmV8KvmCPU::updateThreadContext()
281 {
282 DPRINTF(KvmContext, "In updateThreadContext():\n");
283
284 // Update pstate thread context
285 const CPSR cpsr(getOneRegU64(INT_REG(regs.pstate)));
286 DPRINTF(KvmContext, " %s := 0x%x\n", "PSTATE", cpsr);
287 tc->setMiscRegNoEffect(MISCREG_CPSR, cpsr);
288 tc->setCCReg(CCREG_NZ, cpsr.nz);
289 tc->setCCReg(CCREG_C, cpsr.c);
290 tc->setCCReg(CCREG_V, cpsr.v);
291 if (cpsr.width) {
292 tc->setCCReg(CCREG_GE, cpsr.ge);
293 }
294
295 // Update core misc regs first as they
296 // affect how other registers are mapped.
297 for (const auto &ri : miscRegMap) {
298 const auto value(getOneRegU64(ri.kvm));
299 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
300 tc->setMiscRegNoEffect(ri.idx, value);
301 }
302
303 for (int i = 0; i < NUM_XREGS; ++i) {
304 const auto value(getOneRegU64(kvmXReg(i)));
305 DPRINTF(KvmContext, " X%i := 0x%x\n", i, value);
306 // KVM64 returns registers in 64-bit layout. If we are in aarch32
307 // mode, we need to map these to banked ARM32 registers.
308 if (inAArch64(tc)) {
309 tc->setIntReg(INTREG_X0 + i, value);
310 } else {
311 tc->setIntRegFlat(IntReg64Map[INTREG_X0 + i], value);
312 }
313 }
314
315 for (const auto &ri : intRegMap) {
316 const auto value(getOneRegU64(ri.kvm));
317 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
318 tc->setIntReg(ri.idx, value);
319 }
320
321 for (int i = 0; i < NUM_QREGS; ++i) {
322 KvmFPReg reg;
323 DPRINTF(KvmContext, " Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
324 getOneReg(kvmFPReg(i), reg.data);
325 auto v = tc->getWritableVecReg(RegId(VecRegClass, i)).as<VecElem>();
326 for (int j = 0; j < FP_REGS_PER_VFP_REG; j++)
327 v[j] = reg.s[j].i;
328 }
329
330 for (const auto &ri : getSysRegMap()) {
331 const auto value(getOneRegU64(ri.kvm));
332 DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
333 if (ri.is_device) {
334 // This system register is backed by a device. This means
335 // we need to lock the device event queue.
336 EventQueue::ScopedMigration migrate(deviceEventQueue());
337
338 tc->setMiscReg(ri.idx, value);
339 } else {
340 tc->setMiscRegNoEffect(ri.idx, value);
341 }
342 }
343
344 PCState pc(getOneRegU64(INT_REG(regs.pc)));
345 pc.aarch64(inAArch64(tc));
346 pc.thumb(cpsr.t);
347 pc.nextAArch64(inAArch64(tc));
348 // TODO: This is a massive assumption that will break when
349 // switching to thumb.
350 pc.nextThumb(cpsr.t);
351 DPRINTF(KvmContext, " PC := 0x%x (t: %i, a64: %i)\n",
352 pc.instAddr(), pc.thumb(), pc.aarch64());
353 tc->pcState(pc);
354 }
355
356 const std::vector<ArmV8KvmCPU::MiscRegInfo> &
357 ArmV8KvmCPU::getSysRegMap() const
358 {
359 // Try to use the cached map
360 if (!sysRegMap.empty())
361 return sysRegMap;
362
363 for (const auto &reg : getRegList()) {
364 const uint64_t arch(reg & KVM_REG_ARCH_MASK);
365 if (arch != KVM_REG_ARM64)
366 continue;
367
368 const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK);
369 if (type != KVM_REG_ARM64_SYSREG)
370 continue;
371
372 const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0));
373 const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1));
374 const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN));
375 const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM));
376 const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2));
377 const MiscRegIndex idx(decodeAArch64SysReg(op0, op1, crn, crm, op2));
378 const auto &info(miscRegInfo[idx]);
379 const bool writeable(
380 info[MISCREG_USR_NS_WR] || info[MISCREG_USR_S_WR] ||
381 info[MISCREG_PRI_S_WR] || info[MISCREG_PRI_NS_WR] ||
382 info[MISCREG_HYP_WR] ||
383 info[MISCREG_MON_NS0_WR] || info[MISCREG_MON_NS1_WR]);
384 const bool implemented(
385 info[MISCREG_IMPLEMENTED] || info[MISCREG_WARN_NOT_FAIL]);
386
387 // Only add implemented registers that we are going to be able
388 // to write.
389 if (implemented && writeable)
390 sysRegMap.emplace_back(reg, idx, miscRegName[idx],
391 deviceRegSet.find(idx) != deviceRegSet.end());
392 }
393
394 return sysRegMap;
395 }
396
397 ArmV8KvmCPU *
398 ArmV8KvmCPUParams::create()
399 {
400 return new ArmV8KvmCPU(this);
401 }