aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/intercept.c
diff options
context:
space:
mode:
authorThomas Huth <thuth@linux.vnet.ibm.com>2014-11-12 17:13:29 +0100
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-11-28 12:32:56 +0100
commit04b41acd060541fa76407d4de1e0acf0edd57c2a (patch)
tree2672c0911920ece6247afb7d0be6631ee4e45258 /arch/s390/kvm/intercept.c
parentKVM: s390: Small fixes for the PFMF handler (diff)
downloadlinux-dev-04b41acd060541fa76407d4de1e0acf0edd57c2a.tar.xz
linux-dev-04b41acd060541fa76407d4de1e0acf0edd57c2a.zip
KVM: s390: Fix rewinding of the PSW pointing to an EXECUTE instruction
A couple of our interception handlers rewind the PSW to the beginning of the instruction to run the intercepted instruction again during the next SIE entry. This normally works fine, but there is also the possibility that the instruction did not get run directly but via an EXECUTE instruction. In this case, the PSW does not point to the instruction that caused the interception, but to the EXECUTE instruction! So we've got to rewind the PSW to the beginning of the EXECUTE instruction instead. This is now accomplished with a new helper function kvm_s390_rewind_psw(). Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com> Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm/intercept.c')
-rw-r--r--arch/s390/kvm/intercept.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index eaf46291d361..1d244df5f8c4 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -38,6 +38,19 @@ static const intercept_handler_t instruction_handlers[256] = {
[0xeb] = kvm_s390_handle_eb,
};
+void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc)
+{
+ struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
+
+ /* Use the length of the EXECUTE instruction if necessary */
+ if (sie_block->icptstatus & 1) {
+ ilc = (sie_block->icptstatus >> 4) & 0x6;
+ if (!ilc)
+ ilc = 4;
+ }
+ sie_block->gpsw.addr = __rewind_psw(sie_block->gpsw, ilc);
+}
+
static int handle_noop(struct kvm_vcpu *vcpu)
{
switch (vcpu->arch.sie_block->icptcode) {
@@ -288,7 +301,6 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
*/
static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
{
- psw_t *psw = &vcpu->arch.sie_block->gpsw;
unsigned long srcaddr, dstaddr;
int reg1, reg2, rc;
@@ -310,7 +322,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
if (rc != 0)
return rc;
- psw->addr = __rewind_psw(*psw, 4);
+ kvm_s390_rewind_psw(vcpu, 4);
return 0;
}