Skip to content

Commit 21f27df

Browse files
Nico Boehrfrankjaa
authored andcommitted
KVM: s390: pv: fix external interruption loop not always detected
To determine whether the guest has caused an external interruption loop upon code 20 (external interrupt) intercepts, the ext_new_psw needs to be inspected to see whether external interrupts are enabled. Under non-PV, ext_new_psw can simply be taken from guest lowcore. Under PV, KVM can only access the encrypted guest lowcore and hence the ext_new_psw must not be taken from guest lowcore. handle_external_interrupt() incorrectly did that and hence was not able to reliably tell whether an external interruption loop is happening or not. False negatives cause spurious failures of my kvm-unit-test for extint loops[1] under PV. Since code 20 is only caused under PV if and only if the guest's ext_new_psw is enabled for external interrupts, false positive detection of a external interruption loop can not happen. Fix this issue by instead looking at the guest PSW in the state description. Since the PSW swap for external interrupt is done by the ultravisor before the intercept is caused, this reliably tells whether the guest is enabled for external interrupts in the ext_new_psw. Also update the comments to explain better what is happening. [1] https://lore.kernel.org/kvm/[email protected]/ Signed-off-by: Nico Boehr <[email protected]> Reviewed-by: Janosch Frank <[email protected]> Reviewed-by: Christian Borntraeger <[email protected]> Fixes: 201ae98 ("KVM: s390: protvirt: Implement interrupt injection") Link: https://lore.kernel.org/r/[email protected] Message-Id: <[email protected]> Signed-off-by: Janosch Frank <[email protected]>
1 parent 197b6b6 commit 21f27df

File tree

1 file changed

+24
-8
lines changed

1 file changed

+24
-8
lines changed

arch/s390/kvm/intercept.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,18 @@ static int handle_prog(struct kvm_vcpu *vcpu)
271271
* handle_external_interrupt - used for external interruption interceptions
272272
* @vcpu: virtual cpu
273273
*
274-
* This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if
275-
* the new PSW does not have external interrupts disabled. In the first case,
276-
* we've got to deliver the interrupt manually, and in the second case, we
277-
* drop to userspace to handle the situation there.
274+
* This interception occurs if:
275+
* - the CPUSTAT_EXT_INT bit was already set when the external interrupt
276+
* occurred. In this case, the interrupt needs to be injected manually to
277+
* preserve interrupt priority.
278+
* - the external new PSW has external interrupts enabled, which will cause an
279+
* interruption loop. We drop to userspace in this case.
280+
*
281+
* The latter case can be detected by inspecting the external mask bit in the
282+
* external new psw.
283+
*
284+
* Under PV, only the latter case can occur, since interrupt priorities are
285+
* handled in the ultravisor.
278286
*/
279287
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
280288
{
@@ -285,10 +293,18 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
285293

286294
vcpu->stat.exit_external_interrupt++;
287295

288-
rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
289-
if (rc)
290-
return rc;
291-
/* We can not handle clock comparator or timer interrupt with bad PSW */
296+
if (kvm_s390_pv_cpu_is_protected(vcpu)) {
297+
newpsw = vcpu->arch.sie_block->gpsw;
298+
} else {
299+
rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
300+
if (rc)
301+
return rc;
302+
}
303+
304+
/*
305+
* Clock comparator or timer interrupt with external interrupt enabled
306+
* will cause interrupt loop. Drop to userspace.
307+
*/
292308
if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
293309
(newpsw.mask & PSW_MASK_EXT))
294310
return -EOPNOTSUPP;

0 commit comments

Comments
 (0)