| .. | .. |
|---|
| 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)) { |
|---|