diff options
Diffstat (limited to 'arch/s390/kvm/intercept.c')
| -rw-r--r-- | arch/s390/kvm/intercept.c | 32 | 
1 files changed, 24 insertions, 8 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 0ee02dae14b2..2cda8d9d7c6e 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -271,10 +271,18 @@ static int handle_prog(struct kvm_vcpu *vcpu)   * handle_external_interrupt - used for external interruption interceptions   * @vcpu: virtual cpu   * - * This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if - * the new PSW does not have external interrupts disabled. In the first case, - * we've got to deliver the interrupt manually, and in the second case, we - * drop to userspace to handle the situation there. + * This interception occurs if: + * - the CPUSTAT_EXT_INT bit was already set when the external interrupt + *   occurred. In this case, the interrupt needs to be injected manually to + *   preserve interrupt priority. + * - the external new PSW has external interrupts enabled, which will cause an + *   interruption loop. We drop to userspace in this case. + * + * The latter case can be detected by inspecting the external mask bit in the + * external new psw. + * + * Under PV, only the latter case can occur, since interrupt priorities are + * handled in the ultravisor.   */  static int handle_external_interrupt(struct kvm_vcpu *vcpu)  { @@ -285,10 +293,18 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)  	vcpu->stat.exit_external_interrupt++; -	rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t)); -	if (rc) -		return rc; -	/* We can not handle clock comparator or timer interrupt with bad PSW */ +	if (kvm_s390_pv_cpu_is_protected(vcpu)) { +		newpsw = vcpu->arch.sie_block->gpsw; +	} else { +		rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t)); +		if (rc) +			return rc; +	} + +	/* +	 * Clock comparator or timer interrupt with external interrupt enabled +	 * will cause interrupt loop. Drop to userspace. +	 */  	if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&  	    (newpsw.mask & PSW_MASK_EXT))  		return -EOPNOTSUPP;  |