18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * handling privileged instructions 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.h> 128c2ecf20Sopenharmony_ci#include <linux/gfp.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/compat.h> 158c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 168c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 198c2ecf20Sopenharmony_ci#include <asm/facility.h> 208c2ecf20Sopenharmony_ci#include <asm/current.h> 218c2ecf20Sopenharmony_ci#include <asm/debug.h> 228c2ecf20Sopenharmony_ci#include <asm/ebcdic.h> 238c2ecf20Sopenharmony_ci#include <asm/sysinfo.h> 248c2ecf20Sopenharmony_ci#include <asm/page-states.h> 258c2ecf20Sopenharmony_ci#include <asm/gmap.h> 268c2ecf20Sopenharmony_ci#include <asm/io.h> 278c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 288c2ecf20Sopenharmony_ci#include <asm/sclp.h> 298c2ecf20Sopenharmony_ci#include <asm/ap.h> 308c2ecf20Sopenharmony_ci#include "gaccess.h" 318c2ecf20Sopenharmony_ci#include "kvm-s390.h" 328c2ecf20Sopenharmony_ci#include "trace.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int handle_ri(struct kvm_vcpu *vcpu) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci vcpu->stat.instruction_ri++; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 64)) { 398c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (lazy)"); 408c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb3 |= ECB3_RI; 418c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 428c2ecf20Sopenharmony_ci return 0; 438c2ecf20Sopenharmony_ci } else 448c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciint kvm_s390_handle_aa(struct kvm_vcpu *vcpu) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci if ((vcpu->arch.sie_block->ipa & 0xf) <= 4) 508c2ecf20Sopenharmony_ci return handle_ri(vcpu); 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int handle_gs(struct kvm_vcpu *vcpu) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci vcpu->stat.instruction_gs++; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 133)) { 608c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (lazy)"); 618c2ecf20Sopenharmony_ci preempt_disable(); 628c2ecf20Sopenharmony_ci __ctl_set_bit(2, 4); 638c2ecf20Sopenharmony_ci current->thread.gs_cb = (struct gs_cb *)&vcpu->run->s.regs.gscb; 648c2ecf20Sopenharmony_ci restore_gs_cb(current->thread.gs_cb); 658c2ecf20Sopenharmony_ci preempt_enable(); 668c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb |= ECB_GS; 678c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT; 688c2ecf20Sopenharmony_ci vcpu->arch.gs_enabled = 1; 698c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci } else 728c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciint kvm_s390_handle_e3(struct kvm_vcpu *vcpu) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int code = vcpu->arch.sie_block->ipb & 0xff; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (code == 0x49 || code == 0x4d) 808c2ecf20Sopenharmony_ci return handle_gs(vcpu); 818c2ecf20Sopenharmony_ci else 828c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci/* Handle SCK (SET CLOCK) interception */ 858c2ecf20Sopenharmony_cistatic int handle_set_clock(struct kvm_vcpu *vcpu) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct kvm_s390_vm_tod_clock gtod = { 0 }; 888c2ecf20Sopenharmony_ci int rc; 898c2ecf20Sopenharmony_ci u8 ar; 908c2ecf20Sopenharmony_ci u64 op2; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci vcpu->stat.instruction_sck++; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 958c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci op2 = kvm_s390_get_base_disp_s(vcpu, &ar); 988c2ecf20Sopenharmony_ci if (op2 & 7) /* Operand must be on a doubleword boundary */ 998c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 1008c2ecf20Sopenharmony_ci rc = read_guest(vcpu, op2, ar, >od.tod, sizeof(gtod.tod)); 1018c2ecf20Sopenharmony_ci if (rc) 1028c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod); 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * To set the TOD clock the kvm lock must be taken, but the vcpu lock 1078c2ecf20Sopenharmony_ci * is already held in handle_set_clock. The usual lock order is the 1088c2ecf20Sopenharmony_ci * opposite. As SCK is deprecated and should not be used in several 1098c2ecf20Sopenharmony_ci * cases, for example when the multiple epoch facility or TOD clock 1108c2ecf20Sopenharmony_ci * steering facility is installed (see Principles of Operation), a 1118c2ecf20Sopenharmony_ci * slow path can be used. If the lock can not be taken via try_lock, 1128c2ecf20Sopenharmony_ci * the instruction will be retried via -EAGAIN at a later point in 1138c2ecf20Sopenharmony_ci * time. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci if (!kvm_s390_try_set_tod_clock(vcpu->kvm, >od)) { 1168c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 1178c2ecf20Sopenharmony_ci return -EAGAIN; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 0); 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int handle_set_prefix(struct kvm_vcpu *vcpu) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci u64 operand2; 1278c2ecf20Sopenharmony_ci u32 address; 1288c2ecf20Sopenharmony_ci int rc; 1298c2ecf20Sopenharmony_ci u8 ar; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci vcpu->stat.instruction_spx++; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 1348c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci operand2 = kvm_s390_get_base_disp_s(vcpu, &ar); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* must be word boundary */ 1398c2ecf20Sopenharmony_ci if (operand2 & 3) 1408c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* get the value */ 1438c2ecf20Sopenharmony_ci rc = read_guest(vcpu, operand2, ar, &address, sizeof(address)); 1448c2ecf20Sopenharmony_ci if (rc) 1458c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci address &= 0x7fffe000u; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * Make sure the new value is valid memory. We only need to check the 1518c2ecf20Sopenharmony_ci * first page, since address is 8k aligned and memory pieces are always 1528c2ecf20Sopenharmony_ci * at least 1MB aligned and have at least a size of 1MB. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci if (kvm_is_error_gpa(vcpu->kvm, address)) 1558c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci kvm_s390_set_prefix(vcpu, address); 1588c2ecf20Sopenharmony_ci trace_kvm_s390_handle_prefix(vcpu, 1, address); 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int handle_store_prefix(struct kvm_vcpu *vcpu) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci u64 operand2; 1658c2ecf20Sopenharmony_ci u32 address; 1668c2ecf20Sopenharmony_ci int rc; 1678c2ecf20Sopenharmony_ci u8 ar; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci vcpu->stat.instruction_stpx++; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 1728c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci operand2 = kvm_s390_get_base_disp_s(vcpu, &ar); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* must be word boundary */ 1778c2ecf20Sopenharmony_ci if (operand2 & 3) 1788c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci address = kvm_s390_get_prefix(vcpu); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* get the value */ 1838c2ecf20Sopenharmony_ci rc = write_guest(vcpu, operand2, ar, &address, sizeof(address)); 1848c2ecf20Sopenharmony_ci if (rc) 1858c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "STPX: storing prefix 0x%x into 0x%llx", address, operand2); 1888c2ecf20Sopenharmony_ci trace_kvm_s390_handle_prefix(vcpu, 0, address); 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int handle_store_cpu_address(struct kvm_vcpu *vcpu) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci u16 vcpu_id = vcpu->vcpu_id; 1958c2ecf20Sopenharmony_ci u64 ga; 1968c2ecf20Sopenharmony_ci int rc; 1978c2ecf20Sopenharmony_ci u8 ar; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci vcpu->stat.instruction_stap++; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 2028c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ga = kvm_s390_get_base_disp_s(vcpu, &ar); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (ga & 1) 2078c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci rc = write_guest(vcpu, ga, ar, &vcpu_id, sizeof(vcpu_id)); 2108c2ecf20Sopenharmony_ci if (rc) 2118c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "STAP: storing cpu address (%u) to 0x%llx", vcpu_id, ga); 2148c2ecf20Sopenharmony_ci trace_kvm_s390_handle_stap(vcpu, ga); 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ciint kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci int rc; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci trace_kvm_s390_skey_related_inst(vcpu); 2238c2ecf20Sopenharmony_ci /* Already enabled? */ 2248c2ecf20Sopenharmony_ci if (vcpu->arch.skey_enabled) 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci rc = s390_enable_skey(); 2288c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "enabling storage keys for guest: %d", rc); 2298c2ecf20Sopenharmony_ci if (rc) 2308c2ecf20Sopenharmony_ci return rc; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS)) 2338c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_KSS); 2348c2ecf20Sopenharmony_ci if (!vcpu->kvm->arch.use_skf) 2358c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); 2388c2ecf20Sopenharmony_ci vcpu->arch.skey_enabled = true; 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int try_handle_skey(struct kvm_vcpu *vcpu) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci int rc; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci rc = kvm_s390_skey_check_enable(vcpu); 2478c2ecf20Sopenharmony_ci if (rc) 2488c2ecf20Sopenharmony_ci return rc; 2498c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_skf) { 2508c2ecf20Sopenharmony_ci /* with storage-key facility, SIE interprets it for us */ 2518c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 2528c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); 2538c2ecf20Sopenharmony_ci return -EAGAIN; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int handle_iske(struct kvm_vcpu *vcpu) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci unsigned long gaddr, vmaddr; 2618c2ecf20Sopenharmony_ci unsigned char key; 2628c2ecf20Sopenharmony_ci int reg1, reg2; 2638c2ecf20Sopenharmony_ci bool unlocked; 2648c2ecf20Sopenharmony_ci int rc; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci vcpu->stat.instruction_iske++; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 2698c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci rc = try_handle_skey(vcpu); 2728c2ecf20Sopenharmony_ci if (rc) 2738c2ecf20Sopenharmony_ci return rc != -EAGAIN ? rc : 0; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci gaddr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; 2788c2ecf20Sopenharmony_ci gaddr = kvm_s390_logical_to_effective(vcpu, gaddr); 2798c2ecf20Sopenharmony_ci gaddr = kvm_s390_real_to_abs(vcpu, gaddr); 2808c2ecf20Sopenharmony_ci vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gaddr)); 2818c2ecf20Sopenharmony_ci if (kvm_is_error_hva(vmaddr)) 2828c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 2838c2ecf20Sopenharmony_ciretry: 2848c2ecf20Sopenharmony_ci unlocked = false; 2858c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 2868c2ecf20Sopenharmony_ci rc = get_guest_storage_key(current->mm, vmaddr, &key); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (rc) { 2898c2ecf20Sopenharmony_ci rc = fixup_user_fault(current->mm, vmaddr, 2908c2ecf20Sopenharmony_ci FAULT_FLAG_WRITE, &unlocked); 2918c2ecf20Sopenharmony_ci if (!rc) { 2928c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 2938c2ecf20Sopenharmony_ci goto retry; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 2978c2ecf20Sopenharmony_ci if (rc == -EFAULT) 2988c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 2998c2ecf20Sopenharmony_ci if (rc < 0) 3008c2ecf20Sopenharmony_ci return rc; 3018c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg1] &= ~0xff; 3028c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg1] |= key; 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int handle_rrbe(struct kvm_vcpu *vcpu) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci unsigned long vmaddr, gaddr; 3098c2ecf20Sopenharmony_ci int reg1, reg2; 3108c2ecf20Sopenharmony_ci bool unlocked; 3118c2ecf20Sopenharmony_ci int rc; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci vcpu->stat.instruction_rrbe++; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 3168c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci rc = try_handle_skey(vcpu); 3198c2ecf20Sopenharmony_ci if (rc) 3208c2ecf20Sopenharmony_ci return rc != -EAGAIN ? rc : 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci gaddr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; 3258c2ecf20Sopenharmony_ci gaddr = kvm_s390_logical_to_effective(vcpu, gaddr); 3268c2ecf20Sopenharmony_ci gaddr = kvm_s390_real_to_abs(vcpu, gaddr); 3278c2ecf20Sopenharmony_ci vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gaddr)); 3288c2ecf20Sopenharmony_ci if (kvm_is_error_hva(vmaddr)) 3298c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 3308c2ecf20Sopenharmony_ciretry: 3318c2ecf20Sopenharmony_ci unlocked = false; 3328c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 3338c2ecf20Sopenharmony_ci rc = reset_guest_reference_bit(current->mm, vmaddr); 3348c2ecf20Sopenharmony_ci if (rc < 0) { 3358c2ecf20Sopenharmony_ci rc = fixup_user_fault(current->mm, vmaddr, 3368c2ecf20Sopenharmony_ci FAULT_FLAG_WRITE, &unlocked); 3378c2ecf20Sopenharmony_ci if (!rc) { 3388c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 3398c2ecf20Sopenharmony_ci goto retry; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 3438c2ecf20Sopenharmony_ci if (rc == -EFAULT) 3448c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 3458c2ecf20Sopenharmony_ci if (rc < 0) 3468c2ecf20Sopenharmony_ci return rc; 3478c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, rc); 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci#define SSKE_NQ 0x8 3528c2ecf20Sopenharmony_ci#define SSKE_MR 0x4 3538c2ecf20Sopenharmony_ci#define SSKE_MC 0x2 3548c2ecf20Sopenharmony_ci#define SSKE_MB 0x1 3558c2ecf20Sopenharmony_cistatic int handle_sske(struct kvm_vcpu *vcpu) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci unsigned char m3 = vcpu->arch.sie_block->ipb >> 28; 3588c2ecf20Sopenharmony_ci unsigned long start, end; 3598c2ecf20Sopenharmony_ci unsigned char key, oldkey; 3608c2ecf20Sopenharmony_ci int reg1, reg2; 3618c2ecf20Sopenharmony_ci bool unlocked; 3628c2ecf20Sopenharmony_ci int rc; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci vcpu->stat.instruction_sske++; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 3678c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci rc = try_handle_skey(vcpu); 3708c2ecf20Sopenharmony_ci if (rc) 3718c2ecf20Sopenharmony_ci return rc != -EAGAIN ? rc : 0; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 8)) 3748c2ecf20Sopenharmony_ci m3 &= ~SSKE_MB; 3758c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 10)) 3768c2ecf20Sopenharmony_ci m3 &= ~(SSKE_MC | SSKE_MR); 3778c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 14)) 3788c2ecf20Sopenharmony_ci m3 &= ~SSKE_NQ; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci key = vcpu->run->s.regs.gprs[reg1] & 0xfe; 3838c2ecf20Sopenharmony_ci start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; 3848c2ecf20Sopenharmony_ci start = kvm_s390_logical_to_effective(vcpu, start); 3858c2ecf20Sopenharmony_ci if (m3 & SSKE_MB) { 3868c2ecf20Sopenharmony_ci /* start already designates an absolute address */ 3878c2ecf20Sopenharmony_ci end = (start + _SEGMENT_SIZE) & ~(_SEGMENT_SIZE - 1); 3888c2ecf20Sopenharmony_ci } else { 3898c2ecf20Sopenharmony_ci start = kvm_s390_real_to_abs(vcpu, start); 3908c2ecf20Sopenharmony_ci end = start + PAGE_SIZE; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci while (start != end) { 3948c2ecf20Sopenharmony_ci unsigned long vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start)); 3958c2ecf20Sopenharmony_ci unlocked = false; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (kvm_is_error_hva(vmaddr)) 3988c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 4018c2ecf20Sopenharmony_ci rc = cond_set_guest_storage_key(current->mm, vmaddr, key, &oldkey, 4028c2ecf20Sopenharmony_ci m3 & SSKE_NQ, m3 & SSKE_MR, 4038c2ecf20Sopenharmony_ci m3 & SSKE_MC); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (rc < 0) { 4068c2ecf20Sopenharmony_ci rc = fixup_user_fault(current->mm, vmaddr, 4078c2ecf20Sopenharmony_ci FAULT_FLAG_WRITE, &unlocked); 4088c2ecf20Sopenharmony_ci rc = !rc ? -EAGAIN : rc; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 4118c2ecf20Sopenharmony_ci if (rc == -EFAULT) 4128c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 4138c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 4148c2ecf20Sopenharmony_ci continue; 4158c2ecf20Sopenharmony_ci if (rc < 0) 4168c2ecf20Sopenharmony_ci return rc; 4178c2ecf20Sopenharmony_ci start += PAGE_SIZE; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (m3 & (SSKE_MC | SSKE_MR)) { 4218c2ecf20Sopenharmony_ci if (m3 & SSKE_MB) { 4228c2ecf20Sopenharmony_ci /* skey in reg1 is unpredictable */ 4238c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, rc); 4268c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg1] &= ~0xff00UL; 4278c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg1] |= (u64) oldkey << 8; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci if (m3 & SSKE_MB) { 4318c2ecf20Sopenharmony_ci if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_64BIT) 4328c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] &= ~PAGE_MASK; 4338c2ecf20Sopenharmony_ci else 4348c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] &= ~0xfffff000UL; 4358c2ecf20Sopenharmony_ci end = kvm_s390_logical_to_effective(vcpu, end); 4368c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] |= end; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int handle_ipte_interlock(struct kvm_vcpu *vcpu) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci vcpu->stat.instruction_ipte_interlock++; 4448c2ecf20Sopenharmony_ci if (psw_bits(vcpu->arch.sie_block->gpsw).pstate) 4458c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 4468c2ecf20Sopenharmony_ci wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu)); 4478c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 4488c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation"); 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int handle_test_block(struct kvm_vcpu *vcpu) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci gpa_t addr; 4558c2ecf20Sopenharmony_ci int reg2; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci vcpu->stat.instruction_tb++; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 4608c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, NULL, ®2); 4638c2ecf20Sopenharmony_ci addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; 4648c2ecf20Sopenharmony_ci addr = kvm_s390_logical_to_effective(vcpu, addr); 4658c2ecf20Sopenharmony_ci if (kvm_s390_check_low_addr_prot_real(vcpu, addr)) 4668c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); 4678c2ecf20Sopenharmony_ci addr = kvm_s390_real_to_abs(vcpu, addr); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (kvm_is_error_gpa(vcpu->kvm, addr)) 4708c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * We don't expect errors on modern systems, and do not care 4738c2ecf20Sopenharmony_ci * about storage keys (yet), so let's just clear the page. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci if (kvm_clear_guest(vcpu->kvm, addr, PAGE_SIZE)) 4768c2ecf20Sopenharmony_ci return -EFAULT; 4778c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 0); 4788c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[0] = 0; 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int handle_tpi(struct kvm_vcpu *vcpu) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti; 4858c2ecf20Sopenharmony_ci unsigned long len; 4868c2ecf20Sopenharmony_ci u32 tpi_data[3]; 4878c2ecf20Sopenharmony_ci int rc; 4888c2ecf20Sopenharmony_ci u64 addr; 4898c2ecf20Sopenharmony_ci u8 ar; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci vcpu->stat.instruction_tpi++; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci addr = kvm_s390_get_base_disp_s(vcpu, &ar); 4948c2ecf20Sopenharmony_ci if (addr & 3) 4958c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->arch.sie_block->gcr[6], 0); 4988c2ecf20Sopenharmony_ci if (!inti) { 4998c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 0); 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci tpi_data[0] = inti->io.subchannel_id << 16 | inti->io.subchannel_nr; 5048c2ecf20Sopenharmony_ci tpi_data[1] = inti->io.io_int_parm; 5058c2ecf20Sopenharmony_ci tpi_data[2] = inti->io.io_int_word; 5068c2ecf20Sopenharmony_ci if (addr) { 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * Store the two-word I/O interruption code into the 5098c2ecf20Sopenharmony_ci * provided area. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_ci len = sizeof(tpi_data) - 4; 5128c2ecf20Sopenharmony_ci rc = write_guest(vcpu, addr, ar, &tpi_data, len); 5138c2ecf20Sopenharmony_ci if (rc) { 5148c2ecf20Sopenharmony_ci rc = kvm_s390_inject_prog_cond(vcpu, rc); 5158c2ecf20Sopenharmony_ci goto reinject_interrupt; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } else { 5188c2ecf20Sopenharmony_ci /* 5198c2ecf20Sopenharmony_ci * Store the three-word I/O interruption code into 5208c2ecf20Sopenharmony_ci * the appropriate lowcore area. 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_ci len = sizeof(tpi_data); 5238c2ecf20Sopenharmony_ci if (write_guest_lc(vcpu, __LC_SUBCHANNEL_ID, &tpi_data, len)) { 5248c2ecf20Sopenharmony_ci /* failed writes to the low core are not recoverable */ 5258c2ecf20Sopenharmony_ci rc = -EFAULT; 5268c2ecf20Sopenharmony_ci goto reinject_interrupt; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* irq was successfully handed to the guest */ 5318c2ecf20Sopenharmony_ci kfree(inti); 5328c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 1); 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_cireinject_interrupt: 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * If we encounter a problem storing the interruption code, the 5378c2ecf20Sopenharmony_ci * instruction is suppressed from the guest's view: reinject the 5388c2ecf20Sopenharmony_ci * interrupt. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci if (kvm_s390_reinject_io_int(vcpu->kvm, inti)) { 5418c2ecf20Sopenharmony_ci kfree(inti); 5428c2ecf20Sopenharmony_ci rc = -EFAULT; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci /* don't set the cc, a pgm irq was injected or we drop to user space */ 5458c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int handle_tsch(struct kvm_vcpu *vcpu) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct kvm_s390_interrupt_info *inti = NULL; 5518c2ecf20Sopenharmony_ci const u64 isc_mask = 0xffUL << 24; /* all iscs set */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci vcpu->stat.instruction_tsch++; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* a valid schid has at least one bit set */ 5568c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[1]) 5578c2ecf20Sopenharmony_ci inti = kvm_s390_get_io_int(vcpu->kvm, isc_mask, 5588c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[1]); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* 5618c2ecf20Sopenharmony_ci * Prepare exit to userspace. 5628c2ecf20Sopenharmony_ci * We indicate whether we dequeued a pending I/O interrupt 5638c2ecf20Sopenharmony_ci * so that userspace can re-inject it if the instruction gets 5648c2ecf20Sopenharmony_ci * a program check. While this may re-order the pending I/O 5658c2ecf20Sopenharmony_ci * interrupts, this is no problem since the priority is kept 5668c2ecf20Sopenharmony_ci * intact. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_S390_TSCH; 5698c2ecf20Sopenharmony_ci vcpu->run->s390_tsch.dequeued = !!inti; 5708c2ecf20Sopenharmony_ci if (inti) { 5718c2ecf20Sopenharmony_ci vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id; 5728c2ecf20Sopenharmony_ci vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr; 5738c2ecf20Sopenharmony_ci vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm; 5748c2ecf20Sopenharmony_ci vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb; 5778c2ecf20Sopenharmony_ci kfree(inti); 5788c2ecf20Sopenharmony_ci return -EREMOTE; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int handle_io_inst(struct kvm_vcpu *vcpu) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "%s", "I/O instruction"); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 5868c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.css_support) { 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * Most I/O instructions will be handled by userspace. 5918c2ecf20Sopenharmony_ci * Exceptions are tpi and the interrupt portion of tsch. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb236) 5948c2ecf20Sopenharmony_ci return handle_tpi(vcpu); 5958c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->ipa == 0xb235) 5968c2ecf20Sopenharmony_ci return handle_tsch(vcpu); 5978c2ecf20Sopenharmony_ci /* Handle in userspace. */ 5988c2ecf20Sopenharmony_ci vcpu->stat.instruction_io_other++; 5998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6008c2ecf20Sopenharmony_ci } else { 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * Set condition code 3 to stop the guest from issuing channel 6038c2ecf20Sopenharmony_ci * I/O instructions. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci/* 6118c2ecf20Sopenharmony_ci * handle_pqap: Handling pqap interception 6128c2ecf20Sopenharmony_ci * @vcpu: the vcpu having issue the pqap instruction 6138c2ecf20Sopenharmony_ci * 6148c2ecf20Sopenharmony_ci * We now support PQAP/AQIC instructions and we need to correctly 6158c2ecf20Sopenharmony_ci * answer the guest even if no dedicated driver's hook is available. 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci * The intercepting code calls a dedicated callback for this instruction 6188c2ecf20Sopenharmony_ci * if a driver did register one in the CRYPTO satellite of the 6198c2ecf20Sopenharmony_ci * SIE block. 6208c2ecf20Sopenharmony_ci * 6218c2ecf20Sopenharmony_ci * If no callback is available, the queues are not available, return this 6228c2ecf20Sopenharmony_ci * response code to the caller and set CC to 3. 6238c2ecf20Sopenharmony_ci * Else return the response code returned by the callback. 6248c2ecf20Sopenharmony_ci */ 6258c2ecf20Sopenharmony_cistatic int handle_pqap(struct kvm_vcpu *vcpu) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct ap_queue_status status = {}; 6288c2ecf20Sopenharmony_ci unsigned long reg0; 6298c2ecf20Sopenharmony_ci int ret; 6308c2ecf20Sopenharmony_ci uint8_t fc; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Verify that the AP instruction are available */ 6338c2ecf20Sopenharmony_ci if (!ap_instructions_available()) 6348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6358c2ecf20Sopenharmony_ci /* Verify that the guest is allowed to use AP instructions */ 6368c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->eca & ECA_APIE)) 6378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6388c2ecf20Sopenharmony_ci /* 6398c2ecf20Sopenharmony_ci * The only possibly intercepted functions when AP instructions are 6408c2ecf20Sopenharmony_ci * available for the guest are AQIC and TAPQ with the t bit set 6418c2ecf20Sopenharmony_ci * since we do not set IC.3 (FIII) we currently will only intercept 6428c2ecf20Sopenharmony_ci * the AQIC function code. 6438c2ecf20Sopenharmony_ci * Note: running nested under z/VM can result in intercepts for other 6448c2ecf20Sopenharmony_ci * function codes, e.g. PQAP(QCI). We do not support this and bail out. 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci reg0 = vcpu->run->s.regs.gprs[0]; 6478c2ecf20Sopenharmony_ci fc = (reg0 >> 24) & 0xff; 6488c2ecf20Sopenharmony_ci if (fc != 0x03) 6498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* PQAP instruction is allowed for guest kernel only */ 6528c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 6538c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* Common PQAP instruction specification exceptions */ 6568c2ecf20Sopenharmony_ci /* bits 41-47 must all be zeros */ 6578c2ecf20Sopenharmony_ci if (reg0 & 0x007f0000UL) 6588c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 6598c2ecf20Sopenharmony_ci /* APFT not install and T bit set */ 6608c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 15) && (reg0 & 0x00800000UL)) 6618c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 6628c2ecf20Sopenharmony_ci /* APXA not installed and APID greater 64 or APQI greater 16 */ 6638c2ecf20Sopenharmony_ci if (!(vcpu->kvm->arch.crypto.crycbd & 0x02) && (reg0 & 0x0000c0f0UL)) 6648c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* AQIC function code specific exception */ 6678c2ecf20Sopenharmony_ci /* facility 65 not present for AQIC function code */ 6688c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 65)) 6698c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * Verify that the hook callback is registered, lock the owner 6738c2ecf20Sopenharmony_ci * and call the hook. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.crypto.pqap_hook) { 6768c2ecf20Sopenharmony_ci if (!try_module_get(vcpu->kvm->arch.crypto.pqap_hook->owner)) 6778c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6788c2ecf20Sopenharmony_ci ret = vcpu->kvm->arch.crypto.pqap_hook->hook(vcpu); 6798c2ecf20Sopenharmony_ci module_put(vcpu->kvm->arch.crypto.pqap_hook->owner); 6808c2ecf20Sopenharmony_ci if (!ret && vcpu->run->s.regs.gprs[1] & 0x00ff0000) 6818c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 6828c2ecf20Sopenharmony_ci return ret; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * A vfio_driver must register a hook. 6868c2ecf20Sopenharmony_ci * No hook means no driver to enable the SIE CRYCB and no queues. 6878c2ecf20Sopenharmony_ci * We send this response to the guest. 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci status.response_code = 0x01; 6908c2ecf20Sopenharmony_ci memcpy(&vcpu->run->s.regs.gprs[1], &status, sizeof(status)); 6918c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int handle_stfl(struct kvm_vcpu *vcpu) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci int rc; 6988c2ecf20Sopenharmony_ci unsigned int fac; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci vcpu->stat.instruction_stfl++; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 7038c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* 7068c2ecf20Sopenharmony_ci * We need to shift the lower 32 facility bits (bit 0-31) from a u64 7078c2ecf20Sopenharmony_ci * into a u32 memory representation. They will remain bits 0-31. 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_ci fac = *vcpu->kvm->arch.model.fac_list >> 32; 7108c2ecf20Sopenharmony_ci rc = write_guest_lc(vcpu, offsetof(struct lowcore, stfl_fac_list), 7118c2ecf20Sopenharmony_ci &fac, sizeof(fac)); 7128c2ecf20Sopenharmony_ci if (rc) 7138c2ecf20Sopenharmony_ci return rc; 7148c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "STFL: store facility list 0x%x", fac); 7158c2ecf20Sopenharmony_ci trace_kvm_s390_handle_stfl(vcpu, fac); 7168c2ecf20Sopenharmony_ci return 0; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci#define PSW_MASK_ADDR_MODE (PSW_MASK_EA | PSW_MASK_BA) 7208c2ecf20Sopenharmony_ci#define PSW_MASK_UNASSIGNED 0xb80800fe7fffffffUL 7218c2ecf20Sopenharmony_ci#define PSW_ADDR_24 0x0000000000ffffffUL 7228c2ecf20Sopenharmony_ci#define PSW_ADDR_31 0x000000007fffffffUL 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ciint is_valid_psw(psw_t *psw) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci if (psw->mask & PSW_MASK_UNASSIGNED) 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci if ((psw->mask & PSW_MASK_ADDR_MODE) == PSW_MASK_BA) { 7298c2ecf20Sopenharmony_ci if (psw->addr & ~PSW_ADDR_31) 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci if (!(psw->mask & PSW_MASK_ADDR_MODE) && (psw->addr & ~PSW_ADDR_24)) 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci if ((psw->mask & PSW_MASK_ADDR_MODE) == PSW_MASK_EA) 7358c2ecf20Sopenharmony_ci return 0; 7368c2ecf20Sopenharmony_ci if (psw->addr & 1) 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci return 1; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciint kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci psw_t *gpsw = &vcpu->arch.sie_block->gpsw; 7448c2ecf20Sopenharmony_ci psw_compat_t new_psw; 7458c2ecf20Sopenharmony_ci u64 addr; 7468c2ecf20Sopenharmony_ci int rc; 7478c2ecf20Sopenharmony_ci u8 ar; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci vcpu->stat.instruction_lpsw++; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (gpsw->mask & PSW_MASK_PSTATE) 7528c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci addr = kvm_s390_get_base_disp_s(vcpu, &ar); 7558c2ecf20Sopenharmony_ci if (addr & 7) 7568c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw)); 7598c2ecf20Sopenharmony_ci if (rc) 7608c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 7618c2ecf20Sopenharmony_ci if (!(new_psw.mask & PSW32_MASK_BASE)) 7628c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 7638c2ecf20Sopenharmony_ci gpsw->mask = (new_psw.mask & ~PSW32_MASK_BASE) << 32; 7648c2ecf20Sopenharmony_ci gpsw->mask |= new_psw.addr & PSW32_ADDR_AMODE; 7658c2ecf20Sopenharmony_ci gpsw->addr = new_psw.addr & ~PSW32_ADDR_AMODE; 7668c2ecf20Sopenharmony_ci if (!is_valid_psw(gpsw)) 7678c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 7688c2ecf20Sopenharmony_ci return 0; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic int handle_lpswe(struct kvm_vcpu *vcpu) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci psw_t new_psw; 7748c2ecf20Sopenharmony_ci u64 addr; 7758c2ecf20Sopenharmony_ci int rc; 7768c2ecf20Sopenharmony_ci u8 ar; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci vcpu->stat.instruction_lpswe++; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 7818c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci addr = kvm_s390_get_base_disp_s(vcpu, &ar); 7848c2ecf20Sopenharmony_ci if (addr & 7) 7858c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 7868c2ecf20Sopenharmony_ci rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw)); 7878c2ecf20Sopenharmony_ci if (rc) 7888c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 7898c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw = new_psw; 7908c2ecf20Sopenharmony_ci if (!is_valid_psw(&vcpu->arch.sie_block->gpsw)) 7918c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 7928c2ecf20Sopenharmony_ci return 0; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic int handle_stidp(struct kvm_vcpu *vcpu) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci u64 stidp_data = vcpu->kvm->arch.model.cpuid; 7988c2ecf20Sopenharmony_ci u64 operand2; 7998c2ecf20Sopenharmony_ci int rc; 8008c2ecf20Sopenharmony_ci u8 ar; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci vcpu->stat.instruction_stidp++; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 8058c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci operand2 = kvm_s390_get_base_disp_s(vcpu, &ar); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (operand2 & 7) 8108c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci rc = write_guest(vcpu, operand2, ar, &stidp_data, sizeof(stidp_data)); 8138c2ecf20Sopenharmony_ci if (rc) 8148c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "STIDP: store cpu id 0x%llx", stidp_data); 8178c2ecf20Sopenharmony_ci return 0; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci int cpus = 0; 8238c2ecf20Sopenharmony_ci int n; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci cpus = atomic_read(&vcpu->kvm->online_vcpus); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci /* deal with other level 3 hypervisors */ 8288c2ecf20Sopenharmony_ci if (stsi(mem, 3, 2, 2)) 8298c2ecf20Sopenharmony_ci mem->count = 0; 8308c2ecf20Sopenharmony_ci if (mem->count < 8) 8318c2ecf20Sopenharmony_ci mem->count++; 8328c2ecf20Sopenharmony_ci for (n = mem->count - 1; n > 0 ; n--) 8338c2ecf20Sopenharmony_ci memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0])); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci memset(&mem->vm[0], 0, sizeof(mem->vm[0])); 8368c2ecf20Sopenharmony_ci mem->vm[0].cpus_total = cpus; 8378c2ecf20Sopenharmony_ci mem->vm[0].cpus_configured = cpus; 8388c2ecf20Sopenharmony_ci mem->vm[0].cpus_standby = 0; 8398c2ecf20Sopenharmony_ci mem->vm[0].cpus_reserved = 0; 8408c2ecf20Sopenharmony_ci mem->vm[0].caf = 1000; 8418c2ecf20Sopenharmony_ci memcpy(mem->vm[0].name, "KVMguest", 8); 8428c2ecf20Sopenharmony_ci ASCEBC(mem->vm[0].name, 8); 8438c2ecf20Sopenharmony_ci memcpy(mem->vm[0].cpi, "KVM/Linux ", 16); 8448c2ecf20Sopenharmony_ci ASCEBC(mem->vm[0].cpi, 16); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void insert_stsi_usr_data(struct kvm_vcpu *vcpu, u64 addr, u8 ar, 8488c2ecf20Sopenharmony_ci u8 fc, u8 sel1, u16 sel2) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_S390_STSI; 8518c2ecf20Sopenharmony_ci vcpu->run->s390_stsi.addr = addr; 8528c2ecf20Sopenharmony_ci vcpu->run->s390_stsi.ar = ar; 8538c2ecf20Sopenharmony_ci vcpu->run->s390_stsi.fc = fc; 8548c2ecf20Sopenharmony_ci vcpu->run->s390_stsi.sel1 = sel1; 8558c2ecf20Sopenharmony_ci vcpu->run->s390_stsi.sel2 = sel2; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int handle_stsi(struct kvm_vcpu *vcpu) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28; 8618c2ecf20Sopenharmony_ci int sel1 = vcpu->run->s.regs.gprs[0] & 0xff; 8628c2ecf20Sopenharmony_ci int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff; 8638c2ecf20Sopenharmony_ci unsigned long mem = 0; 8648c2ecf20Sopenharmony_ci u64 operand2; 8658c2ecf20Sopenharmony_ci int rc = 0; 8668c2ecf20Sopenharmony_ci u8 ar; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci vcpu->stat.instruction_stsi++; 8698c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "STSI: fc: %u sel1: %u sel2: %u", fc, sel1, sel2); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 8728c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (fc > 3) { 8758c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[0] & 0x0fffff00 8808c2ecf20Sopenharmony_ci || vcpu->run->s.regs.gprs[1] & 0xffff0000) 8818c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (fc == 0) { 8848c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[0] = 3 << 28; 8858c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 0); 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci operand2 = kvm_s390_get_base_disp_s(vcpu, &ar); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (!kvm_s390_pv_cpu_is_protected(vcpu) && (operand2 & 0xfff)) 8928c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci switch (fc) { 8958c2ecf20Sopenharmony_ci case 1: /* same handling for 1 and 2 */ 8968c2ecf20Sopenharmony_ci case 2: 8978c2ecf20Sopenharmony_ci mem = get_zeroed_page(GFP_KERNEL); 8988c2ecf20Sopenharmony_ci if (!mem) 8998c2ecf20Sopenharmony_ci goto out_no_data; 9008c2ecf20Sopenharmony_ci if (stsi((void *) mem, fc, sel1, sel2)) 9018c2ecf20Sopenharmony_ci goto out_no_data; 9028c2ecf20Sopenharmony_ci break; 9038c2ecf20Sopenharmony_ci case 3: 9048c2ecf20Sopenharmony_ci if (sel1 != 2 || sel2 != 2) 9058c2ecf20Sopenharmony_ci goto out_no_data; 9068c2ecf20Sopenharmony_ci mem = get_zeroed_page(GFP_KERNEL); 9078c2ecf20Sopenharmony_ci if (!mem) 9088c2ecf20Sopenharmony_ci goto out_no_data; 9098c2ecf20Sopenharmony_ci handle_stsi_3_2_2(vcpu, (void *) mem); 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 9138c2ecf20Sopenharmony_ci memcpy((void *)sida_origin(vcpu->arch.sie_block), (void *)mem, 9148c2ecf20Sopenharmony_ci PAGE_SIZE); 9158c2ecf20Sopenharmony_ci rc = 0; 9168c2ecf20Sopenharmony_ci } else { 9178c2ecf20Sopenharmony_ci rc = write_guest(vcpu, operand2, ar, (void *)mem, PAGE_SIZE); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci if (rc) { 9208c2ecf20Sopenharmony_ci rc = kvm_s390_inject_prog_cond(vcpu, rc); 9218c2ecf20Sopenharmony_ci goto out; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.user_stsi) { 9248c2ecf20Sopenharmony_ci insert_stsi_usr_data(vcpu, operand2, ar, fc, sel1, sel2); 9258c2ecf20Sopenharmony_ci rc = -EREMOTE; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); 9288c2ecf20Sopenharmony_ci free_page(mem); 9298c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 0); 9308c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[0] = 0; 9318c2ecf20Sopenharmony_ci return rc; 9328c2ecf20Sopenharmony_ciout_no_data: 9338c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 9348c2ecf20Sopenharmony_ciout: 9358c2ecf20Sopenharmony_ci free_page(mem); 9368c2ecf20Sopenharmony_ci return rc; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ciint kvm_s390_handle_b2(struct kvm_vcpu *vcpu) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->ipa & 0x00ff) { 9428c2ecf20Sopenharmony_ci case 0x02: 9438c2ecf20Sopenharmony_ci return handle_stidp(vcpu); 9448c2ecf20Sopenharmony_ci case 0x04: 9458c2ecf20Sopenharmony_ci return handle_set_clock(vcpu); 9468c2ecf20Sopenharmony_ci case 0x10: 9478c2ecf20Sopenharmony_ci return handle_set_prefix(vcpu); 9488c2ecf20Sopenharmony_ci case 0x11: 9498c2ecf20Sopenharmony_ci return handle_store_prefix(vcpu); 9508c2ecf20Sopenharmony_ci case 0x12: 9518c2ecf20Sopenharmony_ci return handle_store_cpu_address(vcpu); 9528c2ecf20Sopenharmony_ci case 0x14: 9538c2ecf20Sopenharmony_ci return kvm_s390_handle_vsie(vcpu); 9548c2ecf20Sopenharmony_ci case 0x21: 9558c2ecf20Sopenharmony_ci case 0x50: 9568c2ecf20Sopenharmony_ci return handle_ipte_interlock(vcpu); 9578c2ecf20Sopenharmony_ci case 0x29: 9588c2ecf20Sopenharmony_ci return handle_iske(vcpu); 9598c2ecf20Sopenharmony_ci case 0x2a: 9608c2ecf20Sopenharmony_ci return handle_rrbe(vcpu); 9618c2ecf20Sopenharmony_ci case 0x2b: 9628c2ecf20Sopenharmony_ci return handle_sske(vcpu); 9638c2ecf20Sopenharmony_ci case 0x2c: 9648c2ecf20Sopenharmony_ci return handle_test_block(vcpu); 9658c2ecf20Sopenharmony_ci case 0x30: 9668c2ecf20Sopenharmony_ci case 0x31: 9678c2ecf20Sopenharmony_ci case 0x32: 9688c2ecf20Sopenharmony_ci case 0x33: 9698c2ecf20Sopenharmony_ci case 0x34: 9708c2ecf20Sopenharmony_ci case 0x35: 9718c2ecf20Sopenharmony_ci case 0x36: 9728c2ecf20Sopenharmony_ci case 0x37: 9738c2ecf20Sopenharmony_ci case 0x38: 9748c2ecf20Sopenharmony_ci case 0x39: 9758c2ecf20Sopenharmony_ci case 0x3a: 9768c2ecf20Sopenharmony_ci case 0x3b: 9778c2ecf20Sopenharmony_ci case 0x3c: 9788c2ecf20Sopenharmony_ci case 0x5f: 9798c2ecf20Sopenharmony_ci case 0x74: 9808c2ecf20Sopenharmony_ci case 0x76: 9818c2ecf20Sopenharmony_ci return handle_io_inst(vcpu); 9828c2ecf20Sopenharmony_ci case 0x56: 9838c2ecf20Sopenharmony_ci return handle_sthyi(vcpu); 9848c2ecf20Sopenharmony_ci case 0x7d: 9858c2ecf20Sopenharmony_ci return handle_stsi(vcpu); 9868c2ecf20Sopenharmony_ci case 0xaf: 9878c2ecf20Sopenharmony_ci return handle_pqap(vcpu); 9888c2ecf20Sopenharmony_ci case 0xb1: 9898c2ecf20Sopenharmony_ci return handle_stfl(vcpu); 9908c2ecf20Sopenharmony_ci case 0xb2: 9918c2ecf20Sopenharmony_ci return handle_lpswe(vcpu); 9928c2ecf20Sopenharmony_ci default: 9938c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int handle_epsw(struct kvm_vcpu *vcpu) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci int reg1, reg2; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci vcpu->stat.instruction_epsw++; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* This basically extracts the mask half of the psw. */ 10068c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000UL; 10078c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32; 10088c2ecf20Sopenharmony_ci if (reg2) { 10098c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000UL; 10108c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] |= 10118c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffffUL; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci return 0; 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci#define PFMF_RESERVED 0xfffc0101UL 10178c2ecf20Sopenharmony_ci#define PFMF_SK 0x00020000UL 10188c2ecf20Sopenharmony_ci#define PFMF_CF 0x00010000UL 10198c2ecf20Sopenharmony_ci#define PFMF_UI 0x00008000UL 10208c2ecf20Sopenharmony_ci#define PFMF_FSC 0x00007000UL 10218c2ecf20Sopenharmony_ci#define PFMF_NQ 0x00000800UL 10228c2ecf20Sopenharmony_ci#define PFMF_MR 0x00000400UL 10238c2ecf20Sopenharmony_ci#define PFMF_MC 0x00000200UL 10248c2ecf20Sopenharmony_ci#define PFMF_KEY 0x000000feUL 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic int handle_pfmf(struct kvm_vcpu *vcpu) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci bool mr = false, mc = false, nq; 10298c2ecf20Sopenharmony_ci int reg1, reg2; 10308c2ecf20Sopenharmony_ci unsigned long start, end; 10318c2ecf20Sopenharmony_ci unsigned char key; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci vcpu->stat.instruction_pfmf++; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, ®1, ®2); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 8)) 10388c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 10418c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_RESERVED) 10448c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Only provide non-quiescing support if enabled for the guest */ 10478c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ && 10488c2ecf20Sopenharmony_ci !test_kvm_facility(vcpu->kvm, 14)) 10498c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* Only provide conditional-SSKE support if enabled for the guest */ 10528c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK && 10538c2ecf20Sopenharmony_ci test_kvm_facility(vcpu->kvm, 10)) { 10548c2ecf20Sopenharmony_ci mr = vcpu->run->s.regs.gprs[reg1] & PFMF_MR; 10558c2ecf20Sopenharmony_ci mc = vcpu->run->s.regs.gprs[reg1] & PFMF_MC; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci nq = vcpu->run->s.regs.gprs[reg1] & PFMF_NQ; 10598c2ecf20Sopenharmony_ci key = vcpu->run->s.regs.gprs[reg1] & PFMF_KEY; 10608c2ecf20Sopenharmony_ci start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; 10618c2ecf20Sopenharmony_ci start = kvm_s390_logical_to_effective(vcpu, start); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) { 10648c2ecf20Sopenharmony_ci if (kvm_s390_check_low_addr_prot_real(vcpu, start)) 10658c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) { 10698c2ecf20Sopenharmony_ci case 0x00000000: 10708c2ecf20Sopenharmony_ci /* only 4k frames specify a real address */ 10718c2ecf20Sopenharmony_ci start = kvm_s390_real_to_abs(vcpu, start); 10728c2ecf20Sopenharmony_ci end = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1); 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci case 0x00001000: 10758c2ecf20Sopenharmony_ci end = (start + _SEGMENT_SIZE) & ~(_SEGMENT_SIZE - 1); 10768c2ecf20Sopenharmony_ci break; 10778c2ecf20Sopenharmony_ci case 0x00002000: 10788c2ecf20Sopenharmony_ci /* only support 2G frame size if EDAT2 is available and we are 10798c2ecf20Sopenharmony_ci not in 24-bit addressing mode */ 10808c2ecf20Sopenharmony_ci if (!test_kvm_facility(vcpu->kvm, 78) || 10818c2ecf20Sopenharmony_ci psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_24BIT) 10828c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 10838c2ecf20Sopenharmony_ci end = (start + _REGION3_SIZE) & ~(_REGION3_SIZE - 1); 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci default: 10868c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci while (start != end) { 10908c2ecf20Sopenharmony_ci unsigned long vmaddr; 10918c2ecf20Sopenharmony_ci bool unlocked = false; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* Translate guest address to host address */ 10948c2ecf20Sopenharmony_ci vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start)); 10958c2ecf20Sopenharmony_ci if (kvm_is_error_hva(vmaddr)) 10968c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) { 10998c2ecf20Sopenharmony_ci if (kvm_clear_guest(vcpu->kvm, start, PAGE_SIZE)) 11008c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) { 11048c2ecf20Sopenharmony_ci int rc = kvm_s390_skey_check_enable(vcpu); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (rc) 11078c2ecf20Sopenharmony_ci return rc; 11088c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 11098c2ecf20Sopenharmony_ci rc = cond_set_guest_storage_key(current->mm, vmaddr, 11108c2ecf20Sopenharmony_ci key, NULL, nq, mr, mc); 11118c2ecf20Sopenharmony_ci if (rc < 0) { 11128c2ecf20Sopenharmony_ci rc = fixup_user_fault(current->mm, vmaddr, 11138c2ecf20Sopenharmony_ci FAULT_FLAG_WRITE, &unlocked); 11148c2ecf20Sopenharmony_ci rc = !rc ? -EAGAIN : rc; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 11178c2ecf20Sopenharmony_ci if (rc == -EFAULT) 11188c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 11198c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 11208c2ecf20Sopenharmony_ci continue; 11218c2ecf20Sopenharmony_ci if (rc < 0) 11228c2ecf20Sopenharmony_ci return rc; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci start += PAGE_SIZE; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) { 11278c2ecf20Sopenharmony_ci if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_64BIT) { 11288c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] = end; 11298c2ecf20Sopenharmony_ci } else { 11308c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] &= ~0xffffffffUL; 11318c2ecf20Sopenharmony_ci end = kvm_s390_logical_to_effective(vcpu, end); 11328c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[reg2] |= end; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci/* 11398c2ecf20Sopenharmony_ci * Must be called with relevant read locks held (kvm->mm->mmap_lock, kvm->srcu) 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_cistatic inline int __do_essa(struct kvm_vcpu *vcpu, const int orc) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci int r1, r2, nappended, entries; 11448c2ecf20Sopenharmony_ci unsigned long gfn, hva, res, pgstev, ptev; 11458c2ecf20Sopenharmony_ci unsigned long *cbrlo; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* 11488c2ecf20Sopenharmony_ci * We don't need to set SD.FPF.SK to 1 here, because if we have a 11498c2ecf20Sopenharmony_ci * machine check here we either handle it or crash 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci kvm_s390_get_regs_rre(vcpu, &r1, &r2); 11538c2ecf20Sopenharmony_ci gfn = vcpu->run->s.regs.gprs[r2] >> PAGE_SHIFT; 11548c2ecf20Sopenharmony_ci hva = gfn_to_hva(vcpu->kvm, gfn); 11558c2ecf20Sopenharmony_ci entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) 11588c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci nappended = pgste_perform_essa(vcpu->kvm->mm, hva, orc, &ptev, &pgstev); 11618c2ecf20Sopenharmony_ci if (nappended < 0) { 11628c2ecf20Sopenharmony_ci res = orc ? 0x10 : 0; 11638c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[r1] = res; /* Exception Indication */ 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci res = (pgstev & _PGSTE_GPS_USAGE_MASK) >> 22; 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * Set the block-content state part of the result. 0 means resident, so 11698c2ecf20Sopenharmony_ci * nothing to do if the page is valid. 2 is for preserved pages 11708c2ecf20Sopenharmony_ci * (non-present and non-zero), and 3 for zero pages (non-present and 11718c2ecf20Sopenharmony_ci * zero). 11728c2ecf20Sopenharmony_ci */ 11738c2ecf20Sopenharmony_ci if (ptev & _PAGE_INVALID) { 11748c2ecf20Sopenharmony_ci res |= 2; 11758c2ecf20Sopenharmony_ci if (pgstev & _PGSTE_GPS_ZERO) 11768c2ecf20Sopenharmony_ci res |= 1; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci if (pgstev & _PGSTE_GPS_NODAT) 11798c2ecf20Sopenharmony_ci res |= 0x20; 11808c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[r1] = res; 11818c2ecf20Sopenharmony_ci /* 11828c2ecf20Sopenharmony_ci * It is possible that all the normal 511 slots were full, in which case 11838c2ecf20Sopenharmony_ci * we will now write in the 512th slot, which is reserved for host use. 11848c2ecf20Sopenharmony_ci * In both cases we let the normal essa handling code process all the 11858c2ecf20Sopenharmony_ci * slots, including the reserved one, if needed. 11868c2ecf20Sopenharmony_ci */ 11878c2ecf20Sopenharmony_ci if (nappended > 0) { 11888c2ecf20Sopenharmony_ci cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo & PAGE_MASK); 11898c2ecf20Sopenharmony_ci cbrlo[entries] = gfn << PAGE_SHIFT; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (orc) { 11938c2ecf20Sopenharmony_ci struct kvm_memory_slot *ms = gfn_to_memslot(vcpu->kvm, gfn); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* Increment only if we are really flipping the bit */ 11968c2ecf20Sopenharmony_ci if (ms && !test_and_set_bit(gfn - ms->base_gfn, kvm_second_dirty_bitmap(ms))) 11978c2ecf20Sopenharmony_ci atomic64_inc(&vcpu->kvm->arch.cmma_dirty_pages); 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci return nappended; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic int handle_essa(struct kvm_vcpu *vcpu) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci /* entries expected to be 1FF */ 12068c2ecf20Sopenharmony_ci int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3; 12078c2ecf20Sopenharmony_ci unsigned long *cbrlo; 12088c2ecf20Sopenharmony_ci struct gmap *gmap; 12098c2ecf20Sopenharmony_ci int i, orc; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "ESSA: release %d pages", entries); 12128c2ecf20Sopenharmony_ci gmap = vcpu->arch.gmap; 12138c2ecf20Sopenharmony_ci vcpu->stat.instruction_essa++; 12148c2ecf20Sopenharmony_ci if (!vcpu->kvm->arch.use_cmma) 12158c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_OPERATION); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 12188c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 12198c2ecf20Sopenharmony_ci /* Check for invalid operation request code */ 12208c2ecf20Sopenharmony_ci orc = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28; 12218c2ecf20Sopenharmony_ci /* ORCs 0-6 are always valid */ 12228c2ecf20Sopenharmony_ci if (orc > (test_kvm_facility(vcpu->kvm, 147) ? ESSA_SET_STABLE_NODAT 12238c2ecf20Sopenharmony_ci : ESSA_SET_STABLE_IF_RESIDENT)) 12248c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (!vcpu->kvm->arch.migration_mode) { 12278c2ecf20Sopenharmony_ci /* 12288c2ecf20Sopenharmony_ci * CMMA is enabled in the KVM settings, but is disabled in 12298c2ecf20Sopenharmony_ci * the SIE block and in the mm_context, and we are not doing 12308c2ecf20Sopenharmony_ci * a migration. Enable CMMA in the mm_context. 12318c2ecf20Sopenharmony_ci * Since we need to take a write lock to write to the context 12328c2ecf20Sopenharmony_ci * to avoid races with storage keys handling, we check if the 12338c2ecf20Sopenharmony_ci * value really needs to be written to; if the value is 12348c2ecf20Sopenharmony_ci * already correct, we do nothing and avoid the lock. 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci if (vcpu->kvm->mm->context.uses_cmm == 0) { 12378c2ecf20Sopenharmony_ci mmap_write_lock(vcpu->kvm->mm); 12388c2ecf20Sopenharmony_ci vcpu->kvm->mm->context.uses_cmm = 1; 12398c2ecf20Sopenharmony_ci mmap_write_unlock(vcpu->kvm->mm); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci /* 12428c2ecf20Sopenharmony_ci * If we are here, we are supposed to have CMMA enabled in 12438c2ecf20Sopenharmony_ci * the SIE block. Enabling CMMA works on a per-CPU basis, 12448c2ecf20Sopenharmony_ci * while the context use_cmma flag is per process. 12458c2ecf20Sopenharmony_ci * It's possible that the context flag is enabled and the 12468c2ecf20Sopenharmony_ci * SIE flag is not, so we set the flag always; if it was 12478c2ecf20Sopenharmony_ci * already set, nothing changes, otherwise we enable it 12488c2ecf20Sopenharmony_ci * on this CPU too. 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 |= ECB2_CMMA; 12518c2ecf20Sopenharmony_ci /* Retry the ESSA instruction */ 12528c2ecf20Sopenharmony_ci kvm_s390_retry_instr(vcpu); 12538c2ecf20Sopenharmony_ci } else { 12548c2ecf20Sopenharmony_ci int srcu_idx; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci mmap_read_lock(vcpu->kvm->mm); 12578c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 12588c2ecf20Sopenharmony_ci i = __do_essa(vcpu, orc); 12598c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); 12608c2ecf20Sopenharmony_ci mmap_read_unlock(vcpu->kvm->mm); 12618c2ecf20Sopenharmony_ci if (i < 0) 12628c2ecf20Sopenharmony_ci return i; 12638c2ecf20Sopenharmony_ci /* Account for the possible extra cbrl entry */ 12648c2ecf20Sopenharmony_ci entries += i; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */ 12678c2ecf20Sopenharmony_ci cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo); 12688c2ecf20Sopenharmony_ci mmap_read_lock(gmap->mm); 12698c2ecf20Sopenharmony_ci for (i = 0; i < entries; ++i) 12708c2ecf20Sopenharmony_ci __gmap_zap(gmap, cbrlo[i]); 12718c2ecf20Sopenharmony_ci mmap_read_unlock(gmap->mm); 12728c2ecf20Sopenharmony_ci return 0; 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ciint kvm_s390_handle_b9(struct kvm_vcpu *vcpu) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->ipa & 0x00ff) { 12788c2ecf20Sopenharmony_ci case 0x8a: 12798c2ecf20Sopenharmony_ci case 0x8e: 12808c2ecf20Sopenharmony_ci case 0x8f: 12818c2ecf20Sopenharmony_ci return handle_ipte_interlock(vcpu); 12828c2ecf20Sopenharmony_ci case 0x8d: 12838c2ecf20Sopenharmony_ci return handle_epsw(vcpu); 12848c2ecf20Sopenharmony_ci case 0xab: 12858c2ecf20Sopenharmony_ci return handle_essa(vcpu); 12868c2ecf20Sopenharmony_ci case 0xaf: 12878c2ecf20Sopenharmony_ci return handle_pfmf(vcpu); 12888c2ecf20Sopenharmony_ci default: 12898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ciint kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 12968c2ecf20Sopenharmony_ci int reg3 = vcpu->arch.sie_block->ipa & 0x000f; 12978c2ecf20Sopenharmony_ci int reg, rc, nr_regs; 12988c2ecf20Sopenharmony_ci u32 ctl_array[16]; 12998c2ecf20Sopenharmony_ci u64 ga; 13008c2ecf20Sopenharmony_ci u8 ar; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci vcpu->stat.instruction_lctl++; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 13058c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci ga = kvm_s390_get_base_disp_rs(vcpu, &ar); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (ga & 3) 13108c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "LCTL: r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga); 13138c2ecf20Sopenharmony_ci trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, ga); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci nr_regs = ((reg3 - reg1) & 0xf) + 1; 13168c2ecf20Sopenharmony_ci rc = read_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u32)); 13178c2ecf20Sopenharmony_ci if (rc) 13188c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 13198c2ecf20Sopenharmony_ci reg = reg1; 13208c2ecf20Sopenharmony_ci nr_regs = 0; 13218c2ecf20Sopenharmony_ci do { 13228c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; 13238c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gcr[reg] |= ctl_array[nr_regs++]; 13248c2ecf20Sopenharmony_ci if (reg == reg3) 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci reg = (reg + 1) % 16; 13278c2ecf20Sopenharmony_ci } while (1); 13288c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); 13298c2ecf20Sopenharmony_ci return 0; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ciint kvm_s390_handle_stctl(struct kvm_vcpu *vcpu) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 13358c2ecf20Sopenharmony_ci int reg3 = vcpu->arch.sie_block->ipa & 0x000f; 13368c2ecf20Sopenharmony_ci int reg, rc, nr_regs; 13378c2ecf20Sopenharmony_ci u32 ctl_array[16]; 13388c2ecf20Sopenharmony_ci u64 ga; 13398c2ecf20Sopenharmony_ci u8 ar; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci vcpu->stat.instruction_stctl++; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 13448c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci ga = kvm_s390_get_base_disp_rs(vcpu, &ar); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci if (ga & 3) 13498c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "STCTL r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga); 13528c2ecf20Sopenharmony_ci trace_kvm_s390_handle_stctl(vcpu, 0, reg1, reg3, ga); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci reg = reg1; 13558c2ecf20Sopenharmony_ci nr_regs = 0; 13568c2ecf20Sopenharmony_ci do { 13578c2ecf20Sopenharmony_ci ctl_array[nr_regs++] = vcpu->arch.sie_block->gcr[reg]; 13588c2ecf20Sopenharmony_ci if (reg == reg3) 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci reg = (reg + 1) % 16; 13618c2ecf20Sopenharmony_ci } while (1); 13628c2ecf20Sopenharmony_ci rc = write_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u32)); 13638c2ecf20Sopenharmony_ci return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic int handle_lctlg(struct kvm_vcpu *vcpu) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 13698c2ecf20Sopenharmony_ci int reg3 = vcpu->arch.sie_block->ipa & 0x000f; 13708c2ecf20Sopenharmony_ci int reg, rc, nr_regs; 13718c2ecf20Sopenharmony_ci u64 ctl_array[16]; 13728c2ecf20Sopenharmony_ci u64 ga; 13738c2ecf20Sopenharmony_ci u8 ar; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci vcpu->stat.instruction_lctlg++; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 13788c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci ga = kvm_s390_get_base_disp_rsy(vcpu, &ar); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (ga & 7) 13838c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "LCTLG: r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga); 13868c2ecf20Sopenharmony_ci trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, ga); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci nr_regs = ((reg3 - reg1) & 0xf) + 1; 13898c2ecf20Sopenharmony_ci rc = read_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u64)); 13908c2ecf20Sopenharmony_ci if (rc) 13918c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_cond(vcpu, rc); 13928c2ecf20Sopenharmony_ci reg = reg1; 13938c2ecf20Sopenharmony_ci nr_regs = 0; 13948c2ecf20Sopenharmony_ci do { 13958c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gcr[reg] = ctl_array[nr_regs++]; 13968c2ecf20Sopenharmony_ci if (reg == reg3) 13978c2ecf20Sopenharmony_ci break; 13988c2ecf20Sopenharmony_ci reg = (reg + 1) % 16; 13998c2ecf20Sopenharmony_ci } while (1); 14008c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); 14018c2ecf20Sopenharmony_ci return 0; 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic int handle_stctg(struct kvm_vcpu *vcpu) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 14078c2ecf20Sopenharmony_ci int reg3 = vcpu->arch.sie_block->ipa & 0x000f; 14088c2ecf20Sopenharmony_ci int reg, rc, nr_regs; 14098c2ecf20Sopenharmony_ci u64 ctl_array[16]; 14108c2ecf20Sopenharmony_ci u64 ga; 14118c2ecf20Sopenharmony_ci u8 ar; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci vcpu->stat.instruction_stctg++; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 14168c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci ga = kvm_s390_get_base_disp_rsy(vcpu, &ar); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (ga & 7) 14218c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 4, "STCTG r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga); 14248c2ecf20Sopenharmony_ci trace_kvm_s390_handle_stctl(vcpu, 1, reg1, reg3, ga); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci reg = reg1; 14278c2ecf20Sopenharmony_ci nr_regs = 0; 14288c2ecf20Sopenharmony_ci do { 14298c2ecf20Sopenharmony_ci ctl_array[nr_regs++] = vcpu->arch.sie_block->gcr[reg]; 14308c2ecf20Sopenharmony_ci if (reg == reg3) 14318c2ecf20Sopenharmony_ci break; 14328c2ecf20Sopenharmony_ci reg = (reg + 1) % 16; 14338c2ecf20Sopenharmony_ci } while (1); 14348c2ecf20Sopenharmony_ci rc = write_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u64)); 14358c2ecf20Sopenharmony_ci return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ciint kvm_s390_handle_eb(struct kvm_vcpu *vcpu) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->ipb & 0x000000ff) { 14418c2ecf20Sopenharmony_ci case 0x25: 14428c2ecf20Sopenharmony_ci return handle_stctg(vcpu); 14438c2ecf20Sopenharmony_ci case 0x2f: 14448c2ecf20Sopenharmony_ci return handle_lctlg(vcpu); 14458c2ecf20Sopenharmony_ci case 0x60: 14468c2ecf20Sopenharmony_ci case 0x61: 14478c2ecf20Sopenharmony_ci case 0x62: 14488c2ecf20Sopenharmony_ci return handle_ri(vcpu); 14498c2ecf20Sopenharmony_ci default: 14508c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_cistatic int handle_tprot(struct kvm_vcpu *vcpu) 14558c2ecf20Sopenharmony_ci{ 14568c2ecf20Sopenharmony_ci u64 address1, address2; 14578c2ecf20Sopenharmony_ci unsigned long hva, gpa; 14588c2ecf20Sopenharmony_ci int ret = 0, cc = 0; 14598c2ecf20Sopenharmony_ci bool writable; 14608c2ecf20Sopenharmony_ci u8 ar; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci vcpu->stat.instruction_tprot++; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 14658c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci kvm_s390_get_base_disp_sse(vcpu, &address1, &address2, &ar, NULL); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* we only handle the Linux memory detection case: 14708c2ecf20Sopenharmony_ci * access key == 0 14718c2ecf20Sopenharmony_ci * everything else goes to userspace. */ 14728c2ecf20Sopenharmony_ci if (address2 & 0xf0) 14738c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14748c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) 14758c2ecf20Sopenharmony_ci ipte_lock(vcpu); 14768c2ecf20Sopenharmony_ci ret = guest_translate_address(vcpu, address1, ar, &gpa, GACC_STORE); 14778c2ecf20Sopenharmony_ci if (ret == PGM_PROTECTION) { 14788c2ecf20Sopenharmony_ci /* Write protected? Try again with read-only... */ 14798c2ecf20Sopenharmony_ci cc = 1; 14808c2ecf20Sopenharmony_ci ret = guest_translate_address(vcpu, address1, ar, &gpa, 14818c2ecf20Sopenharmony_ci GACC_FETCH); 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci if (ret) { 14848c2ecf20Sopenharmony_ci if (ret == PGM_ADDRESSING || ret == PGM_TRANSLATION_SPEC) { 14858c2ecf20Sopenharmony_ci ret = kvm_s390_inject_program_int(vcpu, ret); 14868c2ecf20Sopenharmony_ci } else if (ret > 0) { 14878c2ecf20Sopenharmony_ci /* Translation not available */ 14888c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 14898c2ecf20Sopenharmony_ci ret = 0; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci goto out_unlock; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci hva = gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable); 14958c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) { 14968c2ecf20Sopenharmony_ci ret = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 14978c2ecf20Sopenharmony_ci } else { 14988c2ecf20Sopenharmony_ci if (!writable) 14998c2ecf20Sopenharmony_ci cc = 1; /* Write not permitted ==> read-only */ 15008c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, cc); 15018c2ecf20Sopenharmony_ci /* Note: CC2 only occurs for storage keys (not supported yet) */ 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ciout_unlock: 15048c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) 15058c2ecf20Sopenharmony_ci ipte_unlock(vcpu); 15068c2ecf20Sopenharmony_ci return ret; 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ciint kvm_s390_handle_e5(struct kvm_vcpu *vcpu) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->ipa & 0x00ff) { 15128c2ecf20Sopenharmony_ci case 0x01: 15138c2ecf20Sopenharmony_ci return handle_tprot(vcpu); 15148c2ecf20Sopenharmony_ci default: 15158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_cistatic int handle_sckpf(struct kvm_vcpu *vcpu) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci u32 value; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci vcpu->stat.instruction_sckpf++; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 15268c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (vcpu->run->s.regs.gprs[0] & 0x00000000ffff0000) 15298c2ecf20Sopenharmony_ci return kvm_s390_inject_program_int(vcpu, 15308c2ecf20Sopenharmony_ci PGM_SPECIFICATION); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci value = vcpu->run->s.regs.gprs[0] & 0x000000000000ffff; 15338c2ecf20Sopenharmony_ci vcpu->arch.sie_block->todpr = value; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci return 0; 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic int handle_ptff(struct kvm_vcpu *vcpu) 15398c2ecf20Sopenharmony_ci{ 15408c2ecf20Sopenharmony_ci vcpu->stat.instruction_ptff++; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci /* we don't emulate any control instructions yet */ 15438c2ecf20Sopenharmony_ci kvm_s390_set_psw_cc(vcpu, 3); 15448c2ecf20Sopenharmony_ci return 0; 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ciint kvm_s390_handle_01(struct kvm_vcpu *vcpu) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci switch (vcpu->arch.sie_block->ipa & 0x00ff) { 15508c2ecf20Sopenharmony_ci case 0x04: 15518c2ecf20Sopenharmony_ci return handle_ptff(vcpu); 15528c2ecf20Sopenharmony_ci case 0x07: 15538c2ecf20Sopenharmony_ci return handle_sckpf(vcpu); 15548c2ecf20Sopenharmony_ci default: 15558c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci} 1558