From patchwork Wed Feb 3 17:16:52 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Hogan X-Patchwork-Id: 8205711 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 7E6AE9F6DA for ; Wed, 3 Feb 2016 17:17:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6E54C20266 for ; Wed, 3 Feb 2016 17:17:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5160C20279 for ; Wed, 3 Feb 2016 17:17:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933540AbcBCRRX (ORCPT ); Wed, 3 Feb 2016 12:17:23 -0500 Received: from mailapp01.imgtec.com ([195.59.15.196]:35379 "EHLO mailapp01.imgtec.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933788AbcBCRRR (ORCPT ); Wed, 3 Feb 2016 12:17:17 -0500 Received: from HHMAIL01.hh.imgtec.org (unknown [10.100.10.19]) by Websense Email Security Gateway with ESMTPS id 3C442243F3FB3; Wed, 3 Feb 2016 17:17:11 +0000 (GMT) Received: from LEMAIL01.le.imgtec.org (192.168.152.62) by HHMAIL01.hh.imgtec.org (10.100.10.19) 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:13 +0000 From: James Hogan To: , Leon Alrae CC: Paolo Bonzini , , Aurelien Jarno , James Hogan Subject: [PATCH v5 6/7] mips/kvm: Support FPU in MIPS KVM guests Date: Wed, 3 Feb 2016 17:16:52 +0000 Message-ID: <1454519813-18797-7-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] Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Support the new KVM_CAP_MIPS_FPU capability, which allows the host's FPU to be exposed to the KVM guest. The capability is enabled if the guest core has an FPU according to its Config1 register. Various config bits are now writeable so that KVM is aware of the configuration (Config1.FP) and so that QEMU can save/restore the guest modifiable bits (Config5.FRE, Config5.UFR, Config5.UFE). The FCSR/FIR registers and the floating point registers are now saved/restored (depending on the FR mode bit). Signed-off-by: James Hogan Cc: Paolo Bonzini Cc: Leon Alrae Cc: Aurelien Jarno --- Changes in v5: - Use restore_fp_status(env). 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 | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 4 deletions(-) diff --git a/target-mips/kvm.c b/target-mips/kvm.c index a297b5a58339..a1f5b6012edd 100644 --- a/target-mips/kvm.c +++ b/target-mips/kvm.c @@ -30,6 +30,8 @@ #define DPRINTF(fmt, ...) \ do { if (DEBUG_KVM) { fprintf(stderr, fmt, ## __VA_ARGS__); } } while (0) +static int kvm_mips_fpu_cap; + const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -46,16 +48,29 @@ int kvm_arch_init(MachineState *ms, KVMState *s) /* MIPS has 128 signals */ kvm_set_sigmask_len(s, 16); + kvm_mips_fpu_cap = kvm_check_extension(s, KVM_CAP_MIPS_FPU); + DPRINTF("%s\n", __func__); return 0; } int kvm_arch_init_vcpu(CPUState *cs) { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; int ret = 0; qemu_add_vm_change_state_handler(kvm_mips_update_state, cs); + if (kvm_mips_fpu_cap && env->CP0_Config1 & (1 << CP0C1_FP)) { + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_MIPS_FPU, 0, 0); + if (ret < 0) { + /* mark unsupported so it gets disabled on reset */ + kvm_mips_fpu_cap = 0; + ret = 0; + } + } + DPRINTF("%s\n", __func__); return ret; } @@ -64,8 +79,8 @@ void kvm_mips_reset_vcpu(MIPSCPU *cpu) { CPUMIPSState *env = &cpu->env; - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - fprintf(stderr, "Warning: FPU not supported with KVM, disabling\n"); + if (!kvm_mips_fpu_cap && env->CP0_Config1 & (1 << CP0C1_FP)) { + fprintf(stderr, "Warning: KVM does not support FPU, disabling\n"); env->CP0_Config1 &= ~(1 << CP0C1_FP); } @@ -355,11 +370,14 @@ static inline int kvm_mips_get_one_ureg64(CPUState *cs, uint64_t reg_id, } #define KVM_REG_MIPS_CP0_CONFIG_MASK (1U << CP0C0_M) -#define KVM_REG_MIPS_CP0_CONFIG1_MASK (1U << CP0C1_M) +#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_CONFIG4_MASK (1U << CP0C4_M) -#define KVM_REG_MIPS_CP0_CONFIG5_MASK 0 +#define KVM_REG_MIPS_CP0_CONFIG5_MASK ((1U << CP0C5_UFE) | \ + (1U << CP0C5_FRE) | \ + (1U << CP0C5_UFR)) static inline int kvm_mips_change_one_reg(CPUState *cs, uint64_t reg_id, int32_t *addr, int32_t mask) @@ -521,6 +539,95 @@ static void kvm_mips_update_state(void *opaque, int running, RunState state) } } +static int kvm_mips_put_fpu_registers(CPUState *cs, int level) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + int err, ret = 0; + unsigned int i; + + /* Only put FPU state if we're emulating a CPU with an FPU */ + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + /* FPU Control Registers */ + if (level == KVM_PUT_FULL_STATE) { + err = kvm_mips_put_one_ureg(cs, KVM_REG_MIPS_FCR_IR, + &env->active_fpu.fcr0); + if (err < 0) { + DPRINTF("%s: Failed to put FCR_IR (%d)\n", __func__, err); + ret = err; + } + } + err = kvm_mips_put_one_ureg(cs, KVM_REG_MIPS_FCR_CSR, + &env->active_fpu.fcr31); + if (err < 0) { + DPRINTF("%s: Failed to put FCR_CSR (%d)\n", __func__, err); + ret = err; + } + + /* 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; + } + } + } + + return ret; +} + +static int kvm_mips_get_fpu_registers(CPUState *cs) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + int err, ret = 0; + unsigned int i; + + /* Only get FPU state if we're emulating a CPU with an FPU */ + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + /* FPU Control Registers */ + err = kvm_mips_get_one_ureg(cs, KVM_REG_MIPS_FCR_IR, + &env->active_fpu.fcr0); + if (err < 0) { + DPRINTF("%s: Failed to get FCR_IR (%d)\n", __func__, err); + ret = err; + } + err = kvm_mips_get_one_ureg(cs, KVM_REG_MIPS_FCR_CSR, + &env->active_fpu.fcr31); + if (err < 0) { + DPRINTF("%s: Failed to get FCR_CSR (%d)\n", __func__, err); + ret = err; + } else { + 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]); + } + if (err < 0) { + DPRINTF("%s: Failed to get FPR%u (%d)\n", __func__, i, err); + ret = err; + } + } + } + + return ret; +} + + static int kvm_mips_put_cp0_registers(CPUState *cs, int level) { MIPSCPU *cpu = MIPS_CPU(cs); @@ -805,6 +912,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } + ret = kvm_mips_put_fpu_registers(cs, level); + if (ret < 0) { + return ret; + } + return ret; } @@ -832,6 +944,7 @@ int kvm_arch_get_registers(CPUState *cs) env->active_tc.PC = regs.pc; kvm_mips_get_cp0_registers(cs); + kvm_mips_get_fpu_registers(cs); return ret; }