From 7c4eb3b4d88480003f8c227731f7a31bd55cb819 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 1 Jun 2015 19:44:19 +0100 Subject: [PATCH 01/16] kvm, arm: Add support for aarch64 This changeset adds support for aarch64 in kvm. The CPU module supports both checkpointing and online CPU model switching as long as no devices are simulated by the host kernel. It currently has the following limitations: * The system register based generic timer can only be simulated by the host kernel. Workaround: Use a memory mapped timer instead to simulate the timer in gem5. * Simulating devices (e.g., the generic timer) in the host kernel requires that the host kernel also simulates the GIC. * ID registers in the host and in gem5 must match for switching between simulated CPUs and KVM. This is particularly important for ID registers describing memory system capabilities (e.g., ASID size, physical address size). * Switching between a virtualized CPU and a simulated CPU is currently not supported if in-kernel device emulation is used. This could be worked around by adding support for switching to the gem5 (e.g., the KvmGic) side of the device models. A simpler workaround is to avoid in-kernel device models altogether. --- SConstruct | 2 +- configs/common/CpuConfig.py | 2 +- src/arch/arm/kvm/ArmV8KvmCPU.py | 43 ++++ src/arch/arm/kvm/BaseArmKvmCPU.py | 44 ++++ src/arch/arm/kvm/SConscript | 6 + src/arch/arm/kvm/armv8_cpu.cc | 326 ++++++++++++++++++++++++++++++ src/arch/arm/kvm/armv8_cpu.hh | 140 +++++++++++++ src/arch/arm/kvm/base_cpu.cc | 154 ++++++++++++++ src/arch/arm/kvm/base_cpu.hh | 111 ++++++++++ src/cpu/kvm/vm.cc | 11 + src/cpu/kvm/vm.hh | 17 ++ 11 files changed, 854 insertions(+), 2 deletions(-) create mode 100644 src/arch/arm/kvm/ArmV8KvmCPU.py create mode 100644 src/arch/arm/kvm/BaseArmKvmCPU.py create mode 100644 src/arch/arm/kvm/armv8_cpu.cc create mode 100644 src/arch/arm/kvm/armv8_cpu.hh create mode 100644 src/arch/arm/kvm/base_cpu.cc create mode 100644 src/arch/arm/kvm/base_cpu.hh diff --git a/SConstruct b/SConstruct index 2d61aa0f2..d229960c2 100755 --- a/SConstruct +++ b/SConstruct @@ -1048,7 +1048,7 @@ def is_isa_kvm_compatible(isa): return False if isa == "arm": - return host_isa == "armv7l" + return host_isa in ( "armv7l", "aarch64" ) elif isa == "x86": if host_isa != "x86_64": return False diff --git a/configs/common/CpuConfig.py b/configs/common/CpuConfig.py index f30e28246..6b530623d 100644 --- a/configs/common/CpuConfig.py +++ b/configs/common/CpuConfig.py @@ -52,7 +52,7 @@ _cpu_aliases_all = [ ("atomic", "AtomicSimpleCPU"), ("minor", "MinorCPU"), ("detailed", "DerivO3CPU"), - ("kvm", ("ArmKvmCPU", "X86KvmCPU")), + ("kvm", ("ArmKvmCPU", "ArmV8KvmCPU", "X86KvmCPU")), ] # Filtered list of aliases. Only aliases for existing CPUs exist in diff --git a/src/arch/arm/kvm/ArmV8KvmCPU.py b/src/arch/arm/kvm/ArmV8KvmCPU.py new file mode 100644 index 000000000..13cf2d4db --- /dev/null +++ b/src/arch/arm/kvm/ArmV8KvmCPU.py @@ -0,0 +1,43 @@ +# Copyright (c) 2015 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Andreas Sandberg + +from m5.params import * +from BaseArmKvmCPU import BaseArmKvmCPU + +class ArmV8KvmCPU(BaseArmKvmCPU): + type = 'ArmV8KvmCPU' + cxx_header = "arch/arm/kvm/armv8_cpu.hh" diff --git a/src/arch/arm/kvm/BaseArmKvmCPU.py b/src/arch/arm/kvm/BaseArmKvmCPU.py new file mode 100644 index 000000000..f29c81190 --- /dev/null +++ b/src/arch/arm/kvm/BaseArmKvmCPU.py @@ -0,0 +1,44 @@ +# Copyright (c) 2015 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Andreas Sandberg + +from m5.params import * +from BaseKvmCPU import BaseKvmCPU + +class BaseArmKvmCPU(BaseKvmCPU): + type = 'BaseArmKvmCPU' + cxx_header = "arch/arm/kvm/base_cpu.hh" + abstract = True diff --git a/src/arch/arm/kvm/SConscript b/src/arch/arm/kvm/SConscript index 185aac7b6..a8a2d2dc8 100644 --- a/src/arch/arm/kvm/SConscript +++ b/src/arch/arm/kvm/SConscript @@ -48,6 +48,12 @@ host_isa = platform.machine() SimObject('KvmGic.py') Source('gic.cc') +SimObject('BaseArmKvmCPU.py') +Source('base_cpu.cc') + if host_isa == "armv7l": SimObject('ArmKvmCPU.py') Source('arm_cpu.cc') +elif host_isa == "aarch64": + SimObject('ArmV8KvmCPU.py') + Source('armv8_cpu.cc') diff --git a/src/arch/arm/kvm/armv8_cpu.cc b/src/arch/arm/kvm/armv8_cpu.cc new file mode 100644 index 000000000..071d27dd0 --- /dev/null +++ b/src/arch/arm/kvm/armv8_cpu.cc @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#include "arch/arm/kvm/armv8_cpu.hh" + +#include + +#include "debug/KvmContext.hh" +#include "params/ArmV8KvmCPU.hh" + +// Unlike gem5, kvm doesn't count the SP as a normal integer register, +// which means we only have 31 normal integer registers. +constexpr static unsigned NUM_XREGS = NUM_ARCH_INTREGS - 1; +static_assert(NUM_XREGS == 31, "Unexpected number of aarch64 int. regs."); + +// The KVM interface accesses vector registers of 4 single precision +// floats instead of individual registers. +constexpr static unsigned NUM_QREGS = NumFloatV8ArchRegs / 4; +static_assert(NUM_QREGS == 32, "Unexpected number of aarch64 vector regs."); + +#define EXTRACT_FIELD(v, name) \ + (((v) & name ## _MASK) >> name ## _SHIFT) + +#define CORE_REG(name, size) \ + (KVM_REG_ARM64 | KVM_REG_ARM_CORE | \ + KVM_REG_SIZE_ ## size | \ + KVM_REG_ARM_CORE_REG(name)) + +#define INT_REG(name) CORE_REG(name, U64) +#define SIMD_REG(name) CORE_REG(name, U128) + +constexpr uint64_t +kvmXReg(const int num) +{ + return INT_REG(regs.regs[0]) + + (INT_REG(regs.regs[1]) - INT_REG(regs.regs[0])) * num; +} + +constexpr uint64_t +kvmFPReg(const int num) +{ + return SIMD_REG(fp_regs.vregs[0]) + + (SIMD_REG(fp_regs.vregs[1]) - SIMD_REG(fp_regs.vregs[0])) * num; +} + +union KvmFPReg { + union { + uint32_t i; + float f; + } s[4]; + + union { + uint64_t i; + double f; + } d[2]; + + uint8_t data[32]; +}; + +#define FP_REGS_PER_VFP_REG 4 +static_assert(sizeof(FloatRegBits) == 4, "Unexpected float reg size"); + +const std::vector ArmV8KvmCPU::intRegMap = { + { INT_REG(regs.sp), INTREG_SP0, "SP(EL0)" }, + { INT_REG(sp_el1), INTREG_SP1, "SP(EL1)" }, +}; + +const std::vector ArmV8KvmCPU::miscRegMap = { + MiscRegInfo(INT_REG(regs.pstate), MISCREG_CPSR, "PSTATE"), + MiscRegInfo(INT_REG(elr_el1), MISCREG_ELR_EL1, "ELR(EL1)"), + MiscRegInfo(INT_REG(spsr[KVM_SPSR_EL1]), MISCREG_SPSR_EL1, "SPSR(EL1)"), + MiscRegInfo(INT_REG(spsr[KVM_SPSR_ABT]), MISCREG_SPSR_ABT, "SPSR(ABT)"), + MiscRegInfo(INT_REG(spsr[KVM_SPSR_UND]), MISCREG_SPSR_UND, "SPSR(UND)"), + MiscRegInfo(INT_REG(spsr[KVM_SPSR_IRQ]), MISCREG_SPSR_IRQ, "SPSR(IRQ)"), + MiscRegInfo(INT_REG(spsr[KVM_SPSR_FIQ]), MISCREG_SPSR_FIQ, "SPSR(FIQ)"), + MiscRegInfo(INT_REG(fp_regs.fpsr), MISCREG_FPSR, "FPSR"), + MiscRegInfo(INT_REG(fp_regs.fpcr), MISCREG_FPCR, "FPCR"), +}; + +ArmV8KvmCPU::ArmV8KvmCPU(ArmV8KvmCPUParams *params) + : BaseArmKvmCPU(params) +{ +} + +ArmV8KvmCPU::~ArmV8KvmCPU() +{ +} + +void +ArmV8KvmCPU::dump() +{ + inform("Integer registers:\n"); + inform(" PC: %s\n", getAndFormatOneReg(INT_REG(regs.pc))); + for (int i = 0; i < NUM_XREGS; ++i) + inform(" X%i: %s\n", i, getAndFormatOneReg(kvmXReg(i))); + + for (int i = 0; i < NUM_QREGS; ++i) + inform(" Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i))); + + for (const auto &ri : intRegMap) + inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm)); + + for (const auto &ri : miscRegMap) + inform(" %s: %s\n", ri.name, getAndFormatOneReg(ri.kvm)); + + for (const auto ® : getRegList()) { + const uint64_t arch(reg & KVM_REG_ARCH_MASK); + if (arch != KVM_REG_ARM64) { + inform("0x%x: %s\n", reg, getAndFormatOneReg(reg)); + continue; + } + + const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK); + switch (type) { + case KVM_REG_ARM_CORE: + // These have already been printed + break; + + case KVM_REG_ARM64_SYSREG: { + const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0)); + const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1)); + const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN)); + const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM)); + const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2)); + const MiscRegIndex idx( + decodeAArch64SysReg(op0, op1, crn, crm, op2)); + + inform(" %s (op0: %i, op1: %i, crn: %i, crm: %i, op2: %i): %s", + miscRegName[idx], op0, op1, crn, crm, op2, + getAndFormatOneReg(reg)); + } break; + + case KVM_REG_ARM_DEMUX: { + const uint64_t id(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_ID)); + const uint64_t val(EXTRACT_FIELD(reg, KVM_REG_ARM_DEMUX_VAL)); + if (id == KVM_REG_ARM_DEMUX_ID_CCSIDR) { + inform(" CSSIDR[%i]: %s\n", val, + getAndFormatOneReg(reg)); + } else { + inform(" UNKNOWN[%i:%i]: %s\n", id, val, + getAndFormatOneReg(reg)); + } + } break; + + default: + inform("0x%x: %s\n", reg, getAndFormatOneReg(reg)); + } + } +} + +void +ArmV8KvmCPU::updateKvmState() +{ + DPRINTF(KvmContext, "In updateKvmState():\n"); + for (const auto &ri : miscRegMap) { + const uint64_t value(tc->readMiscReg(ri.idx)); + DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value); + setOneReg(ri.kvm, value); + } + + for (int i = 0; i < NUM_XREGS; ++i) { + const uint64_t value(tc->readIntReg(INTREG_X0 + i)); + DPRINTF(KvmContext, " X%i := 0x%x\n", i, value); + setOneReg(kvmXReg(i), value); + } + + for (const auto &ri : intRegMap) { + const uint64_t value(tc->readIntReg(ri.idx)); + DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value); + setOneReg(ri.kvm, value); + } + + for (int i = 0; i < NUM_QREGS; ++i) { + const RegIndex reg_base(i * FP_REGS_PER_VFP_REG); + KvmFPReg reg; + for (int j = 0; j < FP_REGS_PER_VFP_REG; j++) + reg.s[j].i = tc->readFloatRegBits(reg_base + j); + + setOneReg(kvmFPReg(i), reg.data); + DPRINTF(KvmContext, " Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i))); + } + + for (const auto &ri : getSysRegMap()) { + const uint64_t value(tc->readMiscReg(ri.idx)); + DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value); + setOneReg(ri.kvm, value); + } + + setOneReg(INT_REG(regs.pc), tc->instAddr()); + DPRINTF(KvmContext, " PC := 0x%x\n", tc->instAddr()); +} + +void +ArmV8KvmCPU::updateThreadContext() +{ + DPRINTF(KvmContext, "In updateThreadContext():\n"); + + // Update core misc regs first as they (particularly PSTATE/CPSR) + // affect how other registers are mapped. + for (const auto &ri : miscRegMap) { + const auto value(getOneRegU64(ri.kvm)); + DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value); + tc->setMiscRegNoEffect(ri.idx, value); + } + + for (int i = 0; i < NUM_XREGS; ++i) { + const auto value(getOneRegU64(kvmXReg(i))); + DPRINTF(KvmContext, " X%i := 0x%x\n", i, value); + tc->setIntReg(INTREG_X0 + i, value); + } + + for (const auto &ri : intRegMap) { + const auto value(getOneRegU64(ri.kvm)); + DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value); + tc->setIntReg(ri.idx, value); + } + + for (int i = 0; i < NUM_QREGS; ++i) { + const RegIndex reg_base(i * FP_REGS_PER_VFP_REG); + KvmFPReg reg; + DPRINTF(KvmContext, " Q%i: %s\n", i, getAndFormatOneReg(kvmFPReg(i))); + getOneReg(kvmFPReg(i), reg.data); + for (int j = 0; j < FP_REGS_PER_VFP_REG; j++) + tc->setFloatRegBits(reg_base + j, reg.s[j].i); + } + + for (const auto &ri : getSysRegMap()) { + const auto value(getOneRegU64(ri.kvm)); + DPRINTF(KvmContext, " %s := 0x%x\n", ri.name, value); + tc->setMiscRegNoEffect(ri.idx, value); + } + + const CPSR cpsr(tc->readMiscRegNoEffect(MISCREG_CPSR)); + PCState pc(getOneRegU64(INT_REG(regs.pc))); + pc.aarch64(inAArch64(tc)); + pc.thumb(cpsr.t); + pc.nextAArch64(inAArch64(tc)); + // TODO: This is a massive assumption that will break when + // switching to thumb. + pc.nextThumb(cpsr.t); + DPRINTF(KvmContext, " PC := 0x%x (t: %i, a64: %i)\n", + pc.instAddr(), pc.thumb(), pc.aarch64()); + tc->pcState(pc); +} + +const std::vector & +ArmV8KvmCPU::getSysRegMap() const +{ + // Try to use the cached map + if (!sysRegMap.empty()) + return sysRegMap; + + for (const auto ® : getRegList()) { + const uint64_t arch(reg & KVM_REG_ARCH_MASK); + if (arch != KVM_REG_ARM64) + continue; + + const uint64_t type(reg & KVM_REG_ARM_COPROC_MASK); + if (type != KVM_REG_ARM64_SYSREG) + continue; + + const uint64_t op0(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP0)); + const uint64_t op1(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP1)); + const uint64_t crn(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRN)); + const uint64_t crm(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_CRM)); + const uint64_t op2(EXTRACT_FIELD(reg, KVM_REG_ARM64_SYSREG_OP2)); + const MiscRegIndex idx(decodeAArch64SysReg(op0, op1, crn, crm, op2)); + const auto &info(miscRegInfo[idx]); + const bool writeable( + info[MISCREG_USR_NS_WR] || info[MISCREG_USR_S_WR] || + info[MISCREG_PRI_S_WR] || info[MISCREG_PRI_NS_WR] || + info[MISCREG_HYP_WR] || + info[MISCREG_MON_NS0_WR] || info[MISCREG_MON_NS1_WR]); + const bool implemented( + info[MISCREG_IMPLEMENTED] || info[MISCREG_WARN_NOT_FAIL]); + + // Only add implemented registers that we are going to be able + // to write. + if (implemented && writeable) + sysRegMap.emplace_back(reg, idx, miscRegName[idx]); + } + + return sysRegMap; +} + +ArmV8KvmCPU * +ArmV8KvmCPUParams::create() +{ + return new ArmV8KvmCPU(this); +} diff --git a/src/arch/arm/kvm/armv8_cpu.hh b/src/arch/arm/kvm/armv8_cpu.hh new file mode 100644 index 000000000..97127b471 --- /dev/null +++ b/src/arch/arm/kvm/armv8_cpu.hh @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#ifndef __ARCH_ARM_KVM_ARMV8_CPU_HH__ +#define __ARCH_ARM_KVM_ARMV8_CPU_HH__ + +#include + +#include "arch/arm/intregs.hh" +#include "arch/arm/kvm/base_cpu.hh" +#include "arch/arm/miscregs.hh" + +struct ArmV8KvmCPUParams; + +/** + * This is an implementation of a KVM-based ARMv8-compatible CPU. + * + * Known limitations: + *
    + * + *
  • The system-register-based generic timer can only be simulated + * by the host kernel. Workaround: Use a memory mapped timer + * instead to simulate the timer in gem5. + * + *
  • Simulating devices (e.g., the generic timer) in the host + * kernel requires that the host kernel also simulates the + * GIC. + * + *
  • ID registers in the host and in gem5 must match for switching + * between simulated CPUs and KVM. This is particularly + * important for ID registers describing memory system + * capabilities (e.g., ASID size, physical address size). + * + *
  • Switching between a virtualized CPU and a simulated CPU is + * currently not supported if in-kernel device emulation is + * used. This could be worked around by adding support for + * switching to the gem5 (e.g., the KvmGic) side of the device + * models. A simpler workaround is to avoid in-kernel device + * models altogether. + * + *
+ * + */ +class ArmV8KvmCPU : public BaseArmKvmCPU +{ + public: + ArmV8KvmCPU(ArmV8KvmCPUParams *params); + virtual ~ArmV8KvmCPU(); + + void dump() M5_ATTR_OVERRIDE; + + protected: + void updateKvmState() M5_ATTR_OVERRIDE; + void updateThreadContext() M5_ATTR_OVERRIDE; + + protected: + /** Mapping between integer registers in gem5 and KVM */ + struct IntRegInfo { + IntRegInfo(uint64_t _kvm, IntRegIndex _idx, const char *_name) + : kvm(_kvm), idx(_idx), name(_name) {} + + /** Register index in KVM */ + uint64_t kvm; + /** Register index in gem5 */ + IntRegIndex idx; + /** Name to use in debug dumps */ + const char *name; + }; + + /** Mapping between misc registers in gem5 and registers in KVM */ + struct MiscRegInfo { + MiscRegInfo(uint64_t _kvm, MiscRegIndex _idx, const char *_name) + : kvm(_kvm), idx(_idx), name(_name) {} + + /** Register index in KVM */ + uint64_t kvm; + /** Register index in gem5 */ + MiscRegIndex idx; + /** Name to use in debug dumps */ + const char *name; + }; + + /** + * Get a map between system registers in kvm and gem5 registers + * + * This method returns a mapping between system registers in kvm + * and misc regs in gem5. The actual mapping is only created the + * first time the method is called and stored in a cache + * (ArmV8KvmCPU::sysRegMap). + * + * @return Vector of kvm<->misc reg mappings. + */ + const std::vector &getSysRegMap() const; + + /** Mapping between gem5 integer registers and integer registers in kvm */ + static const std::vector intRegMap; + /** Mapping between gem5 misc registers registers and registers in kvm */ + static const std::vector miscRegMap; + + /** Cached mapping between system registers in kvm and misc regs in gem5 */ + mutable std::vector sysRegMap; +}; + +#endif // __ARCH_ARM_KVM_ARMV8_CPU_HH__ diff --git a/src/arch/arm/kvm/base_cpu.cc b/src/arch/arm/kvm/base_cpu.cc new file mode 100644 index 000000000..61de16900 --- /dev/null +++ b/src/arch/arm/kvm/base_cpu.cc @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2012, 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#include "arch/arm/kvm/base_cpu.hh" + +#include + +#include "debug/KvmInt.hh" +#include "params/BaseArmKvmCPU.hh" + + +#define INTERRUPT_ID(type, vcpu, irq) ( \ + ((type) << KVM_ARM_IRQ_TYPE_SHIFT) | \ + ((vcpu) << KVM_ARM_IRQ_VCPU_SHIFT) | \ + ((irq) << KVM_ARM_IRQ_NUM_SHIFT)) + +#define INTERRUPT_VCPU_IRQ(vcpu) \ + INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ) + +#define INTERRUPT_VCPU_FIQ(vcpu) \ + INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ) + + +BaseArmKvmCPU::BaseArmKvmCPU(BaseArmKvmCPUParams *params) + : BaseKvmCPU(params), + irqAsserted(false), fiqAsserted(false) +{ +} + +BaseArmKvmCPU::~BaseArmKvmCPU() +{ +} + +void +BaseArmKvmCPU::startup() +{ + BaseKvmCPU::startup(); + + /* TODO: This needs to be moved when we start to support VMs with + * multiple threads since kvmArmVCpuInit requires that all CPUs in + * the VM have been created. + */ + struct kvm_vcpu_init target_config; + memset(&target_config, 0, sizeof(target_config)); + + vm.kvmArmPreferredTarget(target_config); + kvmArmVCpuInit(target_config); +} + +Tick +BaseArmKvmCPU::kvmRun(Tick ticks) +{ + bool simFIQ(interrupts->checkRaw(INT_FIQ)); + bool simIRQ(interrupts->checkRaw(INT_IRQ)); + + if (fiqAsserted != simFIQ) { + fiqAsserted = simFIQ; + DPRINTF(KvmInt, "KVM: Update FIQ state: %i\n", simFIQ); + vm.setIRQLine(INTERRUPT_VCPU_FIQ(vcpuID), simFIQ); + } + if (irqAsserted != simIRQ) { + irqAsserted = simIRQ; + DPRINTF(KvmInt, "KVM: Update IRQ state: %i\n", simIRQ); + vm.setIRQLine(INTERRUPT_VCPU_IRQ(vcpuID), simIRQ); + } + + return BaseKvmCPU::kvmRun(ticks); +} + +const BaseArmKvmCPU::RegIndexVector & +BaseArmKvmCPU::getRegList() const +{ + // Do we need to request a list of registers from the kernel? + if (_regIndexList.size() == 0) { + // Start by probing for the size of the list. We do this + // calling the ioctl with a struct size of 0. The kernel will + // return the number of elements required to hold the list. + kvm_reg_list regs_probe; + regs_probe.n = 0; + getRegList(regs_probe); + + // Request the actual register list now that we know how many + // register we need to allocate space for. + std::unique_ptr regs; + const size_t size(sizeof(struct kvm_reg_list) + + regs_probe.n * sizeof(uint64_t)); + regs.reset((struct kvm_reg_list *)operator new(size)); + regs->n = regs_probe.n; + if (!getRegList(*regs)) + panic("Failed to determine register list size.\n"); + + _regIndexList.assign(regs->reg, regs->reg + regs->n); + } + + return _regIndexList; +} + +void +BaseArmKvmCPU::kvmArmVCpuInit(const struct kvm_vcpu_init &init) +{ + if (ioctl(KVM_ARM_VCPU_INIT, (void *)&init) == -1) + panic("KVM: Failed to initialize vCPU\n"); +} + +bool +BaseArmKvmCPU::getRegList(struct kvm_reg_list ®s) const +{ + if (ioctl(KVM_GET_REG_LIST, (void *)®s) == -1) { + if (errno == E2BIG) { + return false; + } else { + panic("KVM: Failed to get vCPU register list (errno: %i)\n", + errno); + } + } else { + return true; + } +} diff --git a/src/arch/arm/kvm/base_cpu.hh b/src/arch/arm/kvm/base_cpu.hh new file mode 100644 index 000000000..736153b78 --- /dev/null +++ b/src/arch/arm/kvm/base_cpu.hh @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2012, 2015 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Andreas Sandberg + */ + +#ifndef __ARCH_ARM_KVM_BASE_CPU_HH__ +#define __ARCH_ARM_KVM_BASE_CPU_HH__ + +#include + +#include "cpu/kvm/base.hh" + +struct BaseArmKvmCPUParams; + +class BaseArmKvmCPU : public BaseKvmCPU +{ + public: + BaseArmKvmCPU(BaseArmKvmCPUParams *params); + virtual ~BaseArmKvmCPU(); + + void startup() M5_ATTR_OVERRIDE; + + protected: + Tick kvmRun(Tick ticks) M5_ATTR_OVERRIDE; + + + /** Cached state of the IRQ line */ + bool irqAsserted; + /** Cached state of the FIQ line */ + bool fiqAsserted; + + protected: + typedef std::vector RegIndexVector; + + /** + * Get a list of registers supported by getOneReg() and setOneReg(). + * + * This method returns a list of all registers supported by + * kvm. The actual list is only requested the first time this + * method is called. Subsequent calls return a cached copy of the + * register list. + * + * @return Vector of register indexes. + */ + const RegIndexVector &getRegList() const; + + /** + * Tell the kernel to initialize this CPU + * + * The kernel needs to know what type of the CPU that we want to + * emulate. The specified CPU type has to be compatible with the + * host CPU. In practice, we usually call + * KvmVM::kvmArmPreferredTarget() to discover the host CPU. + * + * @param target CPU type to emulate + */ + void kvmArmVCpuInit(const struct kvm_vcpu_init &init); + + private: + std::unique_ptr tryGetRegList(uint64_t nelem) const; + + /** + * Get a list of registers supported by getOneReg() and setOneReg(). + * + * @return False if the number of elements allocated in the list + * is too small to hold the complete register list (the required + * size is written to regs.n in this case). True on success. + */ + bool getRegList(struct kvm_reg_list ®s) const; + + /** + * Cached copy of the list of registers supported by KVM + */ + mutable RegIndexVector _regIndexList; +}; + +#endif // __ARCH_ARM_KVM_BASE_CPU_HH__ diff --git a/src/cpu/kvm/vm.cc b/src/cpu/kvm/vm.cc index a12374aa5..87a76c242 100644 --- a/src/cpu/kvm/vm.cc +++ b/src/cpu/kvm/vm.cc @@ -520,6 +520,17 @@ KvmVM::allocVCPUID() return nextVCPUID++; } +#if defined(__aarch64__) +void +KvmVM::kvmArmPreferredTarget(struct kvm_vcpu_init &target) const +{ + if (ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) { + panic("KVM: Failed to get ARM preferred CPU target (errno: %i)\n", + errno); + } +} +#endif + int KvmVM::ioctl(int request, long p1) const { diff --git a/src/cpu/kvm/vm.hh b/src/cpu/kvm/vm.hh index d21fc2660..8f834a06e 100644 --- a/src/cpu/kvm/vm.hh +++ b/src/cpu/kvm/vm.hh @@ -398,6 +398,23 @@ class KvmVM : public SimObject /** Global KVM interface */ Kvm kvm; +#if defined(__aarch64__) + public: // ARM-specific + /** + * Ask the kernel for the preferred CPU target to simulate. + * + * When creating an ARM vCPU in Kvm, we need to initialize it with + * a call to BaseArmKvmCPU::kvmArmVCpuInit(). When calling this + * function, we need to know what type of CPU the host has. This + * call sets up the kvm_vcpu_init structure with the values the + * kernel wants. + * + * @param[out] target Target structure to initialize. + */ + void kvmArmPreferredTarget(struct kvm_vcpu_init &target) const; + +#endif + protected: /** * VM CPU initialization code. -- 2.30.2 From 31825bd988fd512d822ee73a76d852c98fdf803d Mon Sep 17 00:00:00 2001 From: Curtis Dunham Date: Mon, 1 Jun 2015 18:05:11 -0500 Subject: [PATCH 02/16] sim, arm: add checkpoint upgrader for d02b45a5 The insertion of CONTEXTIDR_EL2 in the ARM miscellaneous registers obsoletes old checkpoints. --- src/sim/serialize.hh | 2 +- util/cpt_upgrader.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh index e9de6f713..888dba614 100644 --- a/src/sim/serialize.hh +++ b/src/sim/serialize.hh @@ -59,7 +59,7 @@ class EventQueue; * SimObject shouldn't cause the version number to increase, only changes to * existing objects such as serializing/unserializing more state, changing sizes * of serialized arrays, etc. */ -static const uint64_t gem5CheckpointVersion = 0x000000000000000d; +static const uint64_t gem5CheckpointVersion = 0x000000000000000e; template void paramOut(std::ostream &os, const std::string &name, const T ¶m); diff --git a/util/cpt_upgrader.py b/util/cpt_upgrader.py index 66c671025..5d836a23d 100755 --- a/util/cpt_upgrader.py +++ b/util/cpt_upgrader.py @@ -602,6 +602,18 @@ def from_C(cpt): cpt.set(sec, 'intRegs', ' '.join(intRegs)) cpt.set(sec, 'ccRegs', ' '.join(ccRegs)) +# Checkpoint version E adds the ARM CONTEXTIDR_EL2 miscreg. +def from_D(cpt): + if cpt.get('root','isa') == 'arm': + for sec in cpt.sections(): + import re + # Search for all ISA sections + if re.search('.*sys.*\.cpu.*\.isa$', sec): + miscRegs = cpt.get(sec, 'miscRegs').split() + # CONTEXTIDR_EL2 defaults to 0b11111100000000000001 + miscRegs[599:599] = [0xFC001] + cpt.set(sec, 'miscRegs', ' '.join(str(x) for x in miscRegs)) + migrations = [] migrations.append(from_0) migrations.append(from_1) @@ -616,6 +628,7 @@ migrations.append(from_9) migrations.append(from_A) migrations.append(from_B) migrations.append(from_C) +migrations.append(from_D) verbose_print = False -- 2.30.2 From 4a174947083b59cd76561ec0c41f23a95697b822 Mon Sep 17 00:00:00 2001 From: Christoph Pfister Date: Sat, 30 May 2015 13:45:17 +0200 Subject: [PATCH 03/16] mem: addr_mapper: restore old address if request not sent Committed by: Nilay Vaish --- src/mem/addr_mapper.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mem/addr_mapper.cc b/src/mem/addr_mapper.cc index 06237745b..2f0020576 100644 --- a/src/mem/addr_mapper.cc +++ b/src/mem/addr_mapper.cc @@ -128,9 +128,13 @@ AddrMapper::recvTimingReq(PacketPtr pkt) // packets) bool successful = masterPort.sendTimingReq(pkt); - // If not successful, restore the sender state - if (!successful && needsResponse) { - delete pkt->popSenderState(); + // If not successful, restore the address and sender state + if (!successful) { + pkt->setAddr(orig_addr); + + if (needsResponse) { + delete pkt->popSenderState(); + } } return successful; -- 2.30.2 From 736d3314bff0f3457ee9c86989a2942f4fbce510 Mon Sep 17 00:00:00 2001 From: "Ruslan Bukin ext:(%2C%20Zhang%20Guoye)" Date: Sun, 7 Jun 2015 14:02:40 -0500 Subject: [PATCH 04/16] arch: fix build under MacOSX put O_DIRECT under ifdefs -- this fixes build for MacOSX. Also use correct class for arm64 openFlagTable. Committed by: Nilay Vaish --- src/arch/arm/freebsd/freebsd.cc | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/arch/arm/freebsd/freebsd.cc b/src/arch/arm/freebsd/freebsd.cc index feee5686f..bb8514e96 100644 --- a/src/arch/arm/freebsd/freebsd.cc +++ b/src/arch/arm/freebsd/freebsd.cc @@ -47,7 +47,9 @@ OpenFlagTransTable ArmFreebsd32::openFlagTable[] = { { ArmFreebsd32::TGT_O_NONBLOCK, O_NONBLOCK }, { ArmFreebsd32::TGT_O_SYNC, O_SYNC }, { ArmFreebsd32::TGT_FASYNC, FASYNC }, +#ifdef O_DIRECT { ArmFreebsd32::TGT_O_DIRECT, O_DIRECT }, +#endif { ArmFreebsd32::TGT_O_DIRECTORY, O_DIRECTORY }, { ArmFreebsd32::TGT_O_NOFOLLOW, O_NOFOLLOW }, }; @@ -57,20 +59,22 @@ const int ArmFreebsd32::NUM_OPEN_FLAGS = sizeof(ArmFreebsd32::openFlagTable) / // open(2) flags translation table OpenFlagTransTable ArmFreebsd64::openFlagTable[] = { - { ArmFreebsd32::TGT_O_RDONLY, O_RDONLY }, - { ArmFreebsd32::TGT_O_WRONLY, O_WRONLY }, - { ArmFreebsd32::TGT_O_RDWR, O_RDWR }, - { ArmFreebsd32::TGT_O_CREAT, O_CREAT }, - { ArmFreebsd32::TGT_O_EXCL, O_EXCL }, - { ArmFreebsd32::TGT_O_NOCTTY, O_NOCTTY }, - { ArmFreebsd32::TGT_O_TRUNC, O_TRUNC }, - { ArmFreebsd32::TGT_O_APPEND, O_APPEND }, - { ArmFreebsd32::TGT_O_NONBLOCK, O_NONBLOCK }, - { ArmFreebsd32::TGT_O_SYNC, O_SYNC }, - { ArmFreebsd32::TGT_FASYNC, FASYNC }, - { ArmFreebsd32::TGT_O_DIRECT, O_DIRECT }, - { ArmFreebsd32::TGT_O_DIRECTORY, O_DIRECTORY }, - { ArmFreebsd32::TGT_O_NOFOLLOW, O_NOFOLLOW }, + { ArmFreebsd64::TGT_O_RDONLY, O_RDONLY }, + { ArmFreebsd64::TGT_O_WRONLY, O_WRONLY }, + { ArmFreebsd64::TGT_O_RDWR, O_RDWR }, + { ArmFreebsd64::TGT_O_CREAT, O_CREAT }, + { ArmFreebsd64::TGT_O_EXCL, O_EXCL }, + { ArmFreebsd64::TGT_O_NOCTTY, O_NOCTTY }, + { ArmFreebsd64::TGT_O_TRUNC, O_TRUNC }, + { ArmFreebsd64::TGT_O_APPEND, O_APPEND }, + { ArmFreebsd64::TGT_O_NONBLOCK, O_NONBLOCK }, + { ArmFreebsd64::TGT_O_SYNC, O_SYNC }, + { ArmFreebsd64::TGT_FASYNC, FASYNC }, +#ifdef O_DIRECT + { ArmFreebsd64::TGT_O_DIRECT, O_DIRECT }, +#endif + { ArmFreebsd64::TGT_O_DIRECTORY, O_DIRECTORY }, + { ArmFreebsd64::TGT_O_NOFOLLOW, O_NOFOLLOW }, }; const int ArmFreebsd64::NUM_OPEN_FLAGS = sizeof(ArmFreebsd64::openFlagTable) / -- 2.30.2 From 25fe4c25291db84c314ed979b3afbb49a3fa7306 Mon Sep 17 00:00:00 2001 From: Matthias Jung Date: Sun, 7 Jun 2015 14:02:40 -0500 Subject: [PATCH 05/16] mem: Add HMC Timing Parameters A single HMC-2500 x32 model based on: [1] DRAMSpec: a high-level DRAM bank modelling tool developed at the University of Kaiserslautern. This high level tool uses RC (resistance-capacitance) and CV (capacitance-voltage) models to estimate the DRAM bank latency and power numbers. [2] A Logic-base Interconnect for Supporting Near Memory Computation in the Hybrid Memory Cube (E. Azarkhish et. al) Assumed for the HMC model is a 30 nm technology node. The modelled HMC consists of a 4 Gbit part with 4 layers connected with TSVs. Each layer has 16 vaults and each vault consists of 2 banks per layer. In order to be able to use the same controller used for 2D DRAM generations for HMC, the following analogy is done: Channel (DDR) => Vault (HMC) device_size (DDR) => size of a single layer in a vault ranks per channel (DDR) => number of layers banks per rank (DDR) => banks per layer devices per rank (DDR) => devices per layer ( 1 for HMC). The parameters for which no input is available are inherited from the DDR3 configuration. --- src/mem/DRAMCtrl.py | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/mem/DRAMCtrl.py b/src/mem/DRAMCtrl.py index 60b3b251e..ef187a31c 100644 --- a/src/mem/DRAMCtrl.py +++ b/src/mem/DRAMCtrl.py @@ -11,6 +11,7 @@ # modified or unmodified, in source code or in binary form. # # Copyright (c) 2013 Amin Farmahini-Farahani +# Copyright (c) 2015 University of Kaiserslautern # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -38,6 +39,8 @@ # # Authors: Andreas Hansson # Ani Udipi +# Omar Naji +# Matthias Jung from m5.params import * from AbstractMemory import * @@ -374,6 +377,92 @@ class DDR3_1600_x64(DRAMCtrl): IDD5 = '220mA' VDD = '1.5V' +# A single HMC-2500 x32 model based on: +# [1] DRAMSpec: a high-level DRAM bank modelling tool +# developed at the University of Kaiserslautern. This high level tool +# uses RC (resistance-capacitance) and CV (capacitance-voltage) models to +# estimate the DRAM bank latency and power numbers. +# [2] A Logic-base Interconnect for Supporting Near Memory Computation in the +# Hybrid Memory Cube (E. Azarkhish et. al) +# Assumed for the HMC model is a 30 nm technology node. +# The modelled HMC consists of 4 Gbit layers which sum up to 2GB of memory (4 +# layers). +# Each layer has 16 vaults and each vault consists of 2 banks per layer. +# In order to be able to use the same controller used for 2D DRAM generations +# for HMC, the following analogy is done: +# Channel (DDR) => Vault (HMC) +# device_size (DDR) => size of a single layer in a vault +# ranks per channel (DDR) => number of layers +# banks per rank (DDR) => banks per layer +# devices per rank (DDR) => devices per layer ( 1 for HMC). +# The parameters for which no input is available are inherited from the DDR3 +# configuration. +# This configuration includes the latencies from the DRAM to the logic layer of +# the HMC +class HMC_2500_x32(DDR3_1600_x64): + # size of device + # two banks per device with each bank 4MB [2] + device_size = '8MB' + + # 1x32 configuration, 1 device with 32 TSVs [2] + device_bus_width = 32 + + # HMC is a BL8 device [2] + burst_length = 8 + + # Each device has a page (row buffer) size of 256 bytes [2] + device_rowbuffer_size = '256B' + + # 1x32 configuration, so 1 device [2] + devices_per_rank = 1 + + # 4 layers so 4 ranks [2] + ranks_per_channel = 4 + + # HMC has 2 banks per layer [2] + # Each layer represents a rank. With 4 layers and 8 banks in total, each + # layer has 2 banks; thus 2 banks per rank. + banks_per_rank = 2 + + # 1250 MHz [2] + tCK = '0.8ns' + + # 8 beats across an x32 interface translates to 4 clocks @ 1250 MHz + tBURST = '3.2ns' + + # Values using DRAMSpec HMC model [1] + tRCD = '10.2ns' + tCL = '9.9ns' + tRP = '7.7ns' + tRAS = '21.6ns' + + # tRRD depends on the power supply network for each vendor. + # We assume a tRRD of a double bank approach to be equal to 4 clock + # cycles (Assumption) + tRRD = '3.2ns' + + # activation limit is set to 0 since there are only 2 banks per vault layer. + activation_limit = 0 + + # Values using DRAMSpec HMC model [1] + tRFC = '59ns' + tWR = '8ns' + tRTP = '4.9ns' + + # Default different rank bus delay assumed to 1 CK for TSVs, @1250 MHz = 0.8 + # ns (Assumption) + tCS = '0.8ns' + + # Value using DRAMSpec HMC model [1] + tREFI = '3.9us' + + # Set default controller parameters + page_policy = 'close' + write_buffer_size = 8 + read_buffer_size = 8 + addr_mapping = 'RoCoRaBaCh' + min_writes_per_switch = 8 + # A single DDR3-2133 x64 channel refining a selected subset of the # options for the DDR-1600 configuration, based on the same DDR3-1600 # 4 Gbit datasheet (Micron MT41J512M8). Most parameters are kept -- 2.30.2 From 6599dd87c8332e4db3d898c9a28531ce2740c37f Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Sun, 7 Jun 2015 14:02:40 -0500 Subject: [PATCH 06/16] ruby: Fix MESI consistency bug Fixes missed forward eviction to CPU. With the O3CPU this can lead to load-load reordering, as the LQ is never notified of the invalidate. Committed by: Nilay Vaish --- src/mem/protocol/MESI_Two_Level-L1cache.sm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mem/protocol/MESI_Two_Level-L1cache.sm b/src/mem/protocol/MESI_Two_Level-L1cache.sm index b449c4f2b..4f9928bf1 100644 --- a/src/mem/protocol/MESI_Two_Level-L1cache.sm +++ b/src/mem/protocol/MESI_Two_Level-L1cache.sm @@ -1341,6 +1341,7 @@ machine(L1Cache, "MESI Directory L1 Cache CMP") // transitions from SM transition(SM, Inv, IM) { + forward_eviction_to_cpu; fi_sendInvAck; dg_invalidate_sc; l_popRequestQueue; -- 2.30.2 From b29e55d44a70de6ed126a03fcd938bfe34a3a8a5 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 9 Jun 2015 09:21:11 -0400 Subject: [PATCH 07/16] scons: Allow GNU assembler version strings with hyphen Make scons a bit more forgiving when determining the GNU assembler version. --- SConstruct | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/SConstruct b/SConstruct index d229960c2..981cd0da9 100755 --- a/SConstruct +++ b/SConstruct @@ -599,10 +599,16 @@ if main['GCC']: # assemblers detect this as an error, "Error: expecting string # instruction after `rep'" if compareVersions(gcc_version, "4.8") > 0: - as_version = readCommand([main['AS'], '-v', '/dev/null'], - exception=False).split() + as_version_raw = readCommand([main['AS'], '-v', '/dev/null'], + exception=False).split() - if not as_version or compareVersions(as_version[-1], "2.23") < 0: + # version strings may contain extra distro-specific + # qualifiers, so play it safe and keep only what comes before + # the first hyphen + as_version = as_version_raw[-1].split('-')[0] if as_version_raw \ + else None + + if not as_version or compareVersions(as_version, "2.23") < 0: print termcap.Yellow + termcap.Bold + \ 'Warning: This combination of gcc and binutils have' + \ ' known incompatibilities.\n' + \ -- 2.30.2 From a9cad92011560fe03c7d6ffde6d679cc84e48816 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Tue, 9 Jun 2015 09:21:12 -0400 Subject: [PATCH 08/16] dev, arm: Include PIO size in AmbaDmaDevice constructor Make it possible to specify the size of the PIO space for an AMBA DMA device. Maintain backwards compatibility and default to zero. --- src/dev/arm/amba_device.cc | 4 ++-- src/dev/arm/amba_device.hh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dev/arm/amba_device.cc b/src/dev/arm/amba_device.cc index 0ba20d087..540d09615 100644 --- a/src/dev/arm/amba_device.cc +++ b/src/dev/arm/amba_device.cc @@ -62,9 +62,9 @@ AmbaIntDevice::AmbaIntDevice(const Params *p, Addr pio_size) -AmbaDmaDevice::AmbaDmaDevice(const Params *p) +AmbaDmaDevice::AmbaDmaDevice(const Params *p, Addr pio_size) : DmaDevice(p), ambaId(AmbaVendor | p->amba_id), - pioAddr(p->pio_addr), pioSize(0), + pioAddr(p->pio_addr), pioSize(pio_size), pioDelay(p->pio_latency),intNum(p->int_num), gic(p->gic) { } diff --git a/src/dev/arm/amba_device.hh b/src/dev/arm/amba_device.hh index 3915e436c..869126146 100644 --- a/src/dev/arm/amba_device.hh +++ b/src/dev/arm/amba_device.hh @@ -109,7 +109,7 @@ class AmbaDmaDevice : public DmaDevice, public AmbaDevice public: typedef AmbaDmaDeviceParams Params; - AmbaDmaDevice(const Params *p); + AmbaDmaDevice(const Params *p, Addr pio_size = 0); }; -- 2.30.2 From 737e5da7f6a4716803e489f473fa4d58579fbd58 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Tue, 9 Jun 2015 09:21:14 -0400 Subject: [PATCH 09/16] base: Reset CircleBuf size on flush() The flush() method in CircleBuf resets the state of the circular buffer, but fails to set size to zero. This obviously confuses code that tries to determine the amount of data in the buffer. Set the size to zero on flush. --- src/base/circlebuf.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc index 06d0075b2..2f04bc16e 100644 --- a/src/base/circlebuf.cc +++ b/src/base/circlebuf.cc @@ -67,6 +67,7 @@ CircleBuf::flush() { _start = 0; _stop = 0; + _size = 0; _rollover = false; } -- 2.30.2 From f4311d393295468389a7093e0e78d7f93f802a49 Mon Sep 17 00:00:00 2001 From: Rune Holm Date: Tue, 9 Jun 2015 09:21:15 -0400 Subject: [PATCH 10/16] arm: Fix typo in ldrsh instruction name ldrsh was typoed as hdrsh, which is a bit annoying when printing instructions. This patch fixes it. --- src/arch/arm/isa/insts/ldr.isa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/arm/isa/insts/ldr.isa b/src/arch/arm/isa/insts/ldr.isa index 6bfe40118..3edeb3805 100644 --- a/src/arch/arm/isa/insts/ldr.isa +++ b/src/arch/arm/isa/insts/ldr.isa @@ -349,7 +349,7 @@ let {{ buildLoads("ldrsbt", size=1, sign=True, user=True) buildLoads("ldrh", size=2) buildLoads("ldrht", size=2, user=True) - buildLoads("hdrsh", size=2, sign=True) + buildLoads("ldrsh", size=2, sign=True) buildLoads("ldrsht", size=2, sign=True, user=True) buildDoubleLoads("ldrd") -- 2.30.2 From eb3ed11794667975476a4ec3b070e215c2c5dc12 Mon Sep 17 00:00:00 2001 From: Rune Holm Date: Tue, 9 Jun 2015 09:21:16 -0400 Subject: [PATCH 11/16] arm: Delete debug print in initialization of hardware thread There seems to have been a debug print left in when the original ARMv8 support was merged in. This printout is performed every time you initialize a hardware thread, and it prints raw pointers, so it always causes diffs in the regression. This patch removes the debug print. --- src/arch/arm/isa.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index 2120c56db..bac7bab89 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -144,7 +144,6 @@ ISA::ISA(Params *p) pmu->setISA(this); system = dynamic_cast(p->system); - DPRINTFN("ISA system set to: %p %p\n", system, p->system); // Cache system-level properties if (FullSystem && system) { -- 2.30.2 From 578a7f20c647e4051e137bdb219cec450a741ca6 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Tue, 9 Jun 2015 09:21:17 -0400 Subject: [PATCH 12/16] mem: Fix snoop packet data allocation bug This patch fixes an issue where the snoop packet did not properly forward the data pointer in case of static data. --- src/mem/cache/cache_impl.hh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 734ca826c..9c5070ffa 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -1610,7 +1610,11 @@ Cache::handleSnoop(PacketPtr pkt, CacheBlk *blk, bool is_timing, // rewritten to be relative to cpu-side bus (if any) bool alreadyResponded = pkt->memInhibitAsserted(); if (is_timing) { - Packet snoopPkt(pkt, true, false); // clear flags, no allocation + // copy the packet so that we can clear any flags before + // forwarding it upwards, we also allocate data (passing + // the pointer along in case of static data), in case + // there is a snoop hit in upper levels + Packet snoopPkt(pkt, true, true); snoopPkt.setExpressSnoop(); snoopPkt.pushSenderState(new ForwardResponseRecord()); // the snoop packet does not need to wait any additional @@ -1622,6 +1626,8 @@ Cache::handleSnoop(PacketPtr pkt, CacheBlk *blk, bool is_timing, assert(!alreadyResponded); pkt->assertMemInhibit(); } else { + // no cache (or anyone else for that matter) will + // respond, so delete the ForwardResponseRecord here delete snoopPkt.popSenderState(); } if (snoopPkt.sharedAsserted()) { -- 2.30.2 From f0c3b704516362f11b0ec53a2f7dae8854349ac4 Mon Sep 17 00:00:00 2001 From: Ali Jafri Date: Tue, 9 Jun 2015 09:21:18 -0400 Subject: [PATCH 13/16] mem: Add check for express snoop in packet destructor Snoop packets share the request pointer with the originating packets. We need to ensure that the snoop packet destruction does not delete the request. Snoops are used for reads, invalidations, HardPFReqs, Writebacks and CleansEvicts. Reads, invalidations, and HardPFReqs need a response so their snoops do not delete the request. For Writebacks and CleanEvicts we need to check explicitly for whethere the current packet is an express snoop, in whcih case do not delete the request. --- src/mem/packet.hh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 10a4f7e89..3f10458e7 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -692,11 +692,18 @@ class Packet : public Printable */ ~Packet() { - // If this is a request packet for which there's no response, - // delete the request object here, since the requester will - // never get the chance. - if (req && isRequest() && !needsResponse()) + // Delete the request object if this is a request packet which + // does not need a response, because the requester will not get + // a chance. If the request packet needs a response then the + // request will be deleted on receipt of the response + // packet. We also make sure to never delete the request for + // express snoops, even for cases when responses are not + // needed (CleanEvict and Writeback), since the snoop packet + // re-uses the same request. + if (req && isRequest() && !needsResponse() && + !isExpressSnoop()) { delete req; + } deleteData(); } -- 2.30.2 From d541038549966dcfc8f5923fd8550021b3d72d91 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Sun, 21 Jun 2015 20:48:33 +0100 Subject: [PATCH 14/16] arm: Cleanup arch headers to remove dma_device.hh dependency Break the dependency on dma_device.hh by forward-declaring DmaPort in the relevant header. --- src/arch/arm/stage2_mmu.cc | 1 + src/arch/arm/stage2_mmu.hh | 1 + src/arch/arm/table_walker.cc | 3 ++- src/arch/arm/table_walker.hh | 3 ++- src/arch/arm/tlb.cc | 3 ++- src/arch/arm/tlb.hh | 1 - 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/arch/arm/stage2_mmu.cc b/src/arch/arm/stage2_mmu.cc index b7f3d07ab..3525768e0 100755 --- a/src/arch/arm/stage2_mmu.cc +++ b/src/arch/arm/stage2_mmu.cc @@ -38,6 +38,7 @@ */ #include "arch/arm/stage2_mmu.hh" + #include "arch/arm/faults.hh" #include "arch/arm/system.hh" #include "arch/arm/table_walker.hh" diff --git a/src/arch/arm/stage2_mmu.hh b/src/arch/arm/stage2_mmu.hh index 132d1b7f5..b42f213e8 100755 --- a/src/arch/arm/stage2_mmu.hh +++ b/src/arch/arm/stage2_mmu.hh @@ -42,6 +42,7 @@ #include "arch/arm/faults.hh" #include "arch/arm/tlb.hh" +#include "dev/dma_device.hh" #include "mem/request.hh" #include "params/ArmStage2MMU.hh" #include "sim/eventq.hh" diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index e92971b7d..f58d8a268 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -37,13 +37,13 @@ * Authors: Ali Saidi * Giacomo Gabrielli */ +#include "arch/arm/table_walker.hh" #include #include "arch/arm/faults.hh" #include "arch/arm/stage2_mmu.hh" #include "arch/arm/system.hh" -#include "arch/arm/table_walker.hh" #include "arch/arm/tlb.hh" #include "cpu/base.hh" #include "cpu/thread_context.hh" @@ -51,6 +51,7 @@ #include "debug/Drain.hh" #include "debug/TLB.hh" #include "debug/TLBVerbose.hh" +#include "dev/dma_device.hh" #include "sim/system.hh" using namespace ArmISA; diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index d9245d595..a5327cd95 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -46,13 +46,14 @@ #include "arch/arm/miscregs.hh" #include "arch/arm/system.hh" #include "arch/arm/tlb.hh" -#include "dev/dma_device.hh" #include "mem/request.hh" #include "params/ArmTableWalker.hh" #include "sim/eventq.hh" class ThreadContext; +class DmaPort; + namespace ArmISA { class Translation; class TLB; diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index dfda14d30..9a706a166 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -42,6 +42,8 @@ * Steve Reinhardt */ +#include "arch/arm/tlb.hh" + #include #include #include @@ -52,7 +54,6 @@ #include "arch/arm/table_walker.hh" #include "arch/arm/stage2_lookup.hh" #include "arch/arm/stage2_mmu.hh" -#include "arch/arm/tlb.hh" #include "arch/arm/utility.hh" #include "base/inifile.hh" #include "base/str.hh" diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index fba5775aa..5d418ef17 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -50,7 +50,6 @@ #include "arch/arm/vtophys.hh" #include "arch/generic/tlb.hh" #include "base/statistics.hh" -#include "dev/dma_device.hh" #include "mem/request.hh" #include "params/ArmTLB.hh" #include "sim/probe/pmu.hh" -- 2.30.2 From cc813cd5f73ea37173ebda761ebdd4184bf99254 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Sun, 21 Jun 2015 20:52:13 +0100 Subject: [PATCH 15/16] base: Add a warn_if macro Add a warn if macro that is analogous to the panic_if and fatal_if. --- src/base/misc.hh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/base/misc.hh b/src/base/misc.hh index 5f89e5f1d..b62548eb2 100644 --- a/src/base/misc.hh +++ b/src/base/misc.hh @@ -218,6 +218,20 @@ extern bool want_hack, hack_verbose; #define hack_once(...) \ cond_message_once(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__) +/** + * Conditional warning macro that checks the supplied condition and + * only prints a warning if the condition is true. Useful to replace + * if + warn. + * + * @param cond Condition that is checked; if true -> warn + * @param ... Printf-based format string with arguments, extends printout. + */ +#define warn_if(cond, ...) \ + do { \ + if ((cond)) \ + warn(__VA_ARGS__); \ + } while (0) + /** * The chatty assert macro will function like a normal assert, but will allow the * specification of additional, helpful material to aid debugging why the -- 2.30.2 From 2f3c4678839b9bf52cdbcb447009ebaa63f50713 Mon Sep 17 00:00:00 2001 From: Jason Power Date: Thu, 25 Jun 2015 11:58:28 -0500 Subject: [PATCH 16/16] Ruby: Remove assert in RubyPort retry list logic Remove the assert when adding a port to the RubyPort retry list. Instead of asserting, just ignore the added port, since it's already on the list. Without this patch, Ruby+detailed fails for even the simplest tests --- src/mem/ruby/system/RubyPort.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh index 2fb31ca09..e68af6dab 100644 --- a/src/mem/ruby/system/RubyPort.hh +++ b/src/mem/ruby/system/RubyPort.hh @@ -188,8 +188,8 @@ class RubyPort : public MemObject private: void addToRetryList(MemSlavePort * port) { - assert(std::find(retryList.begin(), retryList.end(), port) == - retryList.end()); + if (std::find(retryList.begin(), retryList.end(), port) != + retryList.end()) return; retryList.push_back(port); } -- 2.30.2