]> git.karo-electronics.de Git - linux-beck.git/commitdiff
KVM: s390: PSW forwarding / rewinding / ilc rework
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Wed, 4 Nov 2015 12:47:58 +0000 (13:47 +0100)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Wed, 10 Feb 2016 12:12:49 +0000 (13:12 +0100)
We have some confusion about ilc vs. ilen in our current code. So let's
correctly use the term ilen when dealing with (ilc << 1).

Program irq injection didn't take care of the correct ilc in case of
irqs triggered by EXECUTE functions, let's provide one function
kvm_s390_get_ilen() to take care of all that.

Also, manually specifying in intercept handlers the size of the
instruction (and sometimes overwriting that value for EXECUTE internally)
doesn't make too much sense. So also provide the functions:
- kvm_s390_retry_instr to retry the currently intercepted instruction
- kvm_s390_rewind_psw to rewind the PSW without internal overwrites
- kvm_s390_forward_psw to forward the PSW

Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c

index d53c10753c466b47b6fcb4813ec9e3445ca47a04..7f992e02124a1809a286681cf6220fb4cff796f6 100644 (file)
@@ -38,17 +38,32 @@ static const intercept_handler_t instruction_handlers[256] = {
        [0xeb] = kvm_s390_handle_eb,
 };
 
-void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc)
+u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
+       u8 ilen = 0;
 
-       /* Use the length of the EXECUTE instruction if necessary */
-       if (sie_block->icptstatus & 1) {
-               ilc = (sie_block->icptstatus >> 4) & 0x6;
-               if (!ilc)
-                       ilc = 4;
+       switch (vcpu->arch.sie_block->icptcode) {
+       case ICPT_INST:
+       case ICPT_INSTPROGI:
+       case ICPT_OPEREXC:
+       case ICPT_PARTEXEC:
+       case ICPT_IOINST:
+               /* instruction only stored for these icptcodes */
+               ilen = insn_length(vcpu->arch.sie_block->ipa >> 8);
+               /* Use the length of the EXECUTE instruction if necessary */
+               if (sie_block->icptstatus & 1) {
+                       ilen = (sie_block->icptstatus >> 4) & 0x6;
+                       if (!ilen)
+                               ilen = 4;
+               }
+               break;
+       case ICPT_PROGI:
+               /* bit 1+2 of pgmilc are the ilc, so we directly get ilen */
+               ilen = vcpu->arch.sie_block->pgmilc & 0x6;
+               break;
        }
-       sie_block->gpsw.addr = __rewind_psw(sie_block->gpsw, ilc);
+       return ilen;
 }
 
 static int handle_noop(struct kvm_vcpu *vcpu)
@@ -318,7 +333,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu)
        if (rc != 0)
                return rc;
 
-       kvm_s390_rewind_psw(vcpu, 4);
+       kvm_s390_retry_instr(vcpu);
 
        return 0;
 }
index f88ca72c3a77a52e05e65cfa79206cd8e41aa786..daa4fdbcc91c645ce3734bee81b41ee3abf236d5 100644 (file)
@@ -335,23 +335,6 @@ static void set_intercept_indicators(struct kvm_vcpu *vcpu)
        set_intercept_indicators_stop(vcpu);
 }
 
-static u16 get_ilc(struct kvm_vcpu *vcpu)
-{
-       switch (vcpu->arch.sie_block->icptcode) {
-       case ICPT_INST:
-       case ICPT_INSTPROGI:
-       case ICPT_OPEREXC:
-       case ICPT_PARTEXEC:
-       case ICPT_IOINST:
-               /* last instruction only stored for these icptcodes */
-               return insn_length(vcpu->arch.sie_block->ipa >> 8);
-       case ICPT_PROGI:
-               return vcpu->arch.sie_block->pgmilc;
-       default:
-               return 0;
-       }
-}
-
 static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -588,7 +571,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        struct kvm_s390_pgm_info pgm_info;
        int rc = 0, nullifying = false;
-       u16 ilc = get_ilc(vcpu);
+       u16 ilen = kvm_s390_get_ilen(vcpu);
 
        spin_lock(&li->lock);
        pgm_info = li->irq.pgm;
@@ -596,8 +579,8 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
        memset(&li->irq.pgm, 0, sizeof(pgm_info));
        spin_unlock(&li->lock);
 
-       VCPU_EVENT(vcpu, 3, "deliver: program irq code 0x%x, ilc:%d",
-                  pgm_info.code, ilc);
+       VCPU_EVENT(vcpu, 3, "deliver: program irq code 0x%x, ilen:%d",
+                  pgm_info.code, ilen);
        vcpu->stat.deliver_program_int++;
        trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
                                         pgm_info.code, 0);
@@ -682,9 +665,10 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
        }
 
        if (nullifying && vcpu->arch.sie_block->icptcode == ICPT_INST)
-               kvm_s390_rewind_psw(vcpu, ilc);
+               kvm_s390_rewind_psw(vcpu, ilen);
 
-       rc |= put_guest_lc(vcpu, ilc, (u16 *) __LC_PGM_ILC);
+       /* bit 1+2 of the target are the ilc, so we can directly use ilen */
+       rc |= put_guest_lc(vcpu, ilen, (u16 *) __LC_PGM_ILC);
        rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->gbea,
                                 (u64 *) __LC_LAST_BREAK);
        rc |= put_guest_lc(vcpu, pgm_info.code,
index 2270fe4c8b71e7e4a16e3948d85fe15ab7369c21..cd84a3eeb214ef5ed6c4523c03021475da02a36f 100644 (file)
@@ -2181,7 +2181,7 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
        rc = read_guest(vcpu, psw->addr, 0, &opcode, 1);
        if (rc)
                return kvm_s390_inject_prog_cond(vcpu, rc);
-       psw->addr = __rewind_psw(*psw, -insn_length(opcode));
+       kvm_s390_forward_psw(vcpu, insn_length(opcode));
 
        return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
 }
index df1abada1f36dfc3579ab6ff2ef45c7db828490b..1c756c7dd0c2cdda4409ca496a09d5ece1beae94 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <asm/facility.h>
+#include <asm/processor.h>
 
 typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
 
@@ -212,8 +213,22 @@ int kvm_s390_reinject_io_int(struct kvm *kvm,
 int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
 
 /* implemented in intercept.c */
-void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc);
+u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu);
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
+static inline void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilen)
+{
+       struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
+
+       sie_block->gpsw.addr = __rewind_psw(sie_block->gpsw, ilen);
+}
+static inline void kvm_s390_forward_psw(struct kvm_vcpu *vcpu, int ilen)
+{
+       kvm_s390_rewind_psw(vcpu, -ilen);
+}
+static inline void kvm_s390_retry_instr(struct kvm_vcpu *vcpu)
+{
+       kvm_s390_rewind_psw(vcpu, kvm_s390_get_ilen(vcpu));
+}
 
 /* implemented in priv.c */
 int is_valid_psw(psw_t *psw);
index ed74e86d9b9eb60c88b2f91e671c9d9b9c56f316..d58cbe9813dbb853541266c8cff803d0d517422c 100644 (file)
@@ -173,7 +173,7 @@ static int handle_skey(struct kvm_vcpu *vcpu)
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
                return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
-       kvm_s390_rewind_psw(vcpu, 4);
+       kvm_s390_retry_instr(vcpu);
        VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
        return 0;
 }
@@ -184,7 +184,7 @@ static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
        if (psw_bits(vcpu->arch.sie_block->gpsw).p)
                return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
        wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu));
-       kvm_s390_rewind_psw(vcpu, 4);
+       kvm_s390_retry_instr(vcpu);
        VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation");
        return 0;
 }
@@ -759,8 +759,8 @@ static int handle_essa(struct kvm_vcpu *vcpu)
        if (((vcpu->arch.sie_block->ipb & 0xf0000000) >> 28) > 6)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
-       /* Rewind PSW to repeat the ESSA instruction */
-       kvm_s390_rewind_psw(vcpu, 4);
+       /* Retry the ESSA instruction */
+       kvm_s390_retry_instr(vcpu);
        vcpu->arch.sie_block->cbrlo &= PAGE_MASK;       /* reset nceo */
        cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
        down_read(&gmap->mm->mmap_sem);