hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/s390/kvm/intercept.c
....@@ -270,10 +270,18 @@
270270 /**
271271 * handle_external_interrupt - used for external interruption interceptions
272272 *
273
- * This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if
274
- * the new PSW does not have external interrupts disabled. In the first case,
275
- * we've got to deliver the interrupt manually, and in the second case, we
276
- * drop to userspace to handle the situation there.
273
+ * This interception occurs if:
274
+ * - the CPUSTAT_EXT_INT bit was already set when the external interrupt
275
+ * occurred. In this case, the interrupt needs to be injected manually to
276
+ * preserve interrupt priority.
277
+ * - the external new PSW has external interrupts enabled, which will cause an
278
+ * interruption loop. We drop to userspace in this case.
279
+ *
280
+ * The latter case can be detected by inspecting the external mask bit in the
281
+ * external new psw.
282
+ *
283
+ * Under PV, only the latter case can occur, since interrupt priorities are
284
+ * handled in the ultravisor.
277285 */
278286 static int handle_external_interrupt(struct kvm_vcpu *vcpu)
279287 {
....@@ -284,10 +292,18 @@
284292
285293 vcpu->stat.exit_external_interrupt++;
286294
287
- rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
288
- if (rc)
289
- return rc;
290
- /* We can not handle clock comparator or timer interrupt with bad PSW */
295
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
296
+ newpsw = vcpu->arch.sie_block->gpsw;
297
+ } else {
298
+ rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
299
+ if (rc)
300
+ return rc;
301
+ }
302
+
303
+ /*
304
+ * Clock comparator or timer interrupt with external interrupt enabled
305
+ * will cause interrupt loop. Drop to userspace.
306
+ */
291307 if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
292308 (newpsw.mask & PSW_MASK_EXT))
293309 return -EOPNOTSUPP;
....@@ -371,8 +387,8 @@
371387 */
372388 int handle_sthyi(struct kvm_vcpu *vcpu)
373389 {
374
- int reg1, reg2, r = 0;
375
- u64 code, addr, cc = 0, rc = 0;
390
+ int reg1, reg2, cc = 0, r = 0;
391
+ u64 code, addr, rc = 0;
376392 struct sthyi_sctns *sctns = NULL;
377393
378394 if (!test_kvm_facility(vcpu->kvm, 74))
....@@ -403,7 +419,10 @@
403419 return -ENOMEM;
404420
405421 cc = sthyi_fill(sctns, &rc);
406
-
422
+ if (cc < 0) {
423
+ free_page((unsigned long)sctns);
424
+ return cc;
425
+ }
407426 out:
408427 if (!cc) {
409428 if (kvm_s390_pv_cpu_is_protected(vcpu)) {