18f2abe6aSChristian Borntraeger /* 2a53c8fabSHeiko Carstens * in-kernel handling for sie intercepts 38f2abe6aSChristian Borntraeger * 49a558ee3SThomas Huth * Copyright IBM Corp. 2008, 2014 58f2abe6aSChristian Borntraeger * 68f2abe6aSChristian Borntraeger * This program is free software; you can redistribute it and/or modify 78f2abe6aSChristian Borntraeger * it under the terms of the GNU General Public License (version 2 only) 88f2abe6aSChristian Borntraeger * as published by the Free Software Foundation. 98f2abe6aSChristian Borntraeger * 108f2abe6aSChristian Borntraeger * Author(s): Carsten Otte <cotte@de.ibm.com> 118f2abe6aSChristian Borntraeger * Christian Borntraeger <borntraeger@de.ibm.com> 128f2abe6aSChristian Borntraeger */ 138f2abe6aSChristian Borntraeger 148f2abe6aSChristian Borntraeger #include <linux/kvm_host.h> 158f2abe6aSChristian Borntraeger #include <linux/errno.h> 168f2abe6aSChristian Borntraeger #include <linux/pagemap.h> 178f2abe6aSChristian Borntraeger 188f2abe6aSChristian Borntraeger #include <asm/kvm_host.h> 19a86dcc24SMichael Mueller #include <asm/asm-offsets.h> 20*f14d82e0SThomas Huth #include <asm/irq.h> 218f2abe6aSChristian Borntraeger 228f2abe6aSChristian Borntraeger #include "kvm-s390.h" 23ba5c1e9bSCarsten Otte #include "gaccess.h" 245786fffaSCornelia Huck #include "trace.h" 25ade38c31SCornelia Huck #include "trace-s390.h" 26ba5c1e9bSCarsten Otte 27f379aae5SCornelia Huck 2877975357SCornelia Huck static const intercept_handler_t instruction_handlers[256] = { 298c3f61e2SCornelia Huck [0x01] = kvm_s390_handle_01, 3048a3e950SCornelia Huck [0x82] = kvm_s390_handle_lpsw, 31e28acfeaSChristian Borntraeger [0x83] = kvm_s390_handle_diag, 325288fbf0SChristian Borntraeger [0xae] = kvm_s390_handle_sigp, 3370455a36SChristian Borntraeger [0xb2] = kvm_s390_handle_b2, 34aba07508SDavid Hildenbrand [0xb6] = kvm_s390_handle_stctl, 35953ed88dSThomas Huth [0xb7] = kvm_s390_handle_lctl, 3648a3e950SCornelia Huck [0xb9] = kvm_s390_handle_b9, 37bb25b9baSChristian Borntraeger [0xe5] = kvm_s390_handle_e5, 38953ed88dSThomas Huth [0xeb] = kvm_s390_handle_eb, 39ba5c1e9bSCarsten Otte }; 408f2abe6aSChristian Borntraeger 418f2abe6aSChristian Borntraeger static int handle_noop(struct kvm_vcpu *vcpu) 428f2abe6aSChristian Borntraeger { 438f2abe6aSChristian Borntraeger switch (vcpu->arch.sie_block->icptcode) { 440eaeafa1SChristian Borntraeger case 0x0: 450eaeafa1SChristian Borntraeger vcpu->stat.exit_null++; 460eaeafa1SChristian Borntraeger break; 478f2abe6aSChristian Borntraeger case 0x10: 488f2abe6aSChristian Borntraeger vcpu->stat.exit_external_request++; 498f2abe6aSChristian Borntraeger break; 508f2abe6aSChristian Borntraeger default: 518f2abe6aSChristian Borntraeger break; /* nothing */ 528f2abe6aSChristian Borntraeger } 538f2abe6aSChristian Borntraeger return 0; 548f2abe6aSChristian Borntraeger } 558f2abe6aSChristian Borntraeger 568f2abe6aSChristian Borntraeger static int handle_stop(struct kvm_vcpu *vcpu) 578f2abe6aSChristian Borntraeger { 589ace903dSChristian Ehrhardt int rc = 0; 595288fbf0SChristian Borntraeger 608f2abe6aSChristian Borntraeger vcpu->stat.exit_stop_request++; 615288fbf0SChristian Borntraeger spin_lock_bh(&vcpu->arch.local_int.lock); 625288fbf0SChristian Borntraeger 63ade38c31SCornelia Huck trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits); 64ade38c31SCornelia Huck 655288fbf0SChristian Borntraeger if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { 666852d7b6SDavid Hildenbrand kvm_s390_vcpu_stop(vcpu); 675288fbf0SChristian Borntraeger vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; 685288fbf0SChristian Borntraeger VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); 69b8e660b8SHeiko Carstens rc = -EOPNOTSUPP; 709ace903dSChristian Ehrhardt } 719ace903dSChristian Ehrhardt 729e0d5473SJens Freimann if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) { 739e0d5473SJens Freimann vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP; 749e0d5473SJens Freimann /* store status must be called unlocked. Since local_int.lock 759e0d5473SJens Freimann * only protects local_int.* and not guest memory we can give 769e0d5473SJens Freimann * up the lock here */ 779e0d5473SJens Freimann spin_unlock_bh(&vcpu->arch.local_int.lock); 789e0d5473SJens Freimann rc = kvm_s390_vcpu_store_status(vcpu, 799e0d5473SJens Freimann KVM_S390_STORE_STATUS_NOADDR); 809e0d5473SJens Freimann if (rc >= 0) 819e0d5473SJens Freimann rc = -EOPNOTSUPP; 829e0d5473SJens Freimann } else 835288fbf0SChristian Borntraeger spin_unlock_bh(&vcpu->arch.local_int.lock); 845288fbf0SChristian Borntraeger return rc; 858f2abe6aSChristian Borntraeger } 868f2abe6aSChristian Borntraeger 878f2abe6aSChristian Borntraeger static int handle_validity(struct kvm_vcpu *vcpu) 888f2abe6aSChristian Borntraeger { 898f2abe6aSChristian Borntraeger int viwhy = vcpu->arch.sie_block->ipb >> 16; 903edbcff9SCarsten Otte 918f2abe6aSChristian Borntraeger vcpu->stat.exit_validity++; 925786fffaSCornelia Huck trace_kvm_s390_intercept_validity(vcpu, viwhy); 932c70fe44SChristian Borntraeger WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy); 942c70fe44SChristian Borntraeger return -EOPNOTSUPP; 958f2abe6aSChristian Borntraeger } 968f2abe6aSChristian Borntraeger 97ba5c1e9bSCarsten Otte static int handle_instruction(struct kvm_vcpu *vcpu) 98ba5c1e9bSCarsten Otte { 99ba5c1e9bSCarsten Otte intercept_handler_t handler; 100ba5c1e9bSCarsten Otte 101ba5c1e9bSCarsten Otte vcpu->stat.exit_instruction++; 1025786fffaSCornelia Huck trace_kvm_s390_intercept_instruction(vcpu, 1035786fffaSCornelia Huck vcpu->arch.sie_block->ipa, 1045786fffaSCornelia Huck vcpu->arch.sie_block->ipb); 105ba5c1e9bSCarsten Otte handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; 106ba5c1e9bSCarsten Otte if (handler) 107ba5c1e9bSCarsten Otte return handler(vcpu); 108b8e660b8SHeiko Carstens return -EOPNOTSUPP; 109ba5c1e9bSCarsten Otte } 110ba5c1e9bSCarsten Otte 111439716a5SDavid Hildenbrand static void __extract_prog_irq(struct kvm_vcpu *vcpu, 112439716a5SDavid Hildenbrand struct kvm_s390_pgm_info *pgm_info) 113439716a5SDavid Hildenbrand { 114439716a5SDavid Hildenbrand memset(pgm_info, 0, sizeof(struct kvm_s390_pgm_info)); 115439716a5SDavid Hildenbrand pgm_info->code = vcpu->arch.sie_block->iprcc; 116439716a5SDavid Hildenbrand 117439716a5SDavid Hildenbrand switch (vcpu->arch.sie_block->iprcc & ~PGM_PER) { 118439716a5SDavid Hildenbrand case PGM_AFX_TRANSLATION: 119439716a5SDavid Hildenbrand case PGM_ASX_TRANSLATION: 120439716a5SDavid Hildenbrand case PGM_EX_TRANSLATION: 121439716a5SDavid Hildenbrand case PGM_LFX_TRANSLATION: 122439716a5SDavid Hildenbrand case PGM_LSTE_SEQUENCE: 123439716a5SDavid Hildenbrand case PGM_LSX_TRANSLATION: 124439716a5SDavid Hildenbrand case PGM_LX_TRANSLATION: 125439716a5SDavid Hildenbrand case PGM_PRIMARY_AUTHORITY: 126439716a5SDavid Hildenbrand case PGM_SECONDARY_AUTHORITY: 127439716a5SDavid Hildenbrand case PGM_SPACE_SWITCH: 128439716a5SDavid Hildenbrand pgm_info->trans_exc_code = vcpu->arch.sie_block->tecmc; 129439716a5SDavid Hildenbrand break; 130439716a5SDavid Hildenbrand case PGM_ALEN_TRANSLATION: 131439716a5SDavid Hildenbrand case PGM_ALE_SEQUENCE: 132439716a5SDavid Hildenbrand case PGM_ASTE_INSTANCE: 133439716a5SDavid Hildenbrand case PGM_ASTE_SEQUENCE: 134439716a5SDavid Hildenbrand case PGM_ASTE_VALIDITY: 135439716a5SDavid Hildenbrand case PGM_EXTENDED_AUTHORITY: 136439716a5SDavid Hildenbrand pgm_info->exc_access_id = vcpu->arch.sie_block->eai; 137439716a5SDavid Hildenbrand break; 138439716a5SDavid Hildenbrand case PGM_ASCE_TYPE: 139439716a5SDavid Hildenbrand case PGM_PAGE_TRANSLATION: 140439716a5SDavid Hildenbrand case PGM_REGION_FIRST_TRANS: 141439716a5SDavid Hildenbrand case PGM_REGION_SECOND_TRANS: 142439716a5SDavid Hildenbrand case PGM_REGION_THIRD_TRANS: 143439716a5SDavid Hildenbrand case PGM_SEGMENT_TRANSLATION: 144439716a5SDavid Hildenbrand pgm_info->trans_exc_code = vcpu->arch.sie_block->tecmc; 145439716a5SDavid Hildenbrand pgm_info->exc_access_id = vcpu->arch.sie_block->eai; 146439716a5SDavid Hildenbrand pgm_info->op_access_id = vcpu->arch.sie_block->oai; 147439716a5SDavid Hildenbrand break; 148439716a5SDavid Hildenbrand case PGM_MONITOR: 149439716a5SDavid Hildenbrand pgm_info->mon_class_nr = vcpu->arch.sie_block->mcn; 150439716a5SDavid Hildenbrand pgm_info->mon_code = vcpu->arch.sie_block->tecmc; 151439716a5SDavid Hildenbrand break; 152439716a5SDavid Hildenbrand case PGM_DATA: 153439716a5SDavid Hildenbrand pgm_info->data_exc_code = vcpu->arch.sie_block->dxc; 154439716a5SDavid Hildenbrand break; 155439716a5SDavid Hildenbrand case PGM_PROTECTION: 156439716a5SDavid Hildenbrand pgm_info->trans_exc_code = vcpu->arch.sie_block->tecmc; 157439716a5SDavid Hildenbrand pgm_info->exc_access_id = vcpu->arch.sie_block->eai; 158439716a5SDavid Hildenbrand break; 159439716a5SDavid Hildenbrand default: 160439716a5SDavid Hildenbrand break; 161439716a5SDavid Hildenbrand } 162439716a5SDavid Hildenbrand 163439716a5SDavid Hildenbrand if (vcpu->arch.sie_block->iprcc & PGM_PER) { 164439716a5SDavid Hildenbrand pgm_info->per_code = vcpu->arch.sie_block->perc; 165439716a5SDavid Hildenbrand pgm_info->per_atmid = vcpu->arch.sie_block->peratmid; 166439716a5SDavid Hildenbrand pgm_info->per_address = vcpu->arch.sie_block->peraddr; 167439716a5SDavid Hildenbrand pgm_info->per_access_id = vcpu->arch.sie_block->peraid; 168439716a5SDavid Hildenbrand } 169439716a5SDavid Hildenbrand } 170439716a5SDavid Hildenbrand 171e325fe69SMichael Mueller /* 172e325fe69SMichael Mueller * restore ITDB to program-interruption TDB in guest lowcore 173e325fe69SMichael Mueller * and set TX abort indication if required 174e325fe69SMichael Mueller */ 175e325fe69SMichael Mueller static int handle_itdb(struct kvm_vcpu *vcpu) 176e325fe69SMichael Mueller { 177e325fe69SMichael Mueller struct kvm_s390_itdb *itdb; 178e325fe69SMichael Mueller int rc; 179e325fe69SMichael Mueller 180e325fe69SMichael Mueller if (!IS_TE_ENABLED(vcpu) || !IS_ITDB_VALID(vcpu)) 181e325fe69SMichael Mueller return 0; 182e325fe69SMichael Mueller if (current->thread.per_flags & PER_FLAG_NO_TE) 183e325fe69SMichael Mueller return 0; 184e325fe69SMichael Mueller itdb = (struct kvm_s390_itdb *)vcpu->arch.sie_block->itdba; 185e325fe69SMichael Mueller rc = write_guest_lc(vcpu, __LC_PGM_TDB, itdb, sizeof(*itdb)); 186e325fe69SMichael Mueller if (rc) 187e325fe69SMichael Mueller return rc; 188e325fe69SMichael Mueller memset(itdb, 0, sizeof(*itdb)); 189e325fe69SMichael Mueller 190e325fe69SMichael Mueller return 0; 191e325fe69SMichael Mueller } 192e325fe69SMichael Mueller 19327291e21SDavid Hildenbrand #define per_event(vcpu) (vcpu->arch.sie_block->iprcc & PGM_PER) 19427291e21SDavid Hildenbrand 195ba5c1e9bSCarsten Otte static int handle_prog(struct kvm_vcpu *vcpu) 196ba5c1e9bSCarsten Otte { 197439716a5SDavid Hildenbrand struct kvm_s390_pgm_info pgm_info; 1980040e7d2SHeiko Carstens int rc; 1990040e7d2SHeiko Carstens 200ba5c1e9bSCarsten Otte vcpu->stat.exit_program_interruption++; 2017feb6bb8SMichael Mueller 20227291e21SDavid Hildenbrand if (guestdbg_enabled(vcpu) && per_event(vcpu)) { 20327291e21SDavid Hildenbrand kvm_s390_handle_per_event(vcpu); 20427291e21SDavid Hildenbrand /* the interrupt might have been filtered out completely */ 20527291e21SDavid Hildenbrand if (vcpu->arch.sie_block->iprcc == 0) 20627291e21SDavid Hildenbrand return 0; 20727291e21SDavid Hildenbrand } 20827291e21SDavid Hildenbrand 209e325fe69SMichael Mueller trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); 210e325fe69SMichael Mueller 211e325fe69SMichael Mueller rc = handle_itdb(vcpu); 2120040e7d2SHeiko Carstens if (rc) 2130040e7d2SHeiko Carstens return rc; 214439716a5SDavid Hildenbrand 215e325fe69SMichael Mueller __extract_prog_irq(vcpu, &pgm_info); 216439716a5SDavid Hildenbrand return kvm_s390_inject_prog_irq(vcpu, &pgm_info); 217ba5c1e9bSCarsten Otte } 218ba5c1e9bSCarsten Otte 219ba5c1e9bSCarsten Otte static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) 220ba5c1e9bSCarsten Otte { 221ba5c1e9bSCarsten Otte int rc, rc2; 222ba5c1e9bSCarsten Otte 223ba5c1e9bSCarsten Otte vcpu->stat.exit_instr_and_program++; 224ba5c1e9bSCarsten Otte rc = handle_instruction(vcpu); 225ba5c1e9bSCarsten Otte rc2 = handle_prog(vcpu); 226ba5c1e9bSCarsten Otte 227b8e660b8SHeiko Carstens if (rc == -EOPNOTSUPP) 228ba5c1e9bSCarsten Otte vcpu->arch.sie_block->icptcode = 0x04; 229ba5c1e9bSCarsten Otte if (rc) 230ba5c1e9bSCarsten Otte return rc; 231ba5c1e9bSCarsten Otte return rc2; 232ba5c1e9bSCarsten Otte } 233ba5c1e9bSCarsten Otte 2349a558ee3SThomas Huth /** 235*f14d82e0SThomas Huth * handle_external_interrupt - used for external interruption interceptions 236*f14d82e0SThomas Huth * 237*f14d82e0SThomas Huth * This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if 238*f14d82e0SThomas Huth * the new PSW does not have external interrupts disabled. In the first case, 239*f14d82e0SThomas Huth * we've got to deliver the interrupt manually, and in the second case, we 240*f14d82e0SThomas Huth * drop to userspace to handle the situation there. 241*f14d82e0SThomas Huth */ 242*f14d82e0SThomas Huth static int handle_external_interrupt(struct kvm_vcpu *vcpu) 243*f14d82e0SThomas Huth { 244*f14d82e0SThomas Huth u16 eic = vcpu->arch.sie_block->eic; 245*f14d82e0SThomas Huth struct kvm_s390_interrupt irq; 246*f14d82e0SThomas Huth psw_t newpsw; 247*f14d82e0SThomas Huth int rc; 248*f14d82e0SThomas Huth 249*f14d82e0SThomas Huth vcpu->stat.exit_external_interrupt++; 250*f14d82e0SThomas Huth 251*f14d82e0SThomas Huth rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t)); 252*f14d82e0SThomas Huth if (rc) 253*f14d82e0SThomas Huth return rc; 254*f14d82e0SThomas Huth /* We can not handle clock comparator or timer interrupt with bad PSW */ 255*f14d82e0SThomas Huth if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) && 256*f14d82e0SThomas Huth (newpsw.mask & PSW_MASK_EXT)) 257*f14d82e0SThomas Huth return -EOPNOTSUPP; 258*f14d82e0SThomas Huth 259*f14d82e0SThomas Huth switch (eic) { 260*f14d82e0SThomas Huth case EXT_IRQ_CLK_COMP: 261*f14d82e0SThomas Huth irq.type = KVM_S390_INT_CLOCK_COMP; 262*f14d82e0SThomas Huth break; 263*f14d82e0SThomas Huth case EXT_IRQ_CPU_TIMER: 264*f14d82e0SThomas Huth irq.type = KVM_S390_INT_CPU_TIMER; 265*f14d82e0SThomas Huth break; 266*f14d82e0SThomas Huth case EXT_IRQ_EXTERNAL_CALL: 267*f14d82e0SThomas Huth irq.type = KVM_S390_INT_EXTERNAL_CALL; 268*f14d82e0SThomas Huth irq.parm = vcpu->arch.sie_block->extcpuaddr; 269*f14d82e0SThomas Huth break; 270*f14d82e0SThomas Huth default: 271*f14d82e0SThomas Huth return -EOPNOTSUPP; 272*f14d82e0SThomas Huth } 273*f14d82e0SThomas Huth 274*f14d82e0SThomas Huth return kvm_s390_inject_vcpu(vcpu, &irq); 275*f14d82e0SThomas Huth } 276*f14d82e0SThomas Huth 277*f14d82e0SThomas Huth /** 2789a558ee3SThomas Huth * Handle MOVE PAGE partial execution interception. 2799a558ee3SThomas Huth * 2809a558ee3SThomas Huth * This interception can only happen for guests with DAT disabled and 2819a558ee3SThomas Huth * addresses that are currently not mapped in the host. Thus we try to 2829a558ee3SThomas Huth * set up the mappings for the corresponding user pages here (or throw 2839a558ee3SThomas Huth * addressing exceptions in case of illegal guest addresses). 2849a558ee3SThomas Huth */ 2859a558ee3SThomas Huth static int handle_mvpg_pei(struct kvm_vcpu *vcpu) 2869a558ee3SThomas Huth { 2879a558ee3SThomas Huth unsigned long hostaddr, srcaddr, dstaddr; 2889a558ee3SThomas Huth psw_t *psw = &vcpu->arch.sie_block->gpsw; 2899a558ee3SThomas Huth struct mm_struct *mm = current->mm; 2909a558ee3SThomas Huth int reg1, reg2, rc; 2919a558ee3SThomas Huth 2929a558ee3SThomas Huth kvm_s390_get_regs_rre(vcpu, ®1, ®2); 2939a558ee3SThomas Huth srcaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg2]); 2949a558ee3SThomas Huth dstaddr = kvm_s390_real_to_abs(vcpu, vcpu->run->s.regs.gprs[reg1]); 2959a558ee3SThomas Huth 2969a558ee3SThomas Huth /* Make sure that the source is paged-in */ 2979a558ee3SThomas Huth hostaddr = gmap_fault(srcaddr, vcpu->arch.gmap); 2989a558ee3SThomas Huth if (IS_ERR_VALUE(hostaddr)) 2999a558ee3SThomas Huth return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 3009a558ee3SThomas Huth down_read(&mm->mmap_sem); 3019a558ee3SThomas Huth rc = get_user_pages(current, mm, hostaddr, 1, 0, 0, NULL, NULL); 3029a558ee3SThomas Huth up_read(&mm->mmap_sem); 3039a558ee3SThomas Huth if (rc < 0) 3049a558ee3SThomas Huth return rc; 3059a558ee3SThomas Huth 3069a558ee3SThomas Huth /* Make sure that the destination is paged-in */ 3079a558ee3SThomas Huth hostaddr = gmap_fault(dstaddr, vcpu->arch.gmap); 3089a558ee3SThomas Huth if (IS_ERR_VALUE(hostaddr)) 3099a558ee3SThomas Huth return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 3109a558ee3SThomas Huth down_read(&mm->mmap_sem); 3119a558ee3SThomas Huth rc = get_user_pages(current, mm, hostaddr, 1, 1, 0, NULL, NULL); 3129a558ee3SThomas Huth up_read(&mm->mmap_sem); 3139a558ee3SThomas Huth if (rc < 0) 3149a558ee3SThomas Huth return rc; 3159a558ee3SThomas Huth 3169a558ee3SThomas Huth psw->addr = __rewind_psw(*psw, 4); 3179a558ee3SThomas Huth 3189a558ee3SThomas Huth return 0; 3199a558ee3SThomas Huth } 3209a558ee3SThomas Huth 3219a558ee3SThomas Huth static int handle_partial_execution(struct kvm_vcpu *vcpu) 3229a558ee3SThomas Huth { 3239a558ee3SThomas Huth if (vcpu->arch.sie_block->ipa == 0xb254) /* MVPG */ 3249a558ee3SThomas Huth return handle_mvpg_pei(vcpu); 3259a558ee3SThomas Huth 3269a558ee3SThomas Huth return -EOPNOTSUPP; 3279a558ee3SThomas Huth } 3289a558ee3SThomas Huth 329062d5e9bSChristian Borntraeger static const intercept_handler_t intercept_funcs[] = { 3308f2abe6aSChristian Borntraeger [0x00 >> 2] = handle_noop, 331ba5c1e9bSCarsten Otte [0x04 >> 2] = handle_instruction, 332ba5c1e9bSCarsten Otte [0x08 >> 2] = handle_prog, 333ba5c1e9bSCarsten Otte [0x0C >> 2] = handle_instruction_and_prog, 3348f2abe6aSChristian Borntraeger [0x10 >> 2] = handle_noop, 335*f14d82e0SThomas Huth [0x14 >> 2] = handle_external_interrupt, 336fa6b7fe9SCornelia Huck [0x18 >> 2] = handle_noop, 337ba5c1e9bSCarsten Otte [0x1C >> 2] = kvm_s390_handle_wait, 3388f2abe6aSChristian Borntraeger [0x20 >> 2] = handle_validity, 3398f2abe6aSChristian Borntraeger [0x28 >> 2] = handle_stop, 3409a558ee3SThomas Huth [0x38 >> 2] = handle_partial_execution, 3418f2abe6aSChristian Borntraeger }; 3428f2abe6aSChristian Borntraeger 3438f2abe6aSChristian Borntraeger int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) 3448f2abe6aSChristian Borntraeger { 3458f2abe6aSChristian Borntraeger intercept_handler_t func; 3468f2abe6aSChristian Borntraeger u8 code = vcpu->arch.sie_block->icptcode; 3478f2abe6aSChristian Borntraeger 348062d5e9bSChristian Borntraeger if (code & 3 || (code >> 2) >= ARRAY_SIZE(intercept_funcs)) 349b8e660b8SHeiko Carstens return -EOPNOTSUPP; 3508f2abe6aSChristian Borntraeger func = intercept_funcs[code >> 2]; 3518f2abe6aSChristian Borntraeger if (func) 3528f2abe6aSChristian Borntraeger return func(vcpu); 353b8e660b8SHeiko Carstens return -EOPNOTSUPP; 3548f2abe6aSChristian Borntraeger } 355