diff mbox series

[RFC] KVM: PPC: Book3S PR: Fix context tracking

Message ID 20221006142352.128349-1-npiggin@gmail.com (mailing list archive)
State New
Headers show
Series [RFC] KVM: PPC: Book3S PR: Fix context tracking | expand

Commit Message

Nicholas Piggin Oct. 6, 2022, 2:23 p.m. UTC
The main difficulty with supporting context tracking is exiting
from guest context before taking any host interrupts. That path
is all done in assembly with a clever trampoline and bounce to
interrupt handler then back to exit handler with interrupts enabled.
This patch adds a call out to C in virtual mode to exit guest context
before any host interrupts are taken, and splits the context from
timing management because timing wants to be called after interrupts
are enabled.

This is able to boot a a guest on a 64s host without crashing now.
32s doesn't support context tracking yet so that isn't tested, but
it should work, modulo possible incorrect instruction relocation
address when enabling IR.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/kvm/Kconfig             |  2 --
 arch/powerpc/kvm/book3s_exports.c    |  7 +++++++
 arch/powerpc/kvm/book3s_pr.c         | 10 +++++++++-
 arch/powerpc/kvm/book3s_rmhandlers.S |  3 ++-
 arch/powerpc/kvm/book3s_segment.S    | 28 +++++++++++++++++++++++++++-
 arch/powerpc/kvm/powerpc.c           |  3 ++-
 6 files changed, 47 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index a9f57dad6d91..5d580c0f6500 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -51,7 +51,6 @@  config KVM_BOOK3S_HV_POSSIBLE
 config KVM_BOOK3S_32
 	tristate "KVM support for PowerPC book3s_32 processors"
 	depends on PPC_BOOK3S_32 && !SMP && !PTE_64BIT
-	depends on !CONTEXT_TRACKING_USER
 	select KVM
 	select KVM_BOOK3S_32_HANDLER
 	select KVM_BOOK3S_PR_POSSIBLE
@@ -106,7 +105,6 @@  config KVM_BOOK3S_64_HV
 config KVM_BOOK3S_64_PR
 	tristate "KVM support without using hypervisor mode in host"
 	depends on KVM_BOOK3S_64
-	depends on !CONTEXT_TRACKING_USER
 	select KVM_BOOK3S_PR_POSSIBLE
 	help
 	  Support running guest kernels in virtual machines on processors
diff --git a/arch/powerpc/kvm/book3s_exports.c b/arch/powerpc/kvm/book3s_exports.c
index f08565885ddf..cd40a46215cb 100644
--- a/arch/powerpc/kvm/book3s_exports.c
+++ b/arch/powerpc/kvm/book3s_exports.c
@@ -6,6 +6,7 @@ 
  * Authors: Alexander Graf <agraf@suse.de>
  */
 
+#include <linux/context_tracking.h>
 #include <linux/export.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -15,5 +16,11 @@  EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline);
 #endif
 #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
 EXPORT_SYMBOL_GPL(kvmppc_entry_trampoline);
+
+void kvmppc_guest_state_exit_irqoff(void)
+{
+	guest_state_exit_irqoff();
+}
+EXPORT_SYMBOL_GPL(kvmppc_guest_state_exit_irqoff);
 #endif
 
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index d6abed6e51e6..60d7a11a7cbc 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -1144,6 +1144,12 @@  int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr)
 	int r = RESUME_HOST;
 	int s;
 
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+	local_irq_disable();
+	guest_timing_exit_irqoff();
+	local_irq_enable();
+#endif
+
 	vcpu->stat.sum_exits++;
 
 	run->exit_reason = KVM_EXIT_UNKNOWN;
@@ -1152,7 +1158,6 @@  int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr)
 	/* We get here with MSR.EE=1 */
 
 	trace_kvm_exit(exit_nr, vcpu);
-	guest_exit();
 
 	switch (exit_nr) {
 	case BOOK3S_INTERRUPT_INST_STORAGE:
@@ -1448,6 +1453,7 @@  int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr)
 		else {
 			/* interrupts now hard-disabled */
 			kvmppc_fix_ee_before_entry();
+			guest_state_enter_irqoff();
 		}
 
 		kvmppc_handle_lost_ext(vcpu);
@@ -1844,6 +1850,8 @@  static int kvmppc_vcpu_run_pr(struct kvm_vcpu *vcpu)
 
 	kvmppc_fix_ee_before_entry();
 
+	guest_state_enter_irqoff();
+
 	ret = __kvmppc_vcpu_run(vcpu);
 
 	kvmppc_clear_debug(vcpu);
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
index 03886ca24498..d3558a7509e7 100644
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -152,7 +152,8 @@  _GLOBAL_TOC(kvmppc_entry_trampoline)
 	andc	r6, r5, r6	/* Clear DR and IR in MSR value */
 	/*
 	 * Set EE in HOST_MSR so that it's enabled when we get into our
-	 * C exit handler function.
+	 * C exit handler function. If we are tracking context then must
+	 * not take host interrupts before switching out of guest context.
 	 */
 	ori	r5, r5, MSR_EE
 	mtsrr0	r7
diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S
index 202046a83fc1..04f479d07ca8 100644
--- a/arch/powerpc/kvm/book3s_segment.S
+++ b/arch/powerpc/kvm/book3s_segment.S
@@ -363,12 +363,38 @@  END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 	 *
 	 * R1       = host R1
 	 * R2       = host R2
-	 * R10      = raw exit handler id
+	 * R10      = raw exit handler id (XXX doesn't seem to be there)
 	 * R12      = exit handler id
 	 * R13      = shadow vcpu (32-bit) or PACA (64-bit)
 	 * SVCPU.*  = guest *
 	 *
 	 */
+#ifdef CONFIG_CONTEXT_TRACKING_USER
+#ifdef CONFIG_PPC64
+	LOAD_REG_ADDR(r11, 1f)
+	mtctr	r11
+	bctr
+1:
+#endif
+	/* XXX: does 32s need any address change to enable IR? */
+	mfmsr	r11
+	ori	r11, r11, MSR_IR|MSR_DR
+	mtmsr	r11
+	sync
+	PPC_STL	r12, HSTATE_SCRATCH0(r13)
+	mfcr	r9
+	stw	r9, HSTATE_SCRATCH1(r13)
+	bl	FUNC(kvmppc_guest_state_exit_irqoff)
+	nop
+	PPC_LL	r12, HSTATE_SCRATCH0(r13)
+	lwz	r9, HSTATE_SCRATCH1(r13)
+	mtcr	r9
+	mfmsr	r11
+	li	r9, MSR_IR|MSR_DR
+	andc	r11, r11, r9
+	mtmsr	r11
+	sync
+#endif
 
 	PPC_LL	r6, HSTATE_HOST_MSR(r13)
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 757491dd6b7b..3a3c5ad759e4 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -129,7 +129,8 @@  int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
 			continue;
 		}
 
-		guest_enter_irqoff();
+		guest_timing_enter_irqoff();
+
 		return 1;
 	}