18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * in-kernel handling for sie intercepts 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2008, 2020 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author(s): Carsten Otte <cotte@de.ibm.com> 88c2ecf20Sopenharmony_ci * Christian Borntraeger <borntraeger@de.ibm.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 168c2ecf20Sopenharmony_ci#include <asm/irq.h> 178c2ecf20Sopenharmony_ci#include <asm/sysinfo.h> 188c2ecf20Sopenharmony_ci#include <asm/uv.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "kvm-s390.h" 218c2ecf20Sopenharmony_ci#include "gaccess.h" 228c2ecf20Sopenharmony_ci#include "trace.h" 238c2ecf20Sopenharmony_ci#include "trace-s390.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciu8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block; 288c2ecf20Sopenharmony_ci u8 ilen = 0; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->icptcode) { 318c2ecf20Sopenharmony_ci case ICPT_INST: 328c2ecf20Sopenharmony_ci case ICPT_INSTPROGI: 338c2ecf20Sopenharmony_ci case ICPT_OPEREXC: 348c2ecf20Sopenharmony_ci case ICPT_PARTEXEC: 358c2ecf20Sopenharmony_ci case ICPT_IOINST: 368c2ecf20Sopenharmony_ci /* instruction only stored for these icptcodes */ 378c2ecf20Sopenharmony_ci ilen = insn_length(vcpu->arch.sie_block->ipa >> 8); 388c2ecf20Sopenharmony_ci /* Use the length of the EXECUTE instruction if necessary */ 398c2ecf20Sopenharmony_ci if (sie_block->icptstatus & 1) { 408c2ecf20Sopenharmony_ci ilen = (sie_block->icptstatus >> 4) & 0x6; 418c2ecf20Sopenharmony_ci if (!ilen) 428c2ecf20Sopenharmony_ci ilen = 4; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case ICPT_PROGI: 468c2ecf20Sopenharmony_ci /* bit 1+2 of pgmilc are the ilc, so we directly get ilen */ 478c2ecf20Sopenharmony_ci ilen = vcpu->arch.sie_block->pgmilc & 0x6; 488c2ecf20Sopenharmony_ci break; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci return ilen; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int handle_stop(struct kvm_vcpu *vcpu) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 568c2ecf20Sopenharmony_ci int rc = 0; 578c2ecf20Sopenharmony_ci uint8_t flags, stop_pending; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci vcpu->stat.exit_stop_request++; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* delay the stop if any non-stop irq is pending */ 628c2ecf20Sopenharmony_ci if (kvm_s390_vcpu_has_irq(vcpu, 1)) 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* avoid races with the injection/SIGP STOP code */ 668c2ecf20Sopenharmony_ci spin_lock(&li->lock); 678c2ecf20Sopenharmony_ci flags = li->irq.stop.flags; 688c2ecf20Sopenharmony_ci stop_pending = kvm_s390_is_stop_irq_pending(vcpu); 698c2ecf20Sopenharmony_ci spin_unlock(&li->lock); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci trace_kvm_s390_stop_request(stop_pending, flags); 728c2ecf20Sopenharmony_ci if (!stop_pending) 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (flags & KVM_S390_STOP_FLAG_STORE_STATUS) { 768c2ecf20Sopenharmony_ci rc = kvm_s390_vcpu_store_status(vcpu, 778c2ecf20Sopenharmony_ci KVM_S390_STORE_STATUS_NOADDR); 788c2ecf20Sopenharmony_ci if (rc) 798c2ecf20Sopenharmony_ci return rc; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * no need to check the return value of vcpu_stop as it can only have 848c2ecf20Sopenharmony_ci * an error for protvirt, but protvirt means user cpu state 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) 878c2ecf20Sopenharmony_ci kvm_s390_vcpu_stop(vcpu); 888c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int handle_validity(struct kvm_vcpu *vcpu) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int viwhy = vcpu->arch.sie_block->ipb >> 16; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci vcpu->stat.exit_validity++; 968c2ecf20Sopenharmony_ci trace_kvm_s390_intercept_validity(vcpu, viwhy); 978c2ecf20Sopenharmony_ci KVM_EVENT(3, "validity intercept 0x%x for pid %u (kvm 0x%pK)", viwhy, 988c2ecf20Sopenharmony_ci current->pid, vcpu->kvm); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* do not warn on invalid runtime instrumentation mode */ 1018c2ecf20Sopenharmony_ci WARN_ONCE(viwhy != 0x44, "kvm: unhandled validity intercept 0x%x\n", 1028c2ecf20Sopenharmony_ci viwhy); 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int handle_instruction(struct kvm_vcpu *vcpu) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci vcpu->stat.exit_instruction++; 1098c2ecf20Sopenharmony_ci trace_kvm_s390_intercept_instruction(vcpu, 1108c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ipa, 1118c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ipb); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->ipa >> 8) { 1148c2ecf20Sopenharmony_ci case 0x01: 1158c2ecf20Sopenharmony_ci return kvm_s390_handle_01(vcpu); 1168c2ecf20Sopenharmony_ci case 0x82: 1178c2ecf20Sopenharmony_ci return kvm_s390_handle_lpsw(vcpu); 1188c2ecf20Sopenharmony_ci case 0x83: 1198c2ecf20Sopenharmony_ci return kvm_s390_handle_diag(vcpu); 1208c2ecf20Sopenharmony_ci case 0xaa: 1218c2ecf20Sopenharmony_ci return kvm_s390_handle_aa(vcpu); 1228c2ecf20Sopenharmony_ci case 0xae: 1238c2ecf20Sopenharmony_ci return kvm_s390_handle_sigp(vcpu); 1248c2ecf20Sopenharmony_ci case 0xb2: 1258c2ecf20Sopenharmony_ci return kvm_s390_handle_b2(vcpu); 1268c2ecf20Sopenharmony_ci case 0xb6: 1278c2ecf20Sopenharmony_ci return kvm_s390_handle_stctl(vcpu); 1288c2ecf20Sopenharmony_ci case 0xb7: 1298c2ecf20Sopenharmony_ci return kvm_s390_handle_lctl(vcpu); 1308c2ecf20Sopenharmony_ci case 0xb9: 1318c2ecf20Sopenharmony_ci return kvm_s390_handle_b9(vcpu); 1328c2ecf20Sopenharmony_ci case 0xe3: 1338c2ecf20Sopenharmony_ci return kvm_s390_handle_e3(vcpu); 1348c2ecf20Sopenharmony_ci case 0xe5: 1358c2ecf20Sopenharmony_ci return kvm_s390_handle_e5(vcpu); 1368c2ecf20Sopenharmony_ci case 0xeb: 1378c2ecf20Sopenharmony_ci return kvm_s390_handle_eb(vcpu); 1388c2ecf20Sopenharmony_ci default: 1398c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int inject_prog_on_prog_intercept(struct kvm_vcpu *vcpu) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct kvm_s390_pgm_info pgm_info = { 1468c2ecf20Sopenharmony_ci .code = vcpu->arch.sie_block->iprcc, 1478c2ecf20Sopenharmony_ci /* the PSW has already been rewound */ 1488c2ecf20Sopenharmony_ci .flags = KVM_S390_PGM_FLAGS_NO_REWIND, 1498c2ecf20Sopenharmony_ci }; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->iprcc & ~PGM_PER) { 1528c2ecf20Sopenharmony_ci case PGM_AFX_TRANSLATION: 1538c2ecf20Sopenharmony_ci case PGM_ASX_TRANSLATION: 1548c2ecf20Sopenharmony_ci case PGM_EX_TRANSLATION: 1558c2ecf20Sopenharmony_ci case PGM_LFX_TRANSLATION: 1568c2ecf20Sopenharmony_ci case PGM_LSTE_SEQUENCE: 1578c2ecf20Sopenharmony_ci case PGM_LSX_TRANSLATION: 1588c2ecf20Sopenharmony_ci case PGM_LX_TRANSLATION: 1598c2ecf20Sopenharmony_ci case PGM_PRIMARY_AUTHORITY: 1608c2ecf20Sopenharmony_ci case PGM_SECONDARY_AUTHORITY: 1618c2ecf20Sopenharmony_ci case PGM_SPACE_SWITCH: 1628c2ecf20Sopenharmony_ci pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci case PGM_ALEN_TRANSLATION: 1658c2ecf20Sopenharmony_ci case PGM_ALE_SEQUENCE: 1668c2ecf20Sopenharmony_ci case PGM_ASTE_INSTANCE: 1678c2ecf20Sopenharmony_ci case PGM_ASTE_SEQUENCE: 1688c2ecf20Sopenharmony_ci case PGM_ASTE_VALIDITY: 1698c2ecf20Sopenharmony_ci case PGM_EXTENDED_AUTHORITY: 1708c2ecf20Sopenharmony_ci pgm_info.exc_access_id = vcpu->arch.sie_block->eai; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci case PGM_ASCE_TYPE: 1738c2ecf20Sopenharmony_ci case PGM_PAGE_TRANSLATION: 1748c2ecf20Sopenharmony_ci case PGM_REGION_FIRST_TRANS: 1758c2ecf20Sopenharmony_ci case PGM_REGION_SECOND_TRANS: 1768c2ecf20Sopenharmony_ci case PGM_REGION_THIRD_TRANS: 1778c2ecf20Sopenharmony_ci case PGM_SEGMENT_TRANSLATION: 1788c2ecf20Sopenharmony_ci pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc; 1798c2ecf20Sopenharmony_ci pgm_info.exc_access_id = vcpu->arch.sie_block->eai; 1808c2ecf20Sopenharmony_ci pgm_info.op_access_id = vcpu->arch.sie_block->oai; 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci case PGM_MONITOR: 1838c2ecf20Sopenharmony_ci pgm_info.mon_class_nr = vcpu->arch.sie_block->mcn; 1848c2ecf20Sopenharmony_ci pgm_info.mon_code = vcpu->arch.sie_block->tecmc; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci case PGM_VECTOR_PROCESSING: 1878c2ecf20Sopenharmony_ci case PGM_DATA: 1888c2ecf20Sopenharmony_ci pgm_info.data_exc_code = vcpu->arch.sie_block->dxc; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci case PGM_PROTECTION: 1918c2ecf20Sopenharmony_ci pgm_info.trans_exc_code = vcpu->arch.sie_block->tecmc; 1928c2ecf20Sopenharmony_ci pgm_info.exc_access_id = vcpu->arch.sie_block->eai; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci default: 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->iprcc & PGM_PER) { 1998c2ecf20Sopenharmony_ci pgm_info.per_code = vcpu->arch.sie_block->perc; 2008c2ecf20Sopenharmony_ci pgm_info.per_atmid = vcpu->arch.sie_block->peratmid; 2018c2ecf20Sopenharmony_ci pgm_info.per_address = vcpu->arch.sie_block->peraddr; 2028c2ecf20Sopenharmony_ci pgm_info.per_access_id = vcpu->arch.sie_block->peraid; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_irq(vcpu, &pgm_info); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * restore ITDB to program-interruption TDB in guest lowcore 2098c2ecf20Sopenharmony_ci * and set TX abort indication if required 2108c2ecf20Sopenharmony_ci*/ 2118c2ecf20Sopenharmony_cistatic int handle_itdb(struct kvm_vcpu *vcpu) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct kvm_s390_itdb *itdb; 2148c2ecf20Sopenharmony_ci int rc; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!IS_TE_ENABLED(vcpu) || !IS_ITDB_VALID(vcpu)) 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci if (current->thread.per_flags & PER_FLAG_NO_TE) 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci itdb = (struct kvm_s390_itdb *)vcpu->arch.sie_block->itdba; 2218c2ecf20Sopenharmony_ci rc = write_guest_lc(vcpu, __LC_PGM_TDB, itdb, sizeof(*itdb)); 2228c2ecf20Sopenharmony_ci if (rc) 2238c2ecf20Sopenharmony_ci return rc; 2248c2ecf20Sopenharmony_ci memset(itdb, 0, sizeof(*itdb)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define per_event(vcpu) (vcpu->arch.sie_block->iprcc & PGM_PER) 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int handle_prog(struct kvm_vcpu *vcpu) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci psw_t psw; 2348c2ecf20Sopenharmony_ci int rc; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci vcpu->stat.exit_program_interruption++; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * Intercept 8 indicates a loop of specification exceptions 2408c2ecf20Sopenharmony_ci * for protected guests. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) 2438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (guestdbg_enabled(vcpu) && per_event(vcpu)) { 2468c2ecf20Sopenharmony_ci rc = kvm_s390_handle_per_event(vcpu); 2478c2ecf20Sopenharmony_ci if (rc) 2488c2ecf20Sopenharmony_ci return rc; 2498c2ecf20Sopenharmony_ci /* the interrupt might have been filtered out completely */ 2508c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->iprcc == 0) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); 2558c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->iprcc == PGM_SPECIFICATION) { 2568c2ecf20Sopenharmony_ci rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &psw, sizeof(psw_t)); 2578c2ecf20Sopenharmony_ci if (rc) 2588c2ecf20Sopenharmony_ci return rc; 2598c2ecf20Sopenharmony_ci /* Avoid endless loops of specification exceptions */ 2608c2ecf20Sopenharmony_ci if (!is_valid_psw(&psw)) 2618c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci rc = handle_itdb(vcpu); 2648c2ecf20Sopenharmony_ci if (rc) 2658c2ecf20Sopenharmony_ci return rc; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return inject_prog_on_prog_intercept(vcpu); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/** 2718c2ecf20Sopenharmony_ci * handle_external_interrupt - used for external interruption interceptions 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * This interception occurs if: 2748c2ecf20Sopenharmony_ci * - the CPUSTAT_EXT_INT bit was already set when the external interrupt 2758c2ecf20Sopenharmony_ci * occurred. In this case, the interrupt needs to be injected manually to 2768c2ecf20Sopenharmony_ci * preserve interrupt priority. 2778c2ecf20Sopenharmony_ci * - the external new PSW has external interrupts enabled, which will cause an 2788c2ecf20Sopenharmony_ci * interruption loop. We drop to userspace in this case. 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * The latter case can be detected by inspecting the external mask bit in the 2818c2ecf20Sopenharmony_ci * external new psw. 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Under PV, only the latter case can occur, since interrupt priorities are 2848c2ecf20Sopenharmony_ci * handled in the ultravisor. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_cistatic int handle_external_interrupt(struct kvm_vcpu *vcpu) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci u16 eic = vcpu->arch.sie_block->eic; 2898c2ecf20Sopenharmony_ci struct kvm_s390_irq irq; 2908c2ecf20Sopenharmony_ci psw_t newpsw; 2918c2ecf20Sopenharmony_ci int rc; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci vcpu->stat.exit_external_interrupt++; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 2968c2ecf20Sopenharmony_ci newpsw = vcpu->arch.sie_block->gpsw; 2978c2ecf20Sopenharmony_ci } else { 2988c2ecf20Sopenharmony_ci rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t)); 2998c2ecf20Sopenharmony_ci if (rc) 3008c2ecf20Sopenharmony_ci return rc; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Clock comparator or timer interrupt with external interrupt enabled 3058c2ecf20Sopenharmony_ci * will cause interrupt loop. Drop to userspace. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) && 3088c2ecf20Sopenharmony_ci (newpsw.mask & PSW_MASK_EXT)) 3098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci switch (eic) { 3128c2ecf20Sopenharmony_ci case EXT_IRQ_CLK_COMP: 3138c2ecf20Sopenharmony_ci irq.type = KVM_S390_INT_CLOCK_COMP; 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci case EXT_IRQ_CPU_TIMER: 3168c2ecf20Sopenharmony_ci irq.type = KVM_S390_INT_CPU_TIMER; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case EXT_IRQ_EXTERNAL_CALL: 3198c2ecf20Sopenharmony_ci irq.type = KVM_S390_INT_EXTERNAL_CALL; 3208c2ecf20Sopenharmony_ci irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr; 3218c2ecf20Sopenharmony_ci rc = kvm_s390_inject_vcpu(vcpu, &irq); 3228c2ecf20Sopenharmony_ci /* ignore if another external call is already pending */ 3238c2ecf20Sopenharmony_ci if (rc == -EBUSY) 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci return rc; 3268c2ecf20Sopenharmony_ci default: 3278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return kvm_s390_inject_vcpu(vcpu, &irq); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/** 3348c2ecf20Sopenharmony_ci * Handle MOVE PAGE partial execution interception. 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * This interception can only happen for guests with DAT disabled and 3378c2ecf20Sopenharmony_ci * addresses that are currently not mapped in the host. Thus we try to 3388c2ecf20Sopenharmony_ci * set up the mappings for the corresponding user pages here (or throw 3398c2ecf20Sopenharmony_ci * addressing exceptions in case of illegal guest addresses). 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_cistatic int handle_mvpg_pei(struct kvm_vcpu *vcpu) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci unsigned long srcaddr, dstaddr; 3448c2ecf20Sopenharmony_ci int reg1, reg2, rc; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Make sure that the source is paged-in */ 3498c2ecf20Sopenharmony_ci rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg2], 3508c2ecf20Sopenharmony_ci reg2, &srcaddr, GACC_FETCH); 3518c2ecf20Sopenharmony_ci if (rc) 3528c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 3538c2ecf20Sopenharmony_ci rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0); 3548c2ecf20Sopenharmony_ci if (rc != 0) 3558c2ecf20Sopenharmony_ci return rc; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Make sure that the destination is paged-in */ 3588c2ecf20Sopenharmony_ci rc = guest_translate_address(vcpu, vcpu->run->s.regs.gprs[reg1], 3598c2ecf20Sopenharmony_ci reg1, &dstaddr, GACC_STORE); 3608c2ecf20Sopenharmony_ci if (rc) 3618c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 3628c2ecf20Sopenharmony_ci rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1); 3638c2ecf20Sopenharmony_ci if (rc != 0) 3648c2ecf20Sopenharmony_ci return rc; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int handle_partial_execution(struct kvm_vcpu *vcpu) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci vcpu->stat.exit_pei++; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb254) /* MVPG */ 3768c2ecf20Sopenharmony_ci return handle_mvpg_pei(vcpu); 3778c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa >> 8 == 0xae) /* SIGP */ 3788c2ecf20Sopenharmony_ci return kvm_s390_handle_sigp_pei(vcpu); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/* 3848c2ecf20Sopenharmony_ci * Handle the sthyi instruction that provides the guest with system 3858c2ecf20Sopenharmony_ci * information, like current CPU resources available at each level of 3868c2ecf20Sopenharmony_ci * the machine. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ciint handle_sthyi(struct kvm_vcpu *vcpu) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci int reg1, reg2, cc = 0, r = 0; 3918c2ecf20Sopenharmony_ci u64 code, addr, rc = 0; 3928c2ecf20Sopenharmony_ci struct sthyi_sctns *sctns = NULL; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 74)) 3958c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 3988c2ecf20Sopenharmony_ci code = vcpu->run->s.regs.gprs[reg1]; 3998c2ecf20Sopenharmony_ci addr = vcpu->run->s.regs.gprs[reg2]; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci vcpu->stat.instruction_sthyi++; 4028c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr); 4038c2ecf20Sopenharmony_ci trace_kvm_s390_handle_sthyi(vcpu, code, addr); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (reg1 == reg2 || reg1 & 1 || reg2 & 1) 4068c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (code & 0xffff) { 4098c2ecf20Sopenharmony_ci cc = 3; 4108c2ecf20Sopenharmony_ci rc = 4; 4118c2ecf20Sopenharmony_ci goto out; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (!kvm_s390_pv_cpu_is_protected(vcpu) && (addr & ~PAGE_MASK)) 4158c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci sctns = (void *)get_zeroed_page(GFP_KERNEL); 4188c2ecf20Sopenharmony_ci if (!sctns) 4198c2ecf20Sopenharmony_ci return -ENOMEM; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci cc = sthyi_fill(sctns, &rc); 4228c2ecf20Sopenharmony_ci if (cc < 0) { 4238c2ecf20Sopenharmony_ci free_page((unsigned long)sctns); 4248c2ecf20Sopenharmony_ci return cc; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ciout: 4278c2ecf20Sopenharmony_ci if (!cc) { 4288c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 4298c2ecf20Sopenharmony_ci memcpy((void *)(sida_origin(vcpu->arch.sie_block)), 4308c2ecf20Sopenharmony_ci sctns, PAGE_SIZE); 4318c2ecf20Sopenharmony_ci } else { 4328c2ecf20Sopenharmony_ci r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE); 4338c2ecf20Sopenharmony_ci if (r) { 4348c2ecf20Sopenharmony_ci free_page((unsigned long)sctns); 4358c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, r); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci free_page((unsigned long)sctns); 4418c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2 + 1] = rc; 4428c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, cc); 4438c2ecf20Sopenharmony_ci return r; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int handle_operexc(struct kvm_vcpu *vcpu) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci psw_t oldpsw, newpsw; 4498c2ecf20Sopenharmony_ci int rc; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci vcpu->stat.exit_operation_exception++; 4528c2ecf20Sopenharmony_ci trace_kvm_s390_handle_operexc(vcpu, vcpu->arch.sie_block->ipa, 4538c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ipb); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb256) 4568c2ecf20Sopenharmony_ci return handle_sthyi(vcpu); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0) 4598c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4608c2ecf20Sopenharmony_ci rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &newpsw, sizeof(psw_t)); 4618c2ecf20Sopenharmony_ci if (rc) 4628c2ecf20Sopenharmony_ci return rc; 4638c2ecf20Sopenharmony_ci /* 4648c2ecf20Sopenharmony_ci * Avoid endless loops of operation exceptions, if the pgm new 4658c2ecf20Sopenharmony_ci * PSW will cause a new operation exception. 4668c2ecf20Sopenharmony_ci * The heuristic checks if the pgm new psw is within 6 bytes before 4678c2ecf20Sopenharmony_ci * the faulting psw address (with same DAT, AS settings) and the 4688c2ecf20Sopenharmony_ci * new psw is not a wait psw and the fault was not triggered by 4698c2ecf20Sopenharmony_ci * problem state. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci oldpsw = vcpu->arch.sie_block->gpsw; 4728c2ecf20Sopenharmony_ci if (oldpsw.addr - newpsw.addr <= 6 && 4738c2ecf20Sopenharmony_ci !(newpsw.mask & PSW_MASK_WAIT) && 4748c2ecf20Sopenharmony_ci !(oldpsw.mask & PSW_MASK_PSTATE) && 4758c2ecf20Sopenharmony_ci (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) && 4768c2ecf20Sopenharmony_ci (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) 4778c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int handle_pv_spx(struct kvm_vcpu *vcpu) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci u32 pref = *(u32 *)vcpu->arch.sie_block->sidad; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci kvm_s390_set_prefix(vcpu, pref); 4878c2ecf20Sopenharmony_ci trace_kvm_s390_handle_prefix(vcpu, 1, pref); 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic int handle_pv_sclp(struct kvm_vcpu *vcpu) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci spin_lock(&fi->lock); 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * 2 cases: 4988c2ecf20Sopenharmony_ci * a: an sccb answering interrupt was already pending or in flight. 4998c2ecf20Sopenharmony_ci * As the sccb value is not known we can simply set some value to 5008c2ecf20Sopenharmony_ci * trigger delivery of a saved SCCB. UV will then use its saved 5018c2ecf20Sopenharmony_ci * copy of the SCCB value. 5028c2ecf20Sopenharmony_ci * b: an error SCCB interrupt needs to be injected so we also inject 5038c2ecf20Sopenharmony_ci * a fake SCCB address. Firmware will use the proper one. 5048c2ecf20Sopenharmony_ci * This makes sure, that both errors and real sccb returns will only 5058c2ecf20Sopenharmony_ci * be delivered after a notification intercept (instruction has 5068c2ecf20Sopenharmony_ci * finished) but not after others. 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci fi->srv_signal.ext_params |= 0x43000; 5098c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs); 5108c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs); 5118c2ecf20Sopenharmony_ci spin_unlock(&fi->lock); 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int handle_pv_uvc(struct kvm_vcpu *vcpu) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct uv_cb_share *guest_uvcb = (void *)vcpu->arch.sie_block->sidad; 5188c2ecf20Sopenharmony_ci struct uv_cb_cts uvcb = { 5198c2ecf20Sopenharmony_ci .header.cmd = UVC_CMD_UNPIN_PAGE_SHARED, 5208c2ecf20Sopenharmony_ci .header.len = sizeof(uvcb), 5218c2ecf20Sopenharmony_ci .guest_handle = kvm_s390_pv_get_handle(vcpu->kvm), 5228c2ecf20Sopenharmony_ci .gaddr = guest_uvcb->paddr, 5238c2ecf20Sopenharmony_ci }; 5248c2ecf20Sopenharmony_ci int rc; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (guest_uvcb->header.cmd != UVC_CMD_REMOVE_SHARED_ACCESS) { 5278c2ecf20Sopenharmony_ci WARN_ONCE(1, "Unexpected notification intercept for UVC 0x%x\n", 5288c2ecf20Sopenharmony_ci guest_uvcb->header.cmd); 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci rc = gmap_make_secure(vcpu->arch.gmap, uvcb.gaddr, &uvcb); 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci * If the unpin did not succeed, the guest will exit again for the UVC 5348c2ecf20Sopenharmony_ci * and we will retry the unpin. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci if (rc == -EINVAL) 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci return rc; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int handle_pv_notification(struct kvm_vcpu *vcpu) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci int ret; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb210) 5468c2ecf20Sopenharmony_ci return handle_pv_spx(vcpu); 5478c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb220) 5488c2ecf20Sopenharmony_ci return handle_pv_sclp(vcpu); 5498c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb9a4) 5508c2ecf20Sopenharmony_ci return handle_pv_uvc(vcpu); 5518c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa >> 8 == 0xae) { 5528c2ecf20Sopenharmony_ci /* 5538c2ecf20Sopenharmony_ci * Besides external call, other SIGP orders also cause a 5548c2ecf20Sopenharmony_ci * 108 (pv notify) intercept. In contrast to external call, 5558c2ecf20Sopenharmony_ci * these orders need to be emulated and hence the appropriate 5568c2ecf20Sopenharmony_ci * place to handle them is in handle_instruction(). 5578c2ecf20Sopenharmony_ci * So first try kvm_s390_handle_sigp_pei() and if that isn't 5588c2ecf20Sopenharmony_ci * successful, go on with handle_instruction(). 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci ret = kvm_s390_handle_sigp_pei(vcpu); 5618c2ecf20Sopenharmony_ci if (!ret) 5628c2ecf20Sopenharmony_ci return ret; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return handle_instruction(vcpu); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ciint kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci int rc, per_rc = 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (kvm_is_ucontrol(vcpu->kvm)) 5738c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->icptcode) { 5768c2ecf20Sopenharmony_ci case ICPT_EXTREQ: 5778c2ecf20Sopenharmony_ci vcpu->stat.exit_external_request++; 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci case ICPT_IOREQ: 5808c2ecf20Sopenharmony_ci vcpu->stat.exit_io_request++; 5818c2ecf20Sopenharmony_ci return 0; 5828c2ecf20Sopenharmony_ci case ICPT_INST: 5838c2ecf20Sopenharmony_ci rc = handle_instruction(vcpu); 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci case ICPT_PROGI: 5868c2ecf20Sopenharmony_ci return handle_prog(vcpu); 5878c2ecf20Sopenharmony_ci case ICPT_EXTINT: 5888c2ecf20Sopenharmony_ci return handle_external_interrupt(vcpu); 5898c2ecf20Sopenharmony_ci case ICPT_WAIT: 5908c2ecf20Sopenharmony_ci return kvm_s390_handle_wait(vcpu); 5918c2ecf20Sopenharmony_ci case ICPT_VALIDITY: 5928c2ecf20Sopenharmony_ci return handle_validity(vcpu); 5938c2ecf20Sopenharmony_ci case ICPT_STOP: 5948c2ecf20Sopenharmony_ci return handle_stop(vcpu); 5958c2ecf20Sopenharmony_ci case ICPT_OPEREXC: 5968c2ecf20Sopenharmony_ci rc = handle_operexc(vcpu); 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci case ICPT_PARTEXEC: 5998c2ecf20Sopenharmony_ci rc = handle_partial_execution(vcpu); 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case ICPT_KSS: 6028c2ecf20Sopenharmony_ci rc = kvm_s390_skey_check_enable(vcpu); 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci case ICPT_MCHKREQ: 6058c2ecf20Sopenharmony_ci case ICPT_INT_ENABLE: 6068c2ecf20Sopenharmony_ci /* 6078c2ecf20Sopenharmony_ci * PSW bit 13 or a CR (0, 6, 14) changed and we might 6088c2ecf20Sopenharmony_ci * now be able to deliver interrupts. The pre-run code 6098c2ecf20Sopenharmony_ci * will take care of this. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci rc = 0; 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case ICPT_PV_INSTR: 6148c2ecf20Sopenharmony_ci rc = handle_instruction(vcpu); 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case ICPT_PV_NOTIFY: 6178c2ecf20Sopenharmony_ci rc = handle_pv_notification(vcpu); 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci case ICPT_PV_PREF: 6208c2ecf20Sopenharmony_ci rc = 0; 6218c2ecf20Sopenharmony_ci gmap_convert_to_secure(vcpu->arch.gmap, 6228c2ecf20Sopenharmony_ci kvm_s390_get_prefix(vcpu)); 6238c2ecf20Sopenharmony_ci gmap_convert_to_secure(vcpu->arch.gmap, 6248c2ecf20Sopenharmony_ci kvm_s390_get_prefix(vcpu) + PAGE_SIZE); 6258c2ecf20Sopenharmony_ci break; 6268c2ecf20Sopenharmony_ci default: 6278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* process PER, also if the instrution is processed in user space */ 6318c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->icptstatus & 0x02 && 6328c2ecf20Sopenharmony_ci (!rc || rc == -EOPNOTSUPP)) 6338c2ecf20Sopenharmony_ci per_rc = kvm_s390_handle_per_ifetch_icpt(vcpu); 6348c2ecf20Sopenharmony_ci return per_rc ? per_rc : rc; 6358c2ecf20Sopenharmony_ci} 636