From patchwork Wed Feb 3 17:16:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hogan X-Patchwork-Id: 578248 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id AE11114031E for ; Thu, 4 Feb 2016 04:18:17 +1100 (AEDT) Received: from localhost ([::1]:36580 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aR14J-0004m8-3V for incoming@patchwork.ozlabs.org; Wed, 03 Feb 2016 12:18:15 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37550) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aR13P-0002yQ-FX for qemu-devel@nongnu.org; Wed, 03 Feb 2016 12:17:20 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aR13N-00027b-Sc for qemu-devel@nongnu.org; Wed, 03 Feb 2016 12:17:19 -0500 Received: from mailapp01.imgtec.com ([195.59.15.196]:35474) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aR13N-00027J-7J for qemu-devel@nongnu.org; Wed, 03 Feb 2016 12:17:17 -0500 Received: from hhmail02.hh.imgtec.org (unknown [10.100.10.20]) by Websense Email Security Gateway with ESMTPS id 03B172540629; Wed, 3 Feb 2016 17:17:12 +0000 (GMT) Received: from LEMAIL01.le.imgtec.org (192.168.152.62) by hhmail02.hh.imgtec.org (10.100.10.20) with Microsoft SMTP Server (TLS) id 14.3.266.1; Wed, 3 Feb 2016 17:17:14 +0000 Received: from jhogan-linux.le.imgtec.org (192.168.154.110) by LEMAIL01.le.imgtec.org (192.168.152.62) with Microsoft SMTP Server (TLS) id 14.3.210.2; Wed, 3 Feb 2016 17:17:14 +0000 From: James Hogan To: , Leon Alrae Date: Wed, 3 Feb 2016 17:16:53 +0000 Message-ID: <1454519813-18797-8-git-send-email-james.hogan@imgtec.com> X-Mailer: git-send-email 2.4.10 In-Reply-To: <1454519813-18797-1-git-send-email-james.hogan@imgtec.com> References: <1454519813-18797-1-git-send-email-james.hogan@imgtec.com> MIME-Version: 1.0 X-Originating-IP: [192.168.154.110] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.59.15.196 Cc: Paolo Bonzini , James Hogan , Aurelien Jarno , kvm@vger.kernel.org Subject: [Qemu-devel] [PATCH v5 7/7] mips/kvm: Support MSA in MIPS KVM guests X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Support the new KVM_CAP_MIPS_MSA capability, which allows MIPS SIMD Architecture (MSA) to be exposed to the KVM guest. The capability is enabled if the guest core has MSA according to its Config3 register. Various config bits are now writeable so that KVM is aware of the configuration (Config3.MSAP) and so that QEMU can save/restore the guest modifiable bits (Config5.MSAEn). The MSACSR/MSAIR registers and the MSA vector registers are now saved/restored. Since the FP registers are a subset of the vector registers, they are omitted if the guest has MSA. Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Leon Alrae Cc: Aurelien Jarno --- Changes in v5: - Restore MSA FP state using restore_msa_fp_status(env) (Leon). Changes in v2: - Change (1 << x) to (1U << x) in important places to avoid compiler undefined behaviour (Leon). - Removed update of linux-headers/linux/kvm.h (Paolo). --- target-mips/kvm.c | 129 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 20 deletions(-) diff --git a/target-mips/kvm.c b/target-mips/kvm.c index a1f5b6012edd..950bc05b7c32 100644 --- a/target-mips/kvm.c +++ b/target-mips/kvm.c @@ -31,6 +31,7 @@ do { if (DEBUG_KVM) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) static int kvm_mips_fpu_cap; +static int kvm_mips_msa_cap; const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO @@ -49,6 +50,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) kvm_set_sigmask_len(s, 16); kvm_mips_fpu_cap = kvm_check_extension(s, KVM_CAP_MIPS_FPU); + kvm_mips_msa_cap = kvm_check_extension(s, KVM_CAP_MIPS_MSA); DPRINTF("%s\n", __func__); return 0; @@ -71,6 +73,15 @@ int kvm_arch_init_vcpu(CPUState *cs) } } + if (kvm_mips_msa_cap && env->CP0_Config3 & (1 << CP0C3_MSAP)) { + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_MIPS_MSA, 0, 0); + if (ret < 0) { + /* mark unsupported so it gets disabled on reset */ + kvm_mips_msa_cap = 0; + ret = 0; + } + } + DPRINTF("%s\n", __func__); return ret; } @@ -83,6 +94,10 @@ void kvm_mips_reset_vcpu(MIPSCPU *cpu) fprintf(stderr, "Warning: KVM does not support FPU, disabling\n"); env->CP0_Config1 &= ~(1 << CP0C1_FP); } + if (!kvm_mips_msa_cap && env->CP0_Config3 & (1 << CP0C3_MSAP)) { + fprintf(stderr, "Warning: KVM does not support MSA, disabling\n"); + env->CP0_Config3 &= ~(1 << CP0C3_MSAP); + } DPRINTF("%s\n", __func__); } @@ -373,9 +388,11 @@ static inline int kvm_mips_get_one_ureg64(CPUState *cs, uint64_t reg_id, #define KVM_REG_MIPS_CP0_CONFIG1_MASK ((1U << CP0C1_M) | \ (1U << CP0C1_FP)) #define KVM_REG_MIPS_CP0_CONFIG2_MASK (1U << CP0C2_M) -#define KVM_REG_MIPS_CP0_CONFIG3_MASK (1U << CP0C3_M) +#define KVM_REG_MIPS_CP0_CONFIG3_MASK ((1U << CP0C3_M) | \ + (1U << CP0C3_MSAP)) #define KVM_REG_MIPS_CP0_CONFIG4_MASK (1U << CP0C4_M) -#define KVM_REG_MIPS_CP0_CONFIG5_MASK ((1U << CP0C5_UFE) | \ +#define KVM_REG_MIPS_CP0_CONFIG5_MASK ((1U << CP0C5_MSAEn) | \ + (1U << CP0C5_UFE) | \ (1U << CP0C5_FRE) | \ (1U << CP0C5_UFR)) @@ -564,17 +581,53 @@ static int kvm_mips_put_fpu_registers(CPUState *cs, int level) ret = err; } - /* Floating point registers */ + /* + * FPU register state is a subset of MSA vector state, so don't put FPU + * registers if we're emulating a CPU with MSA. + */ + if (!(env->CP0_Config3 & (1 << CP0C3_MSAP))) { + /* Floating point registers */ + for (i = 0; i < 32; ++i) { + if (env->CP0_Status & (1 << CP0St_FR)) { + err = kvm_mips_put_one_ureg64(cs, KVM_REG_MIPS_FPR_64(i), + &env->active_fpu.fpr[i].d); + } else { + err = kvm_mips_get_one_ureg(cs, KVM_REG_MIPS_FPR_32(i), + &env->active_fpu.fpr[i].w[FP_ENDIAN_IDX]); + } + if (err < 0) { + DPRINTF("%s: Failed to put FPR%u (%d)\n", __func__, i, err); + ret = err; + } + } + } + } + + /* Only put MSA state if we're emulating a CPU with MSA */ + if (env->CP0_Config3 & (1 << CP0C3_MSAP)) { + /* MSA Control Registers */ + if (level == KVM_PUT_FULL_STATE) { + err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_MSA_IR, + &env->msair); + if (err < 0) { + DPRINTF("%s: Failed to put MSA_IR (%d)\n", __func__, err); + ret = err; + } + } + err = kvm_mips_put_one_reg(cs, KVM_REG_MIPS_MSA_CSR, + &env->active_tc.msacsr); + if (err < 0) { + DPRINTF("%s: Failed to put MSA_CSR (%d)\n", __func__, err); + ret = err; + } + + /* Vector registers (includes FP registers) */ for (i = 0; i < 32; ++i) { - if (env->CP0_Status & (1 << CP0St_FR)) { - err = kvm_mips_put_one_ureg64(cs, KVM_REG_MIPS_FPR_64(i), - &env->active_fpu.fpr[i].d); - } else { - err = kvm_mips_get_one_ureg(cs, KVM_REG_MIPS_FPR_32(i), - &env->active_fpu.fpr[i].w[FP_ENDIAN_IDX]); - } + /* Big endian MSA not supported by QEMU yet anyway */ + err = kvm_mips_put_one_reg64(cs, KVM_REG_MIPS_VEC_128(i), + env->active_fpu.fpr[i].wr.d); if (err < 0) { - DPRINTF("%s: Failed to put FPR%u (%d)\n", __func__, i, err); + DPRINTF("%s: Failed to put VEC%u (%d)\n", __func__, i, err); ret = err; } } @@ -608,17 +661,53 @@ static int kvm_mips_get_fpu_registers(CPUState *cs) restore_fp_status(env); } - /* Floating point registers */ - for (i = 0; i < 32; ++i) { - if (env->CP0_Status & (1 << CP0St_FR)) { - err = kvm_mips_get_one_ureg64(cs, KVM_REG_MIPS_FPR_64(i), - &env->active_fpu.fpr[i].d); - } else { - err = kvm_mips_get_one_ureg(cs, KVM_REG_MIPS_FPR_32(i), - &env->active_fpu.fpr[i].w[FP_ENDIAN_IDX]); + /* + * FPU register state is a subset of MSA vector state, so don't save FPU + * registers if we're emulating a CPU with MSA. + */ + if (!(env->CP0_Config3 & (1 << CP0C3_MSAP))) { + /* Floating point registers */ + for (i = 0; i < 32; ++i) { + if (env->CP0_Status & (1 << CP0St_FR)) { + err = kvm_mips_get_one_ureg64(cs, KVM_REG_MIPS_FPR_64(i), + &env->active_fpu.fpr[i].d); + } else { + err = kvm_mips_get_one_ureg(cs, KVM_REG_MIPS_FPR_32(i), + &env->active_fpu.fpr[i].w[FP_ENDIAN_IDX]); + } + if (err < 0) { + DPRINTF("%s: Failed to get FPR%u (%d)\n", __func__, i, err); + ret = err; + } } + } + } + + /* Only get MSA state if we're emulating a CPU with MSA */ + if (env->CP0_Config3 & (1 << CP0C3_MSAP)) { + /* MSA Control Registers */ + err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_MSA_IR, + &env->msair); + if (err < 0) { + DPRINTF("%s: Failed to get MSA_IR (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_reg(cs, KVM_REG_MIPS_MSA_CSR, + &env->active_tc.msacsr); + if (err < 0) { + DPRINTF("%s: Failed to get MSA_CSR (%d)\n", __func__, err); + ret = err; + } else { + restore_msa_fp_status(env); + } + + /* Vector registers (includes FP registers) */ + for (i = 0; i < 32; ++i) { + /* Big endian MSA not supported by QEMU yet anyway */ + err = kvm_mips_get_one_reg64(cs, KVM_REG_MIPS_VEC_128(i), + env->active_fpu.fpr[i].wr.d); if (err < 0) { - DPRINTF("%s: Failed to get FPR%u (%d)\n", __func__, i, err); + DPRINTF("%s: Failed to get VEC%u (%d)\n", __func__, i, err); ret = err; } }