Commit 196d9e72 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-s390-next-6.17-1' of...

Merge tag 'kvm-s390-next-6.17-1' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD

RCU wakeup fix for KVM s390 guest entry
parents 6836e1f3 57d88f02
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -59,4 +59,14 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,

#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare

static __always_inline bool arch_in_rcu_eqs(void)
{
	if (IS_ENABLED(CONFIG_KVM))
		return current->flags & PF_VCPU;

	return false;
}

#define arch_in_rcu_eqs arch_in_rcu_eqs

#endif
+3 −0
Original line number Diff line number Diff line
@@ -716,6 +716,9 @@ extern char sie_exit;
bool kvm_s390_pv_is_protected(struct kvm *kvm);
bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu);

extern int kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,
				   u64 *gprs, unsigned long gasce);

extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);
extern int kvm_s390_gisc_unregister(struct kvm *kvm, u32 gisc);

+39 −12
Original line number Diff line number Diff line
@@ -5062,6 +5062,30 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
	return vcpu_post_run_handle_fault(vcpu);
}

int noinstr kvm_s390_enter_exit_sie(struct kvm_s390_sie_block *scb,
				    u64 *gprs, unsigned long gasce)
{
	int ret;

	guest_state_enter_irqoff();

	/*
	 * The guest_state_{enter,exit}_irqoff() functions inform lockdep and
	 * tracing that entry to the guest will enable host IRQs, and exit from
	 * the guest will disable host IRQs.
	 *
	 * We must not use lockdep/tracing/RCU in this critical section, so we
	 * use the low-level arch_local_irq_*() helpers to enable/disable IRQs.
	 */
	arch_local_irq_enable();
	ret = sie64a(scb, gprs, gasce);
	arch_local_irq_disable();

	guest_state_exit_irqoff();

	return ret;
}

#define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK)
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
@@ -5082,20 +5106,27 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
		kvm_vcpu_srcu_read_unlock(vcpu);
		/*
		 * As PF_VCPU will be used in fault handler, between
		 * guest_enter and guest_exit should be no uaccess.
		 * guest_timing_enter_irqoff and guest_timing_exit_irqoff
		 * should be no uaccess.
		 */
		local_irq_disable();
		guest_enter_irqoff();
		__disable_cpu_timer_accounting(vcpu);
		local_irq_enable();
		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
			memcpy(sie_page->pv_grregs,
			       vcpu->run->s.regs.gprs,
			       sizeof(sie_page->pv_grregs));
		}
		exit_reason = sie64a(vcpu->arch.sie_block,

		local_irq_disable();
		guest_timing_enter_irqoff();
		__disable_cpu_timer_accounting(vcpu);

		exit_reason = kvm_s390_enter_exit_sie(vcpu->arch.sie_block,
						      vcpu->run->s.regs.gprs,
						      vcpu->arch.gmap->asce);

		__enable_cpu_timer_accounting(vcpu);
		guest_timing_exit_irqoff();
		local_irq_enable();

		if (kvm_s390_pv_cpu_is_protected(vcpu)) {
			memcpy(vcpu->run->s.regs.gprs,
			       sie_page->pv_grregs,
@@ -5111,10 +5142,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
				vcpu->arch.sie_block->gpsw.mask &= ~PSW_INT_MASK;
			}
		}
		local_irq_disable();
		__enable_cpu_timer_accounting(vcpu);
		guest_exit_irqoff();
		local_irq_enable();
		kvm_vcpu_srcu_read_lock(vcpu);

		rc = vcpu_post_run(vcpu, exit_reason);
+7 −10
Original line number Diff line number Diff line
@@ -1170,10 +1170,6 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
	    vcpu->arch.sie_block->fpf & FPF_BPBC)
		set_thread_flag(TIF_ISOLATE_BP_GUEST);

	local_irq_disable();
	guest_enter_irqoff();
	local_irq_enable();

	/*
	 * Simulate a SIE entry of the VCPU (see sie64a), so VCPU blocking
	 * and VCPU requests also hinder the vSIE from running and lead
@@ -1183,14 +1179,15 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
	vcpu->arch.sie_block->prog0c |= PROG_IN_SIE;
	current->thread.gmap_int_code = 0;
	barrier();
	if (!kvm_s390_vcpu_sie_inhibited(vcpu))
		rc = sie64a(scb_s, vcpu->run->s.regs.gprs, vsie_page->gmap->asce);
	barrier();
	vcpu->arch.sie_block->prog0c &= ~PROG_IN_SIE;

	if (!kvm_s390_vcpu_sie_inhibited(vcpu)) {
		local_irq_disable();
	guest_exit_irqoff();
		guest_timing_enter_irqoff();
		rc = kvm_s390_enter_exit_sie(scb_s, vcpu->run->s.regs.gprs, vsie_page->gmap->asce);
		guest_timing_exit_irqoff();
		local_irq_enable();
	}
	barrier();
	vcpu->arch.sie_block->prog0c &= ~PROG_IN_SIE;

	/* restore guest state for bp isolation override */
	if (!guest_bp_isolation)
+16 −0
Original line number Diff line number Diff line
@@ -86,6 +86,22 @@ static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs);
static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs) {}
#endif

/**
 * arch_in_rcu_eqs - Architecture specific check for RCU extended quiescent
 * states.
 *
 * Returns: true if the CPU is potentially in an RCU EQS, false otherwise.
 *
 * Architectures only need to define this if threads other than the idle thread
 * may have an interruptible EQS. This does not need to handle idle threads. It
 * is safe to over-estimate at the cost of redundant RCU management work.
 *
 * Invoked from irqentry_enter()
 */
#ifndef arch_in_rcu_eqs
static __always_inline bool arch_in_rcu_eqs(void) { return false; }
#endif

/**
 * enter_from_user_mode - Establish state when coming from user mode
 *
Loading