All of lore.kernel.org
 help / color / mirror / Atom feed
From: Avi Kivity <avi@redhat.com>
To: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 31/39] KVM: PPC: Add support for FPU/Altivec/VSX
Date: Sat, 13 Feb 2010 10:01:51 +0200	[thread overview]
Message-ID: <1266048119-14325-32-git-send-email-avi@redhat.com> (raw)
In-Reply-To: <1266048119-14325-1-git-send-email-avi@redhat.com>

From: Alexander Graf <agraf@suse.de>

When our guest starts using either the FPU, Altivec or VSX we need to make
sure Linux knows about it and sneak into its process switching code
accordingly.

This patch makes accesses to the above parts of the system work inside the
VM.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
 arch/powerpc/include/asm/kvm_host.h |   14 +++-
 arch/powerpc/kvm/book3s.c           |  193 ++++++++++++++++++++++++++++++++++-
 2 files changed, 201 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index f7215e6..c30a70c 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -172,9 +172,20 @@ struct kvm_vcpu_arch {
 	struct kvmppc_mmu mmu;
 #endif
 
-	u64 fpr[32];
 	ulong gpr[32];
 
+	u64 fpr[32];
+	u32 fpscr;
+
+#ifdef CONFIG_ALTIVEC
+	vector128 vr[32];
+	vector128 vscr;
+#endif
+
+#ifdef CONFIG_VSX
+	u64 vsr[32];
+#endif
+
 	ulong pc;
 	ulong ctr;
 	ulong lr;
@@ -188,6 +199,7 @@ struct kvm_vcpu_arch {
 #ifdef CONFIG_PPC64
 	ulong shadow_msr;
 	ulong hflags;
+	ulong guest_owned_ext;
 #endif
 	u32 mmucr;
 	ulong sprg0;
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 02861fd..2cb1813 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -33,6 +33,9 @@
 
 /* #define EXIT_DEBUG */
 /* #define EXIT_DEBUG_SIMPLE */
+/* #define DEBUG_EXT */
+
+static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
 	{ "exits",       VCPU_STAT(sum_exits) },
@@ -77,6 +80,10 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
 	memcpy(&to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
 	       sizeof(get_paca()->shadow_vcpu));
 	to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max;
+
+	kvmppc_giveup_ext(vcpu, MSR_FP);
+	kvmppc_giveup_ext(vcpu, MSR_VEC);
+	kvmppc_giveup_ext(vcpu, MSR_VSX);
 }
 
 #if defined(EXIT_DEBUG)
@@ -97,9 +104,9 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
 	msr &= to_book3s(vcpu)->msr_mask;
 	vcpu->arch.msr = msr;
 	vcpu->arch.shadow_msr = msr | MSR_USER32;
-	vcpu->arch.shadow_msr &= ( MSR_VEC | MSR_VSX | MSR_FP | MSR_FE0 |
-				   MSR_USER64 | MSR_SE | MSR_BE | MSR_DE |
-				   MSR_FE1);
+	vcpu->arch.shadow_msr &= (MSR_FE0 | MSR_USER64 | MSR_SE | MSR_BE |
+				  MSR_DE | MSR_FE1);
+	vcpu->arch.shadow_msr |= (msr & vcpu->arch.guest_owned_ext);
 
 	if (msr & (MSR_WE|MSR_POW)) {
 		if (!vcpu->arch.pending_exceptions) {
@@ -551,6 +558,117 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	return r;
 }
 
+static inline int get_fpr_index(int i)
+{
+#ifdef CONFIG_VSX
+	i *= 2;
+#endif
+	return i;
+}
+
+/* Give up external provider (FPU, Altivec, VSX) */
+static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
+{
+	struct thread_struct *t = &current->thread;
+	u64 *vcpu_fpr = vcpu->arch.fpr;
+	u64 *vcpu_vsx = vcpu->arch.vsr;
+	u64 *thread_fpr = (u64*)t->fpr;
+	int i;
+
+	if (!(vcpu->arch.guest_owned_ext & msr))
+		return;
+
+#ifdef DEBUG_EXT
+	printk(KERN_INFO "Giving up ext 0x%lx\n", msr);
+#endif
+
+	switch (msr) {
+	case MSR_FP:
+		giveup_fpu(current);
+		for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
+			vcpu_fpr[i] = thread_fpr[get_fpr_index(i)];
+
+		vcpu->arch.fpscr = t->fpscr.val;
+		break;
+	case MSR_VEC:
+#ifdef CONFIG_ALTIVEC
+		giveup_altivec(current);
+		memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr));
+		vcpu->arch.vscr = t->vscr;
+#endif
+		break;
+	case MSR_VSX:
+#ifdef CONFIG_VSX
+		__giveup_vsx(current);
+		for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++)
+			vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1];
+#endif
+		break;
+	default:
+		BUG();
+	}
+
+	vcpu->arch.guest_owned_ext &= ~msr;
+	current->thread.regs->msr &= ~msr;
+	kvmppc_set_msr(vcpu, vcpu->arch.msr);
+}
+
+/* Handle external providers (FPU, Altivec, VSX) */
+static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
+			     ulong msr)
+{
+	struct thread_struct *t = &current->thread;
+	u64 *vcpu_fpr = vcpu->arch.fpr;
+	u64 *vcpu_vsx = vcpu->arch.vsr;
+	u64 *thread_fpr = (u64*)t->fpr;
+	int i;
+
+	if (!(vcpu->arch.msr & msr)) {
+		kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
+		return RESUME_GUEST;
+	}
+
+#ifdef DEBUG_EXT
+	printk(KERN_INFO "Loading up ext 0x%lx\n", msr);
+#endif
+
+	current->thread.regs->msr |= msr;
+
+	switch (msr) {
+	case MSR_FP:
+		for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
+			thread_fpr[get_fpr_index(i)] = vcpu_fpr[i];
+
+		t->fpscr.val = vcpu->arch.fpscr;
+		t->fpexc_mode = 0;
+		kvmppc_load_up_fpu();
+		break;
+	case MSR_VEC:
+#ifdef CONFIG_ALTIVEC
+		memcpy(t->vr, vcpu->arch.vr, sizeof(vcpu->arch.vr));
+		t->vscr = vcpu->arch.vscr;
+		t->vrsave = -1;
+		kvmppc_load_up_altivec();
+#endif
+		break;
+	case MSR_VSX:
+#ifdef CONFIG_VSX
+		for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++)
+			thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i];
+		kvmppc_load_up_vsx();
+#endif
+		break;
+	default:
+		BUG();
+	}
+
+	vcpu->arch.guest_owned_ext |= msr;
+
+	kvmppc_set_msr(vcpu, vcpu->arch.msr);
+
+	return RESUME_GUEST;
+}
+
 int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned int exit_nr)
 {
@@ -674,11 +792,17 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 		r = RESUME_GUEST;
 		break;
-	case BOOK3S_INTERRUPT_MACHINE_CHECK:
 	case BOOK3S_INTERRUPT_FP_UNAVAIL:
-	case BOOK3S_INTERRUPT_TRACE:
+		r = kvmppc_handle_ext(vcpu, exit_nr, MSR_FP);
+		break;
 	case BOOK3S_INTERRUPT_ALTIVEC:
+		r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VEC);
+		break;
 	case BOOK3S_INTERRUPT_VSX:
+		r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VSX);
+		break;
+	case BOOK3S_INTERRUPT_MACHINE_CHECK:
+	case BOOK3S_INTERRUPT_TRACE:
 		kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 		r = RESUME_GUEST;
 		break;
@@ -959,6 +1083,10 @@ extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
 	int ret;
+	struct thread_struct ext_bkp;
+	bool save_vec = current->thread.used_vr;
+	bool save_vsx = current->thread.used_vsr;
+	ulong ext_msr;
 
 	/* No need to go into the guest when all we do is going out */
 	if (signal_pending(current)) {
@@ -966,6 +1094,35 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 		return -EINTR;
 	}
 
+	/* Save FPU state in stack */
+	if (current->thread.regs->msr & MSR_FP)
+		giveup_fpu(current);
+	memcpy(ext_bkp.fpr, current->thread.fpr, sizeof(current->thread.fpr));
+	ext_bkp.fpscr = current->thread.fpscr;
+	ext_bkp.fpexc_mode = current->thread.fpexc_mode;
+
+#ifdef CONFIG_ALTIVEC
+	/* Save Altivec state in stack */
+	if (save_vec) {
+		if (current->thread.regs->msr & MSR_VEC)
+			giveup_altivec(current);
+		memcpy(ext_bkp.vr, current->thread.vr, sizeof(ext_bkp.vr));
+		ext_bkp.vscr = current->thread.vscr;
+		ext_bkp.vrsave = current->thread.vrsave;
+	}
+	ext_bkp.used_vr = current->thread.used_vr;
+#endif
+
+#ifdef CONFIG_VSX
+	/* Save VSX state in stack */
+	if (save_vsx && (current->thread.regs->msr & MSR_VSX))
+			__giveup_vsx(current);
+	ext_bkp.used_vsr = current->thread.used_vsr;
+#endif
+
+	/* Remember the MSR with disabled extensions */
+	ext_msr = current->thread.regs->msr;
+
 	/* XXX we get called with irq disabled - change that! */
 	local_irq_enable();
 
@@ -973,6 +1130,32 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
 	local_irq_disable();
 
+	current->thread.regs->msr = ext_msr;
+
+	/* Make sure we save the guest FPU/Altivec/VSX state */
+	kvmppc_giveup_ext(vcpu, MSR_FP);
+	kvmppc_giveup_ext(vcpu, MSR_VEC);
+	kvmppc_giveup_ext(vcpu, MSR_VSX);
+
+	/* Restore FPU state from stack */
+	memcpy(current->thread.fpr, ext_bkp.fpr, sizeof(ext_bkp.fpr));
+	current->thread.fpscr = ext_bkp.fpscr;
+	current->thread.fpexc_mode = ext_bkp.fpexc_mode;
+
+#ifdef CONFIG_ALTIVEC
+	/* Restore Altivec state from stack */
+	if (save_vec && current->thread.used_vr) {
+		memcpy(current->thread.vr, ext_bkp.vr, sizeof(ext_bkp.vr));
+		current->thread.vscr = ext_bkp.vscr;
+		current->thread.vrsave= ext_bkp.vrsave;
+	}
+	current->thread.used_vr = ext_bkp.used_vr;
+#endif
+
+#ifdef CONFIG_VSX
+	current->thread.used_vsr = ext_bkp.used_vsr;
+#endif
+
 	return ret;
 }
 
-- 
1.6.5.3


  parent reply	other threads:[~2010-02-13  8:03 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-02-13  8:01 [PATCH 00/39] KVM updates for the 2.6.34 merge window (batch 2/4) Avi Kivity
2010-02-13  8:01 ` [PATCH 01/39] KVM: PPC: Enable lightweight exits again Avi Kivity
2010-02-13  8:01 ` [PATCH 02/39] KVM: x86: Moving PT_*_LEVEL to mmu.h Avi Kivity
2010-02-13  8:01 ` [PATCH 03/39] KVM: x86: Rename gb_page_enable() to get_lpage_level() in kvm_x86_ops Avi Kivity
2010-02-13  8:01 ` [PATCH 04/39] KVM: VMX: Enable EPT 1GB page support Avi Kivity
2010-02-13  8:01 ` [PATCH 05/39] KVM: Fix the explanation of write_emulated Avi Kivity
2010-02-13  8:01 ` [PATCH 06/39] KVM: PPC: Use accessor functions for GPR access Avi Kivity
2010-02-13  8:01 ` [PATCH 07/39] KVM: PPC: Add helpers for CR, XER Avi Kivity
2010-02-13  8:01 ` [PATCH 08/39] KVM: PPC: Use PACA backed shadow vcpu Avi Kivity
2010-02-13  8:01 ` [PATCH 09/39] KVM: PPC: Implement 'skip instruction' mode Avi Kivity
2010-02-13  8:01 ` [PATCH 10/39] KVM: PPC: Get rid of unnecessary RFI Avi Kivity
2010-02-13  8:01 ` [PATCH 11/39] KVM: PPC: Call SLB patching code in interrupt safe manner Avi Kivity
2010-02-13  8:01 ` [PATCH 12/39] KVM: PPC: Emulate trap SRR1 flags properly Avi Kivity
2010-02-13  8:01 ` [PATCH 13/39] KVM: PPC: Fix HID5 setting code Avi Kivity
2010-02-13  8:01 ` [PATCH 14/39] KVM: PPC: Pass program interrupt flags to the guest Avi Kivity
2010-02-13  8:01 ` [PATCH 15/39] KVM: PPC: Pass through program interrupts Avi Kivity
2010-02-13  8:01 ` [PATCH 16/39] KVM: PPC: Make large pages work Avi Kivity
2010-02-13  8:01 ` [PATCH 17/39] KVM: VMX: trace clts and lmsw instructions as cr accesses Avi Kivity
2010-02-13  8:01 ` [PATCH 18/39] KVM: Replace read accesses of vcpu->arch.cr0 by an accessor Avi Kivity
2010-02-13  8:01 ` [PATCH 19/39] KVM: VMX: Allow the guest to own some cr0 bits Avi Kivity
2010-02-13  8:01 ` [PATCH 20/39] KVM: Lazify fpu activation and deactivation Avi Kivity
2010-02-13  8:01 ` [PATCH 21/39] KVM: VMX: Give the guest ownership of cr0.ts when the fpu is active Avi Kivity
2010-02-13  8:01 ` [PATCH 22/39] KVM: Set cr0.et when the guest writes cr0 Avi Kivity
2010-02-13  8:01 ` [PATCH 23/39] KVM: SVM: Fix SVM_CR0_SELECTIVE_MASK Avi Kivity
2010-02-13  8:01 ` [PATCH 24/39] KVM: SVM: Initialize fpu_active in init_vmcb() Avi Kivity
2010-02-13  8:01 ` [PATCH 25/39] KVM: SVM: Restore unconditional cr0 intercept under npt Avi Kivity
2010-02-13  8:01 ` [PATCH 26/39] KVM: SVM: Selective cr0 intercept Avi Kivity
2010-02-13  8:01 ` [PATCH 27/39] KVM: SVM: Lazy fpu with npt Avi Kivity
2010-02-13  8:01 ` [PATCH 28/39] KVM: ia64: remove redundant kvm_get_exit_data() NULL tests Avi Kivity
2010-02-13  8:01 ` [PATCH 29/39] KVM: PPC: Export __giveup_vsx Avi Kivity
2010-02-13  8:01 ` [PATCH 30/39] KVM: PPC: Add helper functions to call real mode loaders Avi Kivity
2010-02-13  8:01 ` Avi Kivity [this message]
2010-02-13  8:01 ` [PATCH 32/39] KVM: PPC: Fix initial GPR settings Avi Kivity
2010-02-13  8:01 ` [PATCH 33/39] KVM: PPC: Keep SRR1 flags around in shadow_msr Avi Kivity
2010-02-13  8:01 ` [PATCH 34/39] KVM: PPC: Move Shadow MSR calculation to function Avi Kivity
2010-02-13  8:01 ` [PATCH 35/39] KVM: Add HYPER-V header file Avi Kivity
2010-02-13  8:01 ` [PATCH 36/39] KVM: Implement bare minimum of HYPER-V MSRs Avi Kivity
2010-02-13  8:01 ` [PATCH 37/39] KVM: Add HYPER-V apic access MSRs Avi Kivity
2010-02-13  8:01 ` [PATCH 38/39] KVM: Implement NotifyLongSpinWait HYPER-V hypercall Avi Kivity
2010-02-13  8:01 ` [PATCH 39/39] KVM: rename is_writeble_pte() to is_writable_pte() Avi Kivity

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1266048119-14325-32-git-send-email-avi@redhat.com \
    --to=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.