.. | .. |
---|
270 | 270 | /** |
---|
271 | 271 | * handle_external_interrupt - used for external interruption interceptions |
---|
272 | 272 | * |
---|
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. |
---|
277 | 285 | */ |
---|
278 | 286 | static int handle_external_interrupt(struct kvm_vcpu *vcpu) |
---|
279 | 287 | { |
---|
.. | .. |
---|
284 | 292 | |
---|
285 | 293 | vcpu->stat.exit_external_interrupt++; |
---|
286 | 294 | |
---|
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 | + */ |
---|
291 | 307 | if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) && |
---|
292 | 308 | (newpsw.mask & PSW_MASK_EXT)) |
---|
293 | 309 | return -EOPNOTSUPP; |
---|
.. | .. |
---|
371 | 387 | */ |
---|
372 | 388 | int handle_sthyi(struct kvm_vcpu *vcpu) |
---|
373 | 389 | { |
---|
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; |
---|
376 | 392 | struct sthyi_sctns *sctns = NULL; |
---|
377 | 393 | |
---|
378 | 394 | if (!test_kvm_facility(vcpu->kvm, 74)) |
---|
.. | .. |
---|
403 | 419 | return -ENOMEM; |
---|
404 | 420 | |
---|
405 | 421 | cc = sthyi_fill(sctns, &rc); |
---|
406 | | - |
---|
| 422 | + if (cc < 0) { |
---|
| 423 | + free_page((unsigned long)sctns); |
---|
| 424 | + return cc; |
---|
| 425 | + } |
---|
407 | 426 | out: |
---|
408 | 427 | if (!cc) { |
---|
409 | 428 | if (kvm_s390_pv_cpu_is_protected(vcpu)) { |
---|