armv8_cpu.cc revision 10860
12689Sktlim@umich.edu/*
22689Sktlim@umich.edu * Copyright (c) 2015 ARM Limited
32689Sktlim@umich.edu * All rights reserved
42689Sktlim@umich.edu *
52689Sktlim@umich.edu * The license below extends only to copyright in the software and shall
62689Sktlim@umich.edu * not be construed as granting a license to any other intellectual
72689Sktlim@umich.edu * property including but not limited to intellectual property relating
82689Sktlim@umich.edu * to a hardware implementation of the functionality of the software
92689Sktlim@umich.edu * licensed hereunder.  You may use the software subject to the license
102689Sktlim@umich.edu * terms below provided that you ensure that this notice is replicated
112689Sktlim@umich.edu * unmodified and in its entirety in all distributions of the software,
122689Sktlim@umich.edu * modified or unmodified, in source code or in binary form.
132689Sktlim@umich.edu *
142689Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without
152689Sktlim@umich.edu * modification, are permitted provided that the following conditions are
162689Sktlim@umich.edu * met: redistributions of source code must retain the above copyright
172689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer;
182689Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright
192689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the
202689Sktlim@umich.edu * documentation and/or other materials provided with the distribution;
212689Sktlim@umich.edu * neither the name of the copyright holders nor the names of its
222689Sktlim@umich.edu * contributors may be used to endorse or promote products derived from
232689Sktlim@umich.edu * this software without specific prior written permission.
242689Sktlim@umich.edu *
252689Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262689Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292689Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302689Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312683Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323402Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332683Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342683Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
353402Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
363402Sktlim@umich.edu *
372862Sktlim@umich.edu * Authors: Andreas Sandberg
382862Sktlim@umich.edu */
392862Sktlim@umich.edu
403565Sgblack@eecs.umich.edu#include "arch/arm/kvm/armv8_cpu.hh"
412862Sktlim@umich.edu
423675Sktlim@umich.edu#include <linux/kvm.h>
432862Sktlim@umich.edu
442683Sktlim@umich.edu#include "debug/KvmContext.hh"
452683Sktlim@umich.edu#include "params/ArmV8KvmCPU.hh"
463402Sktlim@umich.edu
473402Sktlim@umich.edu// Unlike gem5, kvm doesn't count the SP as a normal integer register,
482683Sktlim@umich.edu// which means we only have 31 normal integer registers.
495482Snate@binkert.orgconstexpr static unsigned NUM_XREGS = NUM_ARCH_INTREGS - 1;
503280Sgblack@eecs.umich.edustatic_assert(NUM_XREGS == 31, "Unexpected number of aarch64 int. regs.");
512683Sktlim@umich.edu
523402Sktlim@umich.edu// The KVM interface accesses vector registers of 4 single precision
533402Sktlim@umich.edu// floats instead of individual registers.
543402Sktlim@umich.educonstexpr static unsigned NUM_QREGS = NumFloatV8ArchRegs / 4;
553402Sktlim@umich.edustatic_assert(NUM_QREGS == 32, "Unexpected number of aarch64 vector regs.");
563280Sgblack@eecs.umich.edu
572683Sktlim@umich.edu#define EXTRACT_FIELD(v, name) \
582683Sktlim@umich.edu    (((v) & name ## _MASK) >> name ## _SHIFT)
592699Sktlim@umich.edu
602699Sktlim@umich.edu#define CORE_REG(name, size)                               \
612683Sktlim@umich.edu    (KVM_REG_ARM64 | KVM_REG_ARM_CORE |                    \
622683Sktlim@umich.edu     KVM_REG_SIZE_ ## size |                               \
633486Sktlim@umich.edu     KVM_REG_ARM_CORE_REG(name))
643486Sktlim@umich.edu
653486Sktlim@umich.edu#define INT_REG(name) CORE_REG(name, U64)
663486Sktlim@umich.edu#define SIMD_REG(name) CORE_REG(name, U128)
673486Sktlim@umich.edu
683486Sktlim@umich.educonstexpr uint64_t
693486Sktlim@umich.edukvmXReg(const int num)
703486Sktlim@umich.edu{
713486Sktlim@umich.edu    return INT_REG(regs.regs[0]) +
723486Sktlim@umich.edu        (INT_REG(regs.regs[1]) - INT_REG(regs.regs[0])) * num;
732862Sktlim@umich.edu}
742862Sktlim@umich.edu
752862Sktlim@umich.educonstexpr uint64_t
762862Sktlim@umich.edukvmFPReg(const int num)
772862Sktlim@umich.edu{
782862Sktlim@umich.edu    return SIMD_REG(fp_regs.vregs[0]) +
792862Sktlim@umich.edu        (SIMD_REG(fp_regs.vregs[1]) - SIMD_REG(fp_regs.vregs[0])) * num;
803442Sgblack@eecs.umich.edu}
813442Sgblack@eecs.umich.edu
822862Sktlim@umich.eduunion KvmFPReg {
832862Sktlim@umich.edu    union {
842862Sktlim@umich.edu        uint32_t i;
852862Sktlim@umich.edu        float f;
862862Sktlim@umich.edu    } s[4];
872862Sktlim@umich.edu
882862Sktlim@umich.edu    union {
892862Sktlim@umich.edu        uint64_t i;
902862Sktlim@umich.edu        double f;
912862Sktlim@umich.edu    } d[2];
922862Sktlim@umich.edu
932862Sktlim@umich.edu    uint8_t data[32];
942862Sktlim@umich.edu};
952862Sktlim@umich.edu
962862Sktlim@umich.edu#define FP_REGS_PER_VFP_REG 4
972862Sktlim@umich.edustatic_assert(sizeof(FloatRegBits) == 4, "Unexpected float reg size");
982862Sktlim@umich.edu
992862Sktlim@umich.educonst std::vector<ArmV8KvmCPU::IntRegInfo> ArmV8KvmCPU::intRegMap = {
1002862Sktlim@umich.edu    { INT_REG(regs.sp), INTREG_SP0, "SP(EL0)" },
1013442Sgblack@eecs.umich.edu    { INT_REG(sp_el1), INTREG_SP1, "SP(EL1)" },
1023442Sgblack@eecs.umich.edu};
1032862Sktlim@umich.edu
1042862Sktlim@umich.educonst std::vector<ArmV8KvmCPU::MiscRegInfo> ArmV8KvmCPU::miscRegMap = {
1052862Sktlim@umich.edu    MiscRegInfo(INT_REG(regs.pstate), MISCREG_CPSR, "PSTATE"),
1062862Sktlim@umich.edu    MiscRegInfo(INT_REG(elr_el1), MISCREG_ELR_EL1, "ELR(EL1)"),
1072862Sktlim@umich.edu    MiscRegInfo(INT_REG(spsr[KVM_SPSR_EL1]), MISCREG_SPSR_EL1, "SPSR(EL1)"),
1082862Sktlim@umich.edu    MiscRegInfo(INT_REG(spsr[KVM_SPSR_ABT]), MISCREG_SPSR_ABT, "SPSR(ABT)"),
1092862Sktlim@umich.edu    MiscRegInfo(INT_REG(spsr[KVM_SPSR_UND]), MISCREG_SPSR_UND, "SPSR(UND)"),
1102862Sktlim@umich.edu    MiscRegInfo(INT_REG(spsr[KVM_SPSR_IRQ]), MISCREG_SPSR_IRQ, "SPSR(IRQ)"),
1112862Sktlim@umich.edu    MiscRegInfo(INT_REG(spsr[KVM_SPSR_FIQ]), MISCREG_SPSR_FIQ, "SPSR(FIQ)"),
1122862Sktlim@umich.edu    MiscRegInfo(INT_REG(fp_regs.fpsr), MISCREG_FPSR, "FPSR"),
1132862Sktlim@umich.edu    MiscRegInfo(INT_REG(fp_regs.fpcr), MISCREG_FPCR, "FPCR"),
1142683Sktlim@umich.edu};
1153675Sktlim@umich.edu
1165497Ssaidi@eecs.umich.eduArmV8KvmCPU::ArmV8KvmCPU(ArmV8KvmCPUParams *params)
1173675Sktlim@umich.edu    : BaseArmKvmCPU(params)
1183686Sktlim@umich.edu{
1195497Ssaidi@eecs.umich.edu}
1203675Sktlim@umich.edu
1213675Sktlim@umich.eduArmV8KvmCPU::~ArmV8KvmCPU()
1223675Sktlim@umich.edu{
1233686Sktlim@umich.edu}
1243675Sktlim@umich.edu
1253686Sktlim@umich.eduvoid
1263686Sktlim@umich.eduArmV8KvmCPU::dump()
1273686Sktlim@umich.edu{
1284190Ssaidi@eecs.umich.edu    inform("Integer registers:\n");
1295494Sstever@gmail.com    inform("  PC: %s\n", getAndFormatOneReg(INT_REG(regs.pc)));
1304190Ssaidi@eecs.umich.edu    for (int i = 0; i < NUM_XREGS; ++i)
1314190Ssaidi@eecs.umich.edu        inform("  X%i: %s\n", i, getAndFormatOneReg(kvmXReg(i)));
1323675Sktlim@umich.edu
1333675Sktlim@umich.edu    for (int i = 0; i < NUM_QREGS; ++i)
1343675Sktlim@umich.edu        inform("  Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
1353675Sktlim@umich.edu
1363675Sktlim@umich.edu    for (const auto &ri : intRegMap)
1375497Ssaidi@eecs.umich.edu        inform("  %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
1383675Sktlim@umich.edu
1393686Sktlim@umich.edu    for (const auto &ri : miscRegMap)
1403686Sktlim@umich.edu        inform("  %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm));
1413686Sktlim@umich.edu
1424190Ssaidi@eecs.umich.edu    for (const auto &reg : getRegList()) {
1435494Sstever@gmail.com        const uint64_t arch(reg & KVM_REG_ARCH_MASK);
1444190Ssaidi@eecs.umich.edu        if (arch != KVM_REG_ARM64) {
1454190Ssaidi@eecs.umich.edu            inform("0x%x: %s\n", reg, getAndFormatOneReg(reg));
1465497Ssaidi@eecs.umich.edu            continue;
1473675Sktlim@umich.edu        }
1483675Sktlim@umich.edu
1492683Sktlim@umich.edu        const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK);
1502683Sktlim@umich.edu        switch (type) {
1512683Sktlim@umich.edu          case KVM_REG_ARM_CORE:
1522683Sktlim@umich.edu            // These have already been printed
1532683Sktlim@umich.edu            break;
1542683Sktlim@umich.edu
1552683Sktlim@umich.edu          case KVM_REG_ARM64_SYSREG: {
1562683Sktlim@umich.edu              const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0));
1572683Sktlim@umich.edu              const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1));
1582683Sktlim@umich.edu              const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN));
1592683Sktlim@umich.edu              const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM));
1602683Sktlim@umich.edu              const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2));
1612683Sktlim@umich.edu              const MiscRegIndex idx(
1622683Sktlim@umich.edu                  decodeAArch64SysReg(op0, op1, crn, crm, op2));
1632683Sktlim@umich.edu
1643402Sktlim@umich.edu              inform("  %s (op0: %i, op1: %i, crn: %i, crm: %i, op2: %i): %s",
1653402Sktlim@umich.edu                     miscRegName[idx], op0, op1, crn, crm, op2,
1663402Sktlim@umich.edu                     getAndFormatOneReg(reg));
1673402Sktlim@umich.edu          } break;
1683402Sktlim@umich.edu
1693402Sktlim@umich.edu          case KVM_REG_ARM_DEMUX: {
1703402Sktlim@umich.edu              const uint64_t id(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_ID));
1713402Sktlim@umich.edu              const uint64_t val(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_VAL));
1724434Ssaidi@eecs.umich.edu              if (id == KVM_REG_ARM_DEMUX_ID_CCSIDR) {
1734434Ssaidi@eecs.umich.edu                  inform("  CSSIDR[%i]: %s\n", val,
1743402Sktlim@umich.edu                         getAndFormatOneReg(reg));
1753675Sktlim@umich.edu              } else {
1763486Sktlim@umich.edu                  inform("  UNKNOWN[%i:%i]: %s\n", id, val,
1773486Sktlim@umich.edu                         getAndFormatOneReg(reg));
1783486Sktlim@umich.edu              }
1793486Sktlim@umich.edu          } break;
1803486Sktlim@umich.edu
1813675Sktlim@umich.edu          default:
1823675Sktlim@umich.edu            inform("0x%x: %s\n", reg, getAndFormatOneReg(reg));
1833486Sktlim@umich.edu        }
1843486Sktlim@umich.edu    }
1853486Sktlim@umich.edu}
1863402Sktlim@umich.edu
1873402Sktlim@umich.eduvoid
1883402Sktlim@umich.eduArmV8KvmCPU::updateKvmState()
1893402Sktlim@umich.edu{
1903402Sktlim@umich.edu    DPRINTF(KvmContext, "In updateKvmState():\n");
1913402Sktlim@umich.edu    for (const auto &ri : miscRegMap) {
1923402Sktlim@umich.edu        const uint64_t value(tc->readMiscReg(ri.idx));
1933402Sktlim@umich.edu        DPRINTF(KvmContext, "  %s := 0x%x\n", ri.name, value);
1943402Sktlim@umich.edu        setOneReg(ri.kvm, value);
1953675Sktlim@umich.edu    }
1963675Sktlim@umich.edu
1973402Sktlim@umich.edu    for (int i = 0; i < NUM_XREGS; ++i) {
198        const uint64_t value(tc->readIntReg(INTREG_X0 + i));
199        DPRINTF(KvmContext, "  X%i := 0x%x\n", i, value);
200        setOneReg(kvmXReg(i), value);
201    }
202
203    for (const auto &ri : intRegMap) {
204        const uint64_t value(tc->readIntReg(ri.idx));
205        DPRINTF(KvmContext, "  %s := 0x%x\n", ri.name, value);
206        setOneReg(ri.kvm, value);
207    }
208
209    for (int i = 0; i < NUM_QREGS; ++i) {
210        const RegIndex reg_base(i * FP_REGS_PER_VFP_REG);
211        KvmFPReg reg;
212        for (int j = 0; j < FP_REGS_PER_VFP_REG; j++)
213            reg.s[j].i = tc->readFloatRegBits(reg_base + j);
214
215        setOneReg(kvmFPReg(i), reg.data);
216        DPRINTF(KvmContext, "  Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
217    }
218
219    for (const auto &ri : getSysRegMap()) {
220        const uint64_t value(tc->readMiscReg(ri.idx));
221        DPRINTF(KvmContext, "  %s := 0x%x\n", ri.name, value);
222        setOneReg(ri.kvm, value);
223    }
224
225    setOneReg(INT_REG(regs.pc), tc->instAddr());
226    DPRINTF(KvmContext, "  PC := 0x%x\n", tc->instAddr());
227}
228
229void
230ArmV8KvmCPU::updateThreadContext()
231{
232    DPRINTF(KvmContext, "In updateThreadContext():\n");
233
234    // Update core misc regs first as they (particularly PSTATE/CPSR)
235    // affect how other registers are mapped.
236    for (const auto &ri : miscRegMap) {
237        const auto value(getOneRegU64(ri.kvm));
238        DPRINTF(KvmContext, "  %s := 0x%x\n", ri.name, value);
239        tc->setMiscRegNoEffect(ri.idx, value);
240    }
241
242    for (int i = 0; i < NUM_XREGS; ++i) {
243        const auto value(getOneRegU64(kvmXReg(i)));
244        DPRINTF(KvmContext, "  X%i := 0x%x\n", i, value);
245        tc->setIntReg(INTREG_X0 + i, value);
246    }
247
248    for (const auto &ri : intRegMap) {
249        const auto value(getOneRegU64(ri.kvm));
250        DPRINTF(KvmContext, "  %s := 0x%x\n", ri.name, value);
251        tc->setIntReg(ri.idx, value);
252    }
253
254    for (int i = 0; i < NUM_QREGS; ++i) {
255        const RegIndex reg_base(i * FP_REGS_PER_VFP_REG);
256        KvmFPReg reg;
257        DPRINTF(KvmContext, "  Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i)));
258        getOneReg(kvmFPReg(i), reg.data);
259        for (int j = 0; j < FP_REGS_PER_VFP_REG; j++)
260            tc->setFloatRegBits(reg_base + j, reg.s[j].i);
261    }
262
263    for (const auto &ri : getSysRegMap()) {
264        const auto value(getOneRegU64(ri.kvm));
265        DPRINTF(KvmContext, "  %s := 0x%x\n", ri.name, value);
266        tc->setMiscRegNoEffect(ri.idx, value);
267    }
268
269    const CPSR cpsr(tc->readMiscRegNoEffect(MISCREG_CPSR));
270    PCState pc(getOneRegU64(INT_REG(regs.pc)));
271    pc.aarch64(inAArch64(tc));
272    pc.thumb(cpsr.t);
273    pc.nextAArch64(inAArch64(tc));
274    // TODO: This is a massive assumption that will break when
275    // switching to thumb.
276    pc.nextThumb(cpsr.t);
277    DPRINTF(KvmContext, "  PC := 0x%x (t: %i, a64: %i)\n",
278            pc.instAddr(), pc.thumb(), pc.aarch64());
279    tc->pcState(pc);
280}
281
282const std::vector<ArmV8KvmCPU::MiscRegInfo> &
283ArmV8KvmCPU::getSysRegMap() const
284{
285    // Try to use the cached map
286    if (!sysRegMap.empty())
287        return sysRegMap;
288
289    for (const auto &reg : getRegList()) {
290        const uint64_t arch(reg & KVM_REG_ARCH_MASK);
291        if (arch != KVM_REG_ARM64)
292            continue;
293
294        const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK);
295        if (type != KVM_REG_ARM64_SYSREG)
296            continue;
297
298        const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0));
299        const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1));
300        const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN));
301        const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM));
302        const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2));
303        const MiscRegIndex idx(decodeAArch64SysReg(op0, op1, crn, crm, op2));
304        const auto &info(miscRegInfo[idx]);
305        const bool writeable(
306            info[MISCREG_USR_NS_WR] || info[MISCREG_USR_S_WR] ||
307            info[MISCREG_PRI_S_WR] || info[MISCREG_PRI_NS_WR] ||
308            info[MISCREG_HYP_WR] ||
309            info[MISCREG_MON_NS0_WR] || info[MISCREG_MON_NS1_WR]);
310        const bool implemented(
311            info[MISCREG_IMPLEMENTED] || info[MISCREG_WARN_NOT_FAIL]);
312
313        // Only add implemented registers that we are going to be able
314        // to write.
315        if (implemented && writeable)
316            sysRegMap.emplace_back(reg, idx, miscRegName[idx]);
317    }
318
319    return sysRegMap;
320}
321
322ArmV8KvmCPU *
323ArmV8KvmCPUParams::create()
324{
325    return new ArmV8KvmCPU(this);
326}
327