KVM: s390: deliver program irq parameters and use correct ilc
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Mon, 3 Mar 2014 09:55:13 +0000 (10:55 +0100)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Tue, 22 Apr 2014 11:24:49 +0000 (13:24 +0200)
When a program interrupt was to be delivered until now, no program interrupt
parameters were stored in the low-core of the target vcpu.

This patch enables the delivery of those program interrupt parameters, takes
care of concurrent PER events which can be injected in addition to any program
interrupt and uses the correct instruction length code (depending on the
interception code) for the injection of program interrupts.

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

index b8c808192893168b4dd66c6cc8e0cd1ad88a6ddb..5e5a14db8c21ed6196eed18c7b6ef5c99fcbda8c 100644 (file)
@@ -102,6 +102,12 @@ struct kvm_s390_sie_block {
 #define ICTL_RRBE 0x00001000
        __u32   ictl;                   /* 0x0048 */
        __u32   eca;                    /* 0x004c */
+#define ICPT_INST      0x04
+#define ICPT_PROGI     0x08
+#define ICPT_INSTPROGI 0x0C
+#define ICPT_OPEREXC   0x2C
+#define ICPT_PARTEXEC  0x38
+#define ICPT_IOINST    0x40
        __u8    icptcode;               /* 0x0050 */
        __u8    reserved51;             /* 0x0051 */
        __u16   ihcpu;                  /* 0x0052 */
index 1c74bb92329b513521b99fb77a60f5a617ae68e7..c49b4d4d310a2fba246f78ab71a7811ae13dc0d5 100644 (file)
@@ -174,6 +174,106 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
        }
 }
 
+static int __deliver_prog_irq(struct kvm_vcpu *vcpu,
+                             struct kvm_s390_pgm_info *pgm_info)
+{
+       const unsigned short table[] = { 2, 4, 4, 6 };
+       int rc = 0;
+
+       switch (pgm_info->code & ~PGM_PER) {
+       case PGM_AFX_TRANSLATION:
+       case PGM_ASX_TRANSLATION:
+       case PGM_EX_TRANSLATION:
+       case PGM_LFX_TRANSLATION:
+       case PGM_LSTE_SEQUENCE:
+       case PGM_LSX_TRANSLATION:
+       case PGM_LX_TRANSLATION:
+       case PGM_PRIMARY_AUTHORITY:
+       case PGM_SECONDARY_AUTHORITY:
+       case PGM_SPACE_SWITCH:
+               rc = put_guest_lc(vcpu, pgm_info->trans_exc_code,
+                                 (u64 *)__LC_TRANS_EXC_CODE);
+               break;
+       case PGM_ALEN_TRANSLATION:
+       case PGM_ALE_SEQUENCE:
+       case PGM_ASTE_INSTANCE:
+       case PGM_ASTE_SEQUENCE:
+       case PGM_ASTE_VALIDITY:
+       case PGM_EXTENDED_AUTHORITY:
+               rc = put_guest_lc(vcpu, pgm_info->exc_access_id,
+                                 (u8 *)__LC_EXC_ACCESS_ID);
+               break;
+       case PGM_ASCE_TYPE:
+       case PGM_PAGE_TRANSLATION:
+       case PGM_REGION_FIRST_TRANS:
+       case PGM_REGION_SECOND_TRANS:
+       case PGM_REGION_THIRD_TRANS:
+       case PGM_SEGMENT_TRANSLATION:
+               rc = put_guest_lc(vcpu, pgm_info->trans_exc_code,
+                                 (u64 *)__LC_TRANS_EXC_CODE);
+               rc |= put_guest_lc(vcpu, pgm_info->exc_access_id,
+                                  (u8 *)__LC_EXC_ACCESS_ID);
+               rc |= put_guest_lc(vcpu, pgm_info->op_access_id,
+                                  (u8 *)__LC_OP_ACCESS_ID);
+               break;
+       case PGM_MONITOR:
+               rc = put_guest_lc(vcpu, pgm_info->mon_class_nr,
+                                 (u64 *)__LC_MON_CLASS_NR);
+               rc |= put_guest_lc(vcpu, pgm_info->mon_code,
+                                  (u64 *)__LC_MON_CODE);
+               break;
+       case PGM_DATA:
+               rc = put_guest_lc(vcpu, pgm_info->data_exc_code,
+                                 (u32 *)__LC_DATA_EXC_CODE);
+               break;
+       case PGM_PROTECTION:
+               rc = put_guest_lc(vcpu, pgm_info->trans_exc_code,
+                                 (u64 *)__LC_TRANS_EXC_CODE);
+               rc |= put_guest_lc(vcpu, pgm_info->exc_access_id,
+                                  (u8 *)__LC_EXC_ACCESS_ID);
+               break;
+       }
+
+       if (pgm_info->code & PGM_PER) {
+               rc |= put_guest_lc(vcpu, pgm_info->per_code,
+                                  (u8 *) __LC_PER_CODE);
+               rc |= put_guest_lc(vcpu, pgm_info->per_atmid,
+                                  (u8 *)__LC_PER_ATMID);
+               rc |= put_guest_lc(vcpu, pgm_info->per_address,
+                                  (u64 *) __LC_PER_ADDRESS);
+               rc |= put_guest_lc(vcpu, pgm_info->per_access_id,
+                                  (u8 *) __LC_PER_ACCESS_ID);
+       }
+
+       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 */
+               rc |= put_guest_lc(vcpu, table[vcpu->arch.sie_block->ipa >> 14],
+                                  (u16 *) __LC_PGM_ILC);
+               break;
+       case ICPT_PROGI:
+               rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->pgmilc,
+                                  (u16 *) __LC_PGM_ILC);
+               break;
+       default:
+               rc |= put_guest_lc(vcpu, 0,
+                                  (u16 *) __LC_PGM_ILC);
+       }
+
+       rc |= put_guest_lc(vcpu, pgm_info->code,
+                          (u16 *)__LC_PGM_INT_CODE);
+       rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW,
+                            &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+       rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW,
+                           &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+
+       return rc;
+}
+
 static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                                   struct kvm_s390_interrupt_info *inti)
 {
@@ -305,15 +405,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                vcpu->stat.deliver_program_int++;
                trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
                                                 inti->pgm.code, 0);
-               rc  = put_guest_lc(vcpu, inti->pgm.code,
-                                  (u16 __user *)__LC_PGM_INT_CODE);
-               rc |= put_guest_lc(vcpu, table[vcpu->arch.sie_block->ipa >> 14],
-                                  (u16 __user *)__LC_PGM_ILC);
-               rc |= write_guest_lc(vcpu, __LC_PGM_OLD_PSW,
-                                    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
-               rc |= read_guest_lc(vcpu, __LC_PGM_NEW_PSW,
-                                   &vcpu->arch.sie_block->gpsw,
-                                   sizeof(psw_t));
+               rc = __deliver_prog_irq(vcpu, &inti->pgm);
                break;
 
        case KVM_S390_MCHK: