mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-18 02:04:05 +08:00
1. Fixes an error return code for the breakpoint setup
2. External interrupt fixes 2.1. Some interrupt conditions like cpu timer or clock comparator stay pending even after the interrupt is injected. If the external new PSW is enabled for interrupts this will result in an endless loop. Usually this indicates a programming error in the guest OS. Lets detect such situations and go to userspace. We will provide a QEMU patch that sets the guest in panicked/crashed state to avoid wasting CPU cycles. 2.2 Resend external interrupts back to the guest if the HW could not do it. - -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJTaOGKAAoJEBF7vIC1phx8IqkP/0zQ3gWbYdGV20UEvIB+oHsO u7OysZdyfXS3wx6rysTWepQJ6rtWJ/yQSyzTt+RnCTYxUnyhMVPKMJOmoztyhkD5 37I9ricqMS/Ob5A3pKGEW2p/TojPYL5o8svCRt+UWbyxz05AQiCEPteeD7MrcOK+ ASULR2z2h95EYfrMhZSeFjFoXHrPfeMoR5OVESP8gef7uGTlqIZO1mZ6QkAFqL/b VtqCI74oTc+XpNj7jxnvxznilqnvjD31oaci2oK+AX+DQcwOnTIGuUlU1bS+XOwm WFbDKUbksNC/QQ2hPqcCvZTtK+U7XlPZz7pRyEdvHYRckaNDzLbiLzYHvRGgCHoq uy9u429L1pthoj1vQvUY2ZD4HyI4K/UusApie5x3hmYlePNSEcC7TNDt2SvdjrID yX6X9zWC9ffHSmKLBI11PWNs5R1EUrUlBcZ7CFDDmJDCeKRmwmY1+nuYSm7x80iB ctfpXTJG4Ajrbbki5LCdoLPU0piR/IkSEwxeEY0u/5XLcdEiY/Z3SEJzlWeuIPf6 bNuWQK8YP6ane8p3Vc/UwmtMgaCEsnAwYrcRfmjOEQfVDxmRzHARIxbIFs0EsM54 S+6SH6LN1HCeFsG3zvpwPrm9gK2GojvJ0tCwZ78UZZx5m4CrgtHVHHfbspygftv8 6L/YJ/Q0PQja0s3lx/Eh =R95o -----END PGP SIGNATURE----- Merge tag 'kvm-s390-20140506' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into kvm-next 1. Fixes an error return code for the breakpoint setup 2. External interrupt fixes 2.1. Some interrupt conditions like cpu timer or clock comparator stay pending even after the interrupt is injected. If the external new PSW is enabled for interrupts this will result in an endless loop. Usually this indicates a programming error in the guest OS. Lets detect such situations and go to userspace. We will provide a QEMU patch that sets the guest in panicked/crashed state to avoid wasting CPU cycles. 2.2 Resend external interrupts back to the guest if the HW could not do it. -
This commit is contained in:
commit
2ce316f0b9
@ -2211,6 +2211,8 @@ KVM_S390_SIGP_STOP (vcpu) - sigp restart
|
||||
KVM_S390_PROGRAM_INT (vcpu) - program check; code in parm
|
||||
KVM_S390_SIGP_SET_PREFIX (vcpu) - sigp set prefix; prefix address in parm
|
||||
KVM_S390_RESTART (vcpu) - restart
|
||||
KVM_S390_INT_CLOCK_COMP (vcpu) - clock comparator interrupt
|
||||
KVM_S390_INT_CPU_TIMER (vcpu) - CPU timer interrupt
|
||||
KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt
|
||||
parameters in parm and parm64
|
||||
KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
|
||||
|
@ -132,7 +132,10 @@ struct kvm_s390_sie_block {
|
||||
psw_t gpsw; /* 0x0090 */
|
||||
__u64 gg14; /* 0x00a0 */
|
||||
__u64 gg15; /* 0x00a8 */
|
||||
__u8 reservedb0[28]; /* 0x00b0 */
|
||||
__u8 reservedb0[20]; /* 0x00b0 */
|
||||
__u16 extcpuaddr; /* 0x00c4 */
|
||||
__u16 eic; /* 0x00c6 */
|
||||
__u32 reservedc8; /* 0x00c8 */
|
||||
__u16 pgmilc; /* 0x00cc */
|
||||
__u16 iprcc; /* 0x00ce */
|
||||
__u32 dxc; /* 0x00d0 */
|
||||
|
@ -223,9 +223,10 @@ int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu,
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = copy_from_user(bp_data, dbg->arch.hw_bp, size);
|
||||
if (ret)
|
||||
if (copy_from_user(bp_data, dbg->arch.hw_bp, size)) {
|
||||
ret = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < dbg->arch.nr_hw_bp; i++) {
|
||||
switch (bp_data[i].type) {
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <asm/kvm_host.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "kvm-s390.h"
|
||||
#include "gaccess.h"
|
||||
@ -46,9 +47,6 @@ static int handle_noop(struct kvm_vcpu *vcpu)
|
||||
case 0x10:
|
||||
vcpu->stat.exit_external_request++;
|
||||
break;
|
||||
case 0x14:
|
||||
vcpu->stat.exit_external_interrupt++;
|
||||
break;
|
||||
default:
|
||||
break; /* nothing */
|
||||
}
|
||||
@ -233,6 +231,49 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
|
||||
return rc2;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_external_interrupt - used for external interruption interceptions
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u16 eic = vcpu->arch.sie_block->eic;
|
||||
struct kvm_s390_interrupt irq;
|
||||
psw_t newpsw;
|
||||
int rc;
|
||||
|
||||
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 ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
|
||||
(newpsw.mask & PSW_MASK_EXT))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (eic) {
|
||||
case EXT_IRQ_CLK_COMP:
|
||||
irq.type = KVM_S390_INT_CLOCK_COMP;
|
||||
break;
|
||||
case EXT_IRQ_CPU_TIMER:
|
||||
irq.type = KVM_S390_INT_CPU_TIMER;
|
||||
break;
|
||||
case EXT_IRQ_EXTERNAL_CALL:
|
||||
irq.type = KVM_S390_INT_EXTERNAL_CALL;
|
||||
irq.parm = vcpu->arch.sie_block->extcpuaddr;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return kvm_s390_inject_vcpu(vcpu, &irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle MOVE PAGE partial execution interception.
|
||||
*
|
||||
@ -291,7 +332,7 @@ static const intercept_handler_t intercept_funcs[] = {
|
||||
[0x08 >> 2] = handle_prog,
|
||||
[0x0C >> 2] = handle_instruction_and_prog,
|
||||
[0x10 >> 2] = handle_noop,
|
||||
[0x14 >> 2] = handle_noop,
|
||||
[0x14 >> 2] = handle_external_interrupt,
|
||||
[0x18 >> 2] = handle_noop,
|
||||
[0x1C >> 2] = kvm_s390_handle_wait,
|
||||
[0x20 >> 2] = handle_validity,
|
||||
|
@ -27,6 +27,8 @@
|
||||
#define IOINT_CSSID_MASK 0x03fc0000
|
||||
#define IOINT_AI_MASK 0x04000000
|
||||
|
||||
static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu);
|
||||
|
||||
static int is_ioint(u64 type)
|
||||
{
|
||||
return ((type & 0xfffe0000u) != 0xfffe0000u);
|
||||
@ -89,6 +91,14 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
|
||||
if (vcpu->arch.sie_block->gcr[0] & 0x4000ul)
|
||||
return 1;
|
||||
return 0;
|
||||
case KVM_S390_INT_CLOCK_COMP:
|
||||
return ckc_interrupts_enabled(vcpu);
|
||||
case KVM_S390_INT_CPU_TIMER:
|
||||
if (psw_extint_disabled(vcpu))
|
||||
return 0;
|
||||
if (vcpu->arch.sie_block->gcr[0] & 0x400ul)
|
||||
return 1;
|
||||
return 0;
|
||||
case KVM_S390_INT_SERVICE:
|
||||
case KVM_S390_INT_PFAULT_INIT:
|
||||
case KVM_S390_INT_PFAULT_DONE:
|
||||
@ -166,6 +176,8 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
|
||||
case KVM_S390_INT_PFAULT_INIT:
|
||||
case KVM_S390_INT_PFAULT_DONE:
|
||||
case KVM_S390_INT_VIRTIO:
|
||||
case KVM_S390_INT_CLOCK_COMP:
|
||||
case KVM_S390_INT_CPU_TIMER:
|
||||
if (psw_extint_disabled(vcpu))
|
||||
__set_cpuflag(vcpu, CPUSTAT_EXT_INT);
|
||||
else
|
||||
@ -326,6 +338,24 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
|
||||
&vcpu->arch.sie_block->gpsw,
|
||||
sizeof(psw_t));
|
||||
break;
|
||||
case KVM_S390_INT_CLOCK_COMP:
|
||||
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
|
||||
inti->ext.ext_params, 0);
|
||||
deliver_ckc_interrupt(vcpu);
|
||||
break;
|
||||
case KVM_S390_INT_CPU_TIMER:
|
||||
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
|
||||
inti->ext.ext_params, 0);
|
||||
rc = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
|
||||
(u16 *)__LC_EXT_INT_CODE);
|
||||
rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
|
||||
&vcpu->arch.sie_block->gpsw,
|
||||
sizeof(psw_t));
|
||||
rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
|
||||
&vcpu->arch.sie_block->gpsw, sizeof(psw_t));
|
||||
rc |= put_guest_lc(vcpu, inti->ext.ext_params,
|
||||
(u32 *)__LC_EXT_PARAMS);
|
||||
break;
|
||||
case KVM_S390_INT_SERVICE:
|
||||
VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
|
||||
inti->ext.ext_params);
|
||||
@ -984,6 +1014,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
|
||||
break;
|
||||
case KVM_S390_SIGP_STOP:
|
||||
case KVM_S390_RESTART:
|
||||
case KVM_S390_INT_CLOCK_COMP:
|
||||
case KVM_S390_INT_CPU_TIMER:
|
||||
VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
|
||||
inti->type = s390int->type;
|
||||
break;
|
||||
|
@ -416,6 +416,8 @@ struct kvm_s390_psw {
|
||||
#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
|
||||
#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
|
||||
#define KVM_S390_MCHK 0xfffe1000u
|
||||
#define KVM_S390_INT_CLOCK_COMP 0xffff1004u
|
||||
#define KVM_S390_INT_CPU_TIMER 0xffff1005u
|
||||
#define KVM_S390_INT_VIRTIO 0xffff2603u
|
||||
#define KVM_S390_INT_SERVICE 0xffff2401u
|
||||
#define KVM_S390_INT_EMERGENCY 0xffff1201u
|
||||
|
Loading…
Reference in New Issue
Block a user