gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
armv8_cpu.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, 2017 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 
41 
42 #include <linux/kvm.h>
43 
44 #include "debug/KvmContext.hh"
45 #include "params/ArmV8KvmCPU.hh"
46 
47 // Unlike gem5, kvm doesn't count the SP as a normal integer register,
48 // which means we only have 31 normal integer registers.
49 constexpr static unsigned NUM_XREGS = NUM_ARCH_INTREGS - 1;
50 static_assert(NUM_XREGS == 31, "Unexpected number of aarch64 int. regs.");
51 
52 // The KVM interface accesses vector registers of 4 single precision
53 // floats instead of individual registers.
54 constexpr static unsigned NUM_QREGS = NumFloatV8ArchRegs / 4;
55 static_assert(NUM_QREGS == 32, "Unexpected number of aarch64 vector regs.");
56 
57 #define EXTRACT_FIELD(v, name) \
58  (((v) & name ## _MASK) >> name ## _SHIFT)
59 
60 #define CORE_REG(name, size) \
61  (KVM_REG_ARM64 | KVM_REG_ARM_CORE | \
62  KVM_REG_SIZE_ ## size | \
63  KVM_REG_ARM_CORE_REG(name))
64 
65 #define INT_REG(name) CORE_REG(name, U64)
66 #define SIMD_REG(name) CORE_REG(name, U128)
67 
68 #define SYS_MPIDR_EL1 ARM64_SYS_REG(0b11, 0b000, 0b0000, 0b0000, 0b101)
69 
70 constexpr uint64_t
71 kvmXReg(const int num)
72 {
73  return INT_REG(regs.regs[0]) +
74  (INT_REG(regs.regs[1]) - INT_REG(regs.regs[0])) * num;
75 }
76 
77 constexpr uint64_t
78 kvmFPReg(const int num)
79 {
80  return SIMD_REG(fp_regs.vregs[0]) +
81  (SIMD_REG(fp_regs.vregs[1]) - SIMD_REG(fp_regs.vregs[0])) * num;
82 }
83 
84 union KvmFPReg {
85  union {
86  uint32_t i;
87  float f;
88  } s[4];
89 
90  union {
91  uint64_t i;
92  double f;
93  } d[2];
94 
95  uint8_t data[32];
96 };
97 
98 #define FP_REGS_PER_VFP_REG 4
99 static_assert(sizeof(FloatRegBits) == 4, "Unexpected float reg size");
100 
102  { INT_REG(regs.sp), INTREG_SP0, "SP(EL0)" },
103  { INT_REG(sp_el1), INTREG_SP1, "SP(EL1)" },
104 };
105 
107  MiscRegInfo(INT_REG(elr_el1), MISCREG_ELR_EL1, "ELR(EL1)"),
108  MiscRegInfo(INT_REG(spsr[KVM_SPSR_EL1]), MISCREG_SPSR_EL1, "SPSR(EL1)"),
109  MiscRegInfo(INT_REG(spsr[KVM_SPSR_ABT]), MISCREG_SPSR_ABT, "SPSR(ABT)"),
110  MiscRegInfo(INT_REG(spsr[KVM_SPSR_UND]), MISCREG_SPSR_UND, "SPSR(UND)"),
111  MiscRegInfo(INT_REG(spsr[KVM_SPSR_IRQ]), MISCREG_SPSR_IRQ, "SPSR(IRQ)"),
112  MiscRegInfo(INT_REG(spsr[KVM_SPSR_FIQ]), MISCREG_SPSR_FIQ, "SPSR(FIQ)"),
113  MiscRegInfo(INT_REG(fp_regs.fpsr), MISCREG_FPSR, "FPSR"),
114  MiscRegInfo(INT_REG(fp_regs.fpcr), MISCREG_FPCR, "FPCR"),
115 };
116 
119 };
120 
121 ArmV8KvmCPU::ArmV8KvmCPU(ArmV8KvmCPUParams *params)
122  : BaseArmKvmCPU(params)
123 {
124 }
125 
127 {
128 }
129 
130 void
132 {
134 
135  // Override ID registers that KVM should "inherit" from gem5.
136  for (const auto &ri : miscRegIdMap) {
137  const uint64_t value(tc->readMiscReg(ri.idx));
138  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
139  setOneReg(ri.kvm, value);
140  }
141 }
142 
143 void
145 {
146  inform("Integer registers:\n");
147  inform(" PC: %s\n", getAndFormatOneReg(INT_REG(regs.pc)));
148  for (int i = 0; i < NUM_XREGS; ++i)
149  inform(" X%i: %s\n", i, getAndFormatOneReg(kvmXReg(i)));
150 
151  for (int i = 0; i < NUM_QREGS; ++i)
152  inform(" Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
153 
154  for (const auto &ri : intRegMap)
155  inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
156 
157  inform(" %s: %s\n", "PSTATE", getAndFormatOneReg(INT_REG(regs.pstate)));
158 
159  for (const auto &ri : miscRegMap)
160  inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
161 
162  for (const auto &ri : miscRegIdMap)
163  inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
164 
165  for (const auto &reg : getRegList()) {
166  const uint64_t arch(reg & KVM_REG_ARCH_MASK);
167  if (arch != KVM_REG_ARM64) {
168  inform("0x%x: %s\n", reg, getAndFormatOneReg(reg));
169  continue;
170  }
171 
172  const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK);
173  switch (type) {
174  case KVM_REG_ARM_CORE:
175  // These have already been printed
176  break;
177 
178  case KVM_REG_ARM64_SYSREG: {
179  const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0));
180  const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1));
181  const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN));
182  const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM));
183  const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2));
184  const MiscRegIndex idx(
185  decodeAArch64SysReg(op0, op1, crn, crm, op2));
186 
187  inform(" %s (op0: %i, op1: %i, crn: %i, crm: %i, op2: %i): %s",
188  miscRegName[idx], op0, op1, crn, crm, op2,
190  } break;
191 
192  case KVM_REG_ARM_DEMUX: {
193  const uint64_t id(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_ID));
194  const uint64_t val(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_VAL));
195  if (id == KVM_REG_ARM_DEMUX_ID_CCSIDR) {
196  inform(" CSSIDR[%i]: %s\n", val,
198  } else {
199  inform(" UNKNOWN[%i:%i]: %s\n", id, val,
201  }
202  } break;
203 
204  default:
205  inform("0x%x: %s\n", reg, getAndFormatOneReg(reg));
206  }
207  }
208 }
209 
210 void
212 {
213  DPRINTF(KvmContext, "In updateKvmState():\n");
214 
215  // update pstate register state
216  CPSR cpsr(tc->readMiscReg(MISCREG_CPSR));
217  cpsr.nz = tc->readCCReg(CCREG_NZ);
218  cpsr.c = tc->readCCReg(CCREG_C);
219  cpsr.v = tc->readCCReg(CCREG_V);
220  if (cpsr.width) {
221  cpsr.ge = tc->readCCReg(CCREG_GE);
222  } else {
223  cpsr.ge = 0;
224  }
225  DPRINTF(KvmContext, " %s := 0x%x\n", "PSTATE", cpsr);
226  setOneReg(INT_REG(regs.pstate), static_cast<uint64_t>(cpsr));
227 
228  for (const auto &ri : miscRegMap) {
229  const uint64_t value(tc->readMiscReg(ri.idx));
230  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
231  setOneReg(ri.kvm, value);
232  }
233 
234  for (int i = 0; i < NUM_XREGS; ++i) {
235  const uint64_t value(tc->readIntReg(INTREG_X0 + i));
236  DPRINTF(KvmContext, " X%i := 0x%x\n", i, value);
237  setOneReg(kvmXReg(i), value);
238  }
239 
240  for (const auto &ri : intRegMap) {
241  const uint64_t value(tc->readIntReg(ri.idx));
242  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
243  setOneReg(ri.kvm, value);
244  }
245 
246  for (int i = 0; i < NUM_QREGS; ++i) {
247  const RegIndex reg_base(i * FP_REGS_PER_VFP_REG);
248  KvmFPReg reg;
249  for (int j = 0; j < FP_REGS_PER_VFP_REG; j++)
250  reg.s[j].i = tc->readFloatRegBits(reg_base + j);
251 
252  setOneReg(kvmFPReg(i), reg.data);
253  DPRINTF(KvmContext, " Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
254  }
255 
256  for (const auto &ri : getSysRegMap()) {
257  const uint64_t value(tc->readMiscReg(ri.idx));
258  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
259  setOneReg(ri.kvm, value);
260  }
261 
262  setOneReg(INT_REG(regs.pc), tc->instAddr());
263  DPRINTF(KvmContext, " PC := 0x%x\n", tc->instAddr());
264 }
265 
266 void
268 {
269  DPRINTF(KvmContext, "In updateThreadContext():\n");
270 
271  // Update pstate thread context
272  const CPSR cpsr(getOneRegU64(INT_REG(regs.pstate)));
273  DPRINTF(KvmContext, " %s := 0x%x\n", "PSTATE", cpsr);
275  tc->setCCReg(CCREG_NZ, cpsr.nz);
276  tc->setCCReg(CCREG_C, cpsr.c);
277  tc->setCCReg(CCREG_V, cpsr.v);
278  if (cpsr.width) {
279  tc->setCCReg(CCREG_GE, cpsr.ge);
280  }
281 
282  // Update core misc regs first as they
283  // affect how other registers are mapped.
284  for (const auto &ri : miscRegMap) {
285  const auto value(getOneRegU64(ri.kvm));
286  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
287  tc->setMiscRegNoEffect(ri.idx, value);
288  }
289 
290  for (int i = 0; i < NUM_XREGS; ++i) {
291  const auto value(getOneRegU64(kvmXReg(i)));
292  DPRINTF(KvmContext, " X%i := 0x%x\n", i, value);
293  // KVM64 returns registers in 64-bit layout. If we are in aarch32
294  // mode, we need to map these to banked ARM32 registers.
295  if (inAArch64(tc)) {
296  tc->setIntReg(INTREG_X0 + i, value);
297  } else {
298  tc->setIntRegFlat(IntReg64Map[INTREG_X0 + i], value);
299  }
300  }
301 
302  for (const auto &ri : intRegMap) {
303  const auto value(getOneRegU64(ri.kvm));
304  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
305  tc->setIntReg(ri.idx, value);
306  }
307 
308  for (int i = 0; i < NUM_QREGS; ++i) {
309  const RegIndex reg_base(i * FP_REGS_PER_VFP_REG);
310  KvmFPReg reg;
311  DPRINTF(KvmContext, " Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
312  getOneReg(kvmFPReg(i), reg.data);
313  for (int j = 0; j < FP_REGS_PER_VFP_REG; j++)
314  tc->setFloatRegBits(reg_base + j, reg.s[j].i);
315  }
316 
317  for (const auto &ri : getSysRegMap()) {
318  const auto value(getOneRegU64(ri.kvm));
319  DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value);
320  tc->setMiscRegNoEffect(ri.idx, value);
321  }
322 
323  PCState pc(getOneRegU64(INT_REG(regs.pc)));
324  pc.aarch64(inAArch64(tc));
325  pc.thumb(cpsr.t);
326  pc.nextAArch64(inAArch64(tc));
327  // TODO: This is a massive assumption that will break when
328  // switching to thumb.
329  pc.nextThumb(cpsr.t);
330  DPRINTF(KvmContext, " PC := 0x%x (t: %i, a64: %i)\n",
331  pc.instAddr(), pc.thumb(), pc.aarch64());
332  tc->pcState(pc);
333 }
334 
337 {
338  // Try to use the cached map
339  if (!sysRegMap.empty())
340  return sysRegMap;
341 
342  for (const auto &reg : getRegList()) {
343  const uint64_t arch(reg & KVM_REG_ARCH_MASK);
344  if (arch != KVM_REG_ARM64)
345  continue;
346 
347  const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK);
348  if (type != KVM_REG_ARM64_SYSREG)
349  continue;
350 
351  const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0));
352  const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1));
353  const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN));
354  const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM));
355  const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2));
356  const MiscRegIndex idx(decodeAArch64SysReg(op0, op1, crn, crm, op2));
357  const auto &info(miscRegInfo[idx]);
358  const bool writeable(
359  info[MISCREG_USR_NS_WR] || info[MISCREG_USR_S_WR] ||
360  info[MISCREG_PRI_S_WR] || info[MISCREG_PRI_NS_WR] ||
361  info[MISCREG_HYP_WR] ||
362  info[MISCREG_MON_NS0_WR] || info[MISCREG_MON_NS1_WR]);
363  const bool implemented(
365 
366  // Only add implemented registers that we are going to be able
367  // to write.
368  if (implemented && writeable)
369  sysRegMap.emplace_back(reg, idx, miscRegName[idx]);
370  }
371 
372  return sysRegMap;
373 }
374 
375 ArmV8KvmCPU *
376 ArmV8KvmCPUParams::create()
377 {
378  return new ArmV8KvmCPU(this);
379 }
static constexpr unsigned NUM_XREGS
Definition: armv8_cpu.cc:49
#define DPRINTF(x,...)
Definition: trace.hh:212
const RegIndexVector & getRegList() const
Get a list of registers supported by getOneReg() and setOneReg().
Definition: base_cpu.cc:109
bitset< NUM_MISCREG_INFOS > miscRegInfo[NUM_MISCREGS]
Definition: miscregs.cc:131
Bitfield< 5, 3 > reg
Definition: types.hh:89
virtual Addr instAddr()=0
Bitfield< 7 > i
Definition: miscregs.hh:1378
virtual CCReg readCCReg(int reg_idx)=0
const IntRegMap IntReg64Map
Definition: intregs.hh:306
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state...
Definition: base.hh:150
virtual void setIntRegFlat(int idx, uint64_t val)=0
virtual void setIntReg(int reg_idx, uint64_t val)=0
const char *const miscRegName[]
Definition: miscregs.hh:739
uint64_t i
Definition: armv8_cpu.cc:91
virtual FloatRegBits readFloatRegBits(int reg_idx)=0
virtual TheISA::PCState pcState()=0
void updateKvmState() override
Update the KVM state from the current thread context.
Definition: armv8_cpu.cc:211
uint8_t data[32]
Definition: armv8_cpu.cc:95
#define INT_REG(name)
Definition: armv8_cpu.cc:65
void updateThreadContext() override
Update the current thread context with the KVM state.
Definition: armv8_cpu.cc:267
STL vector class.
Definition: stl.hh:40
void startup() override
Definition: base_cpu.cc:70
This is an implementation of a KVM-based ARMv8-compatible CPU.
Definition: armv8_cpu.hh:80
Bitfield< 63 > val
Definition: misc.hh:770
virtual void setFloatRegBits(int reg_idx, FloatRegBits val)=0
float f
Definition: armv8_cpu.cc:87
constexpr uint64_t kvmXReg(const int num)
Definition: armv8_cpu.cc:71
virtual void setCCReg(int reg_idx, CCReg val)=0
static const std::vector< ArmV8KvmCPU::MiscRegInfo > miscRegIdMap
Mapping between gem5 ID misc registers registers and registers in kvm.
Definition: armv8_cpu.hh:138
virtual uint64_t readIntReg(int reg_idx)=0
uint8_t RegIndex
Definition: registers.hh:46
uint32_t i
Definition: armv8_cpu.cc:86
uint64_t FloatRegBits
Definition: registers.hh:51
MiscRegIndex decodeAArch64SysReg(unsigned op0, unsigned op1, unsigned crn, unsigned crm, unsigned op2)
Definition: miscregs.cc:2178
#define FP_REGS_PER_VFP_REG
Definition: armv8_cpu.cc:98
void setOneReg(uint64_t id, const void *addr)
Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
Definition: base.cc:880
void startup() override
Definition: armv8_cpu.cc:131
#define SYS_MPIDR_EL1
Definition: armv8_cpu.cc:68
uint64_t getOneRegU64(uint64_t id) const
Definition: base.hh:372
const std::vector< ArmV8KvmCPU::MiscRegInfo > & getSysRegMap() const
Get a map between system registers in kvm and gem5 registers.
Definition: armv8_cpu.cc:336
#define SIMD_REG(name)
Definition: armv8_cpu.cc:66
static constexpr unsigned NUM_QREGS
Definition: armv8_cpu.cc:54
ArmV8KvmCPU(ArmV8KvmCPUParams *params)
Definition: armv8_cpu.cc:121
MiscRegInfo
Definition: miscregs.hh:680
Bitfield< 24 > j
Definition: miscregs.hh:1369
virtual MiscReg readMiscReg(int misc_reg)=0
union KvmFPReg::@3 s[4]
type
Definition: misc.hh:728
std::vector< ArmV8KvmCPU::MiscRegInfo > sysRegMap
Cached mapping between system registers in kvm and misc regs in gem5.
Definition: armv8_cpu.hh:141
void dump() const override
Dump the internal state to the terminal.
Definition: armv8_cpu.cc:144
GenericISA::SimplePCState< MachInst > PCState
Definition: types.hh:43
void getOneReg(uint64_t id, void *addr) const
Definition: base.cc:897
std::string getAndFormatOneReg(uint64_t id) const
Get and format one register for printout.
Definition: base.cc:914
const int NumFloatV8ArchRegs
Definition: registers.hh:79
constexpr uint64_t kvmFPReg(const int num)
Definition: armv8_cpu.cc:78
union KvmFPReg::@4 d[2]
IntReg pc
Definition: remote_gdb.hh:91
#define EXTRACT_FIELD(v, name)
Definition: armv8_cpu.cc:57
static const std::vector< ArmV8KvmCPU::IntRegInfo > intRegMap
Mapping between gem5 integer registers and integer registers in kvm.
Definition: armv8_cpu.hh:134
bool inAArch64(ThreadContext *tc)
Definition: utility.cc:185
double f
Definition: armv8_cpu.cc:92
static const std::vector< ArmV8KvmCPU::MiscRegInfo > miscRegMap
Mapping between gem5 misc registers registers and registers in kvm.
Definition: armv8_cpu.hh:136
Bitfield< 11 > id
Definition: miscregs.hh:124
virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val)=0
#define inform(...)
Definition: misc.hh:221
virtual ~ArmV8KvmCPU()
Definition: armv8_cpu.cc:126

Generated on Fri Jun 9 2017 13:03:39 for gem5 by doxygen 1.8.6