18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * hosting IBM Z kernel virtual machines (s390x) 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 * Heiko Carstens <heiko.carstens@de.ibm.com> 108c2ecf20Sopenharmony_ci * Christian Ehrhardt <ehrhardt@de.ibm.com> 118c2ecf20Sopenharmony_ci * Jason J. Herne <jjherne@us.ibm.com> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "kvm-s390" 158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/compiler.h> 188c2ecf20Sopenharmony_ci#include <linux/err.h> 198c2ecf20Sopenharmony_ci#include <linux/fs.h> 208c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/kvm.h> 238c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 248c2ecf20Sopenharmony_ci#include <linux/mman.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 278c2ecf20Sopenharmony_ci#include <linux/random.h> 288c2ecf20Sopenharmony_ci#include <linux/slab.h> 298c2ecf20Sopenharmony_ci#include <linux/timer.h> 308c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 318c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 328c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 338c2ecf20Sopenharmony_ci#include <linux/string.h> 348c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 378c2ecf20Sopenharmony_ci#include <asm/lowcore.h> 388c2ecf20Sopenharmony_ci#include <asm/stp.h> 398c2ecf20Sopenharmony_ci#include <asm/gmap.h> 408c2ecf20Sopenharmony_ci#include <asm/nmi.h> 418c2ecf20Sopenharmony_ci#include <asm/switch_to.h> 428c2ecf20Sopenharmony_ci#include <asm/isc.h> 438c2ecf20Sopenharmony_ci#include <asm/sclp.h> 448c2ecf20Sopenharmony_ci#include <asm/cpacf.h> 458c2ecf20Sopenharmony_ci#include <asm/timex.h> 468c2ecf20Sopenharmony_ci#include <asm/ap.h> 478c2ecf20Sopenharmony_ci#include <asm/uv.h> 488c2ecf20Sopenharmony_ci#include "kvm-s390.h" 498c2ecf20Sopenharmony_ci#include "gaccess.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 528c2ecf20Sopenharmony_ci#include "trace.h" 538c2ecf20Sopenharmony_ci#include "trace-s390.h" 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */ 568c2ecf20Sopenharmony_ci#define LOCAL_IRQS 32 578c2ecf20Sopenharmony_ci#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \ 588c2ecf20Sopenharmony_ci (KVM_MAX_VCPUS + LOCAL_IRQS)) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct kvm_stats_debugfs_item debugfs_entries[] = { 618c2ecf20Sopenharmony_ci VCPU_STAT("userspace_handled", exit_userspace), 628c2ecf20Sopenharmony_ci VCPU_STAT("exit_null", exit_null), 638c2ecf20Sopenharmony_ci VCPU_STAT("exit_validity", exit_validity), 648c2ecf20Sopenharmony_ci VCPU_STAT("exit_stop_request", exit_stop_request), 658c2ecf20Sopenharmony_ci VCPU_STAT("exit_external_request", exit_external_request), 668c2ecf20Sopenharmony_ci VCPU_STAT("exit_io_request", exit_io_request), 678c2ecf20Sopenharmony_ci VCPU_STAT("exit_external_interrupt", exit_external_interrupt), 688c2ecf20Sopenharmony_ci VCPU_STAT("exit_instruction", exit_instruction), 698c2ecf20Sopenharmony_ci VCPU_STAT("exit_pei", exit_pei), 708c2ecf20Sopenharmony_ci VCPU_STAT("exit_program_interruption", exit_program_interruption), 718c2ecf20Sopenharmony_ci VCPU_STAT("exit_instr_and_program_int", exit_instr_and_program), 728c2ecf20Sopenharmony_ci VCPU_STAT("exit_operation_exception", exit_operation_exception), 738c2ecf20Sopenharmony_ci VCPU_STAT("halt_successful_poll", halt_successful_poll), 748c2ecf20Sopenharmony_ci VCPU_STAT("halt_attempted_poll", halt_attempted_poll), 758c2ecf20Sopenharmony_ci VCPU_STAT("halt_poll_invalid", halt_poll_invalid), 768c2ecf20Sopenharmony_ci VCPU_STAT("halt_no_poll_steal", halt_no_poll_steal), 778c2ecf20Sopenharmony_ci VCPU_STAT("halt_wakeup", halt_wakeup), 788c2ecf20Sopenharmony_ci VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 798c2ecf20Sopenharmony_ci VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 808c2ecf20Sopenharmony_ci VCPU_STAT("instruction_lctlg", instruction_lctlg), 818c2ecf20Sopenharmony_ci VCPU_STAT("instruction_lctl", instruction_lctl), 828c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stctl", instruction_stctl), 838c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stctg", instruction_stctg), 848c2ecf20Sopenharmony_ci VCPU_STAT("deliver_ckc", deliver_ckc), 858c2ecf20Sopenharmony_ci VCPU_STAT("deliver_cputm", deliver_cputm), 868c2ecf20Sopenharmony_ci VCPU_STAT("deliver_emergency_signal", deliver_emergency_signal), 878c2ecf20Sopenharmony_ci VCPU_STAT("deliver_external_call", deliver_external_call), 888c2ecf20Sopenharmony_ci VCPU_STAT("deliver_service_signal", deliver_service_signal), 898c2ecf20Sopenharmony_ci VCPU_STAT("deliver_virtio", deliver_virtio), 908c2ecf20Sopenharmony_ci VCPU_STAT("deliver_stop_signal", deliver_stop_signal), 918c2ecf20Sopenharmony_ci VCPU_STAT("deliver_prefix_signal", deliver_prefix_signal), 928c2ecf20Sopenharmony_ci VCPU_STAT("deliver_restart_signal", deliver_restart_signal), 938c2ecf20Sopenharmony_ci VCPU_STAT("deliver_program", deliver_program), 948c2ecf20Sopenharmony_ci VCPU_STAT("deliver_io", deliver_io), 958c2ecf20Sopenharmony_ci VCPU_STAT("deliver_machine_check", deliver_machine_check), 968c2ecf20Sopenharmony_ci VCPU_STAT("exit_wait_state", exit_wait_state), 978c2ecf20Sopenharmony_ci VCPU_STAT("inject_ckc", inject_ckc), 988c2ecf20Sopenharmony_ci VCPU_STAT("inject_cputm", inject_cputm), 998c2ecf20Sopenharmony_ci VCPU_STAT("inject_external_call", inject_external_call), 1008c2ecf20Sopenharmony_ci VM_STAT("inject_float_mchk", inject_float_mchk), 1018c2ecf20Sopenharmony_ci VCPU_STAT("inject_emergency_signal", inject_emergency_signal), 1028c2ecf20Sopenharmony_ci VM_STAT("inject_io", inject_io), 1038c2ecf20Sopenharmony_ci VCPU_STAT("inject_mchk", inject_mchk), 1048c2ecf20Sopenharmony_ci VM_STAT("inject_pfault_done", inject_pfault_done), 1058c2ecf20Sopenharmony_ci VCPU_STAT("inject_program", inject_program), 1068c2ecf20Sopenharmony_ci VCPU_STAT("inject_restart", inject_restart), 1078c2ecf20Sopenharmony_ci VM_STAT("inject_service_signal", inject_service_signal), 1088c2ecf20Sopenharmony_ci VCPU_STAT("inject_set_prefix", inject_set_prefix), 1098c2ecf20Sopenharmony_ci VCPU_STAT("inject_stop_signal", inject_stop_signal), 1108c2ecf20Sopenharmony_ci VCPU_STAT("inject_pfault_init", inject_pfault_init), 1118c2ecf20Sopenharmony_ci VM_STAT("inject_virtio", inject_virtio), 1128c2ecf20Sopenharmony_ci VCPU_STAT("instruction_epsw", instruction_epsw), 1138c2ecf20Sopenharmony_ci VCPU_STAT("instruction_gs", instruction_gs), 1148c2ecf20Sopenharmony_ci VCPU_STAT("instruction_io_other", instruction_io_other), 1158c2ecf20Sopenharmony_ci VCPU_STAT("instruction_lpsw", instruction_lpsw), 1168c2ecf20Sopenharmony_ci VCPU_STAT("instruction_lpswe", instruction_lpswe), 1178c2ecf20Sopenharmony_ci VCPU_STAT("instruction_pfmf", instruction_pfmf), 1188c2ecf20Sopenharmony_ci VCPU_STAT("instruction_ptff", instruction_ptff), 1198c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stidp", instruction_stidp), 1208c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sck", instruction_sck), 1218c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sckpf", instruction_sckpf), 1228c2ecf20Sopenharmony_ci VCPU_STAT("instruction_spx", instruction_spx), 1238c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stpx", instruction_stpx), 1248c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stap", instruction_stap), 1258c2ecf20Sopenharmony_ci VCPU_STAT("instruction_iske", instruction_iske), 1268c2ecf20Sopenharmony_ci VCPU_STAT("instruction_ri", instruction_ri), 1278c2ecf20Sopenharmony_ci VCPU_STAT("instruction_rrbe", instruction_rrbe), 1288c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sske", instruction_sske), 1298c2ecf20Sopenharmony_ci VCPU_STAT("instruction_ipte_interlock", instruction_ipte_interlock), 1308c2ecf20Sopenharmony_ci VCPU_STAT("instruction_essa", instruction_essa), 1318c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stsi", instruction_stsi), 1328c2ecf20Sopenharmony_ci VCPU_STAT("instruction_stfl", instruction_stfl), 1338c2ecf20Sopenharmony_ci VCPU_STAT("instruction_tb", instruction_tb), 1348c2ecf20Sopenharmony_ci VCPU_STAT("instruction_tpi", instruction_tpi), 1358c2ecf20Sopenharmony_ci VCPU_STAT("instruction_tprot", instruction_tprot), 1368c2ecf20Sopenharmony_ci VCPU_STAT("instruction_tsch", instruction_tsch), 1378c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sthyi", instruction_sthyi), 1388c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sie", instruction_sie), 1398c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_sense", instruction_sigp_sense), 1408c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_sense_running", instruction_sigp_sense_running), 1418c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_external_call", instruction_sigp_external_call), 1428c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_emergency", instruction_sigp_emergency), 1438c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_cond_emergency", instruction_sigp_cond_emergency), 1448c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_start", instruction_sigp_start), 1458c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_stop", instruction_sigp_stop), 1468c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_stop_store_status", instruction_sigp_stop_store_status), 1478c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_store_status", instruction_sigp_store_status), 1488c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_store_adtl_status", instruction_sigp_store_adtl_status), 1498c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_set_arch", instruction_sigp_arch), 1508c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_set_prefix", instruction_sigp_prefix), 1518c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_restart", instruction_sigp_restart), 1528c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_cpu_reset", instruction_sigp_cpu_reset), 1538c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_init_cpu_reset", instruction_sigp_init_cpu_reset), 1548c2ecf20Sopenharmony_ci VCPU_STAT("instruction_sigp_unknown", instruction_sigp_unknown), 1558c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_10", diagnose_10), 1568c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_44", diagnose_44), 1578c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_9c", diagnose_9c), 1588c2ecf20Sopenharmony_ci VCPU_STAT("diag_9c_ignored", diagnose_9c_ignored), 1598c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_258", diagnose_258), 1608c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_308", diagnose_308), 1618c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_500", diagnose_500), 1628c2ecf20Sopenharmony_ci VCPU_STAT("instruction_diag_other", diagnose_other), 1638c2ecf20Sopenharmony_ci { NULL } 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistruct kvm_s390_tod_clock_ext { 1678c2ecf20Sopenharmony_ci __u8 epoch_idx; 1688c2ecf20Sopenharmony_ci __u64 tod; 1698c2ecf20Sopenharmony_ci __u8 reserved[7]; 1708c2ecf20Sopenharmony_ci} __packed; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* allow nested virtualization in KVM (if enabled by user space) */ 1738c2ecf20Sopenharmony_cistatic int nested; 1748c2ecf20Sopenharmony_cimodule_param(nested, int, S_IRUGO); 1758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nested, "Nested virtualization support"); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* allow 1m huge page guest backing, if !nested */ 1788c2ecf20Sopenharmony_cistatic int hpage; 1798c2ecf20Sopenharmony_cimodule_param(hpage, int, 0444); 1808c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hpage, "1m huge page backing support"); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* maximum percentage of steal time for polling. >100 is treated like 100 */ 1838c2ecf20Sopenharmony_cistatic u8 halt_poll_max_steal = 10; 1848c2ecf20Sopenharmony_cimodule_param(halt_poll_max_steal, byte, 0644); 1858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(halt_poll_max_steal, "Maximum percentage of steal time to allow polling"); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* if set to true, the GISA will be initialized and used if available */ 1888c2ecf20Sopenharmony_cistatic bool use_gisa = true; 1898c2ecf20Sopenharmony_cimodule_param(use_gisa, bool, 0644); 1908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_gisa, "Use the GISA if the host supports it."); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * For now we handle at most 16 double words as this is what the s390 base 1948c2ecf20Sopenharmony_ci * kernel handles and stores in the prefix page. If we ever need to go beyond 1958c2ecf20Sopenharmony_ci * this, this requires changes to code, but the external uapi can stay. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci#define SIZE_INTERNAL 16 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * Base feature mask that defines default mask for facilities. Consists of the 2018c2ecf20Sopenharmony_ci * defines in FACILITIES_KVM and the non-hypervisor managed bits. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_cistatic unsigned long kvm_s390_fac_base[SIZE_INTERNAL] = { FACILITIES_KVM }; 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * Extended feature mask. Consists of the defines in FACILITIES_KVM_CPUMODEL 2068c2ecf20Sopenharmony_ci * and defines the facilities that can be enabled via a cpu model. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_cistatic unsigned long kvm_s390_fac_ext[SIZE_INTERNAL] = { FACILITIES_KVM_CPUMODEL }; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic unsigned long kvm_s390_fac_size(void) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_MASK_SIZE_U64); 2138c2ecf20Sopenharmony_ci BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_LIST_SIZE_U64); 2148c2ecf20Sopenharmony_ci BUILD_BUG_ON(SIZE_INTERNAL * sizeof(unsigned long) > 2158c2ecf20Sopenharmony_ci sizeof(S390_lowcore.stfle_fac_list)); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return SIZE_INTERNAL; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* available cpu features supported by kvm */ 2218c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS); 2228c2ecf20Sopenharmony_ci/* available subfunctions indicated via query / "test bit" */ 2238c2ecf20Sopenharmony_cistatic struct kvm_s390_vm_cpu_subfunc kvm_s390_available_subfunc; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic struct gmap_notifier gmap_notifier; 2268c2ecf20Sopenharmony_cistatic struct gmap_notifier vsie_gmap_notifier; 2278c2ecf20Sopenharmony_cidebug_info_t *kvm_s390_dbf; 2288c2ecf20Sopenharmony_cidebug_info_t *kvm_s390_dbf_uv; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* Section: not file related */ 2318c2ecf20Sopenharmony_ciint kvm_arch_hardware_enable(void) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci /* every s390 is virtualization enabled ;-) */ 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint kvm_arch_check_processor_compat(void *opaque) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* forward declarations */ 2438c2ecf20Sopenharmony_cistatic void kvm_gmap_notifier(struct gmap *gmap, unsigned long start, 2448c2ecf20Sopenharmony_ci unsigned long end); 2458c2ecf20Sopenharmony_cistatic int sca_switch_to_extended(struct kvm *kvm); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void kvm_clock_sync_scb(struct kvm_s390_sie_block *scb, u64 delta) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u8 delta_idx = 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * The TOD jumps by delta, we have to compensate this by adding 2538c2ecf20Sopenharmony_ci * -delta to the epoch. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci delta = -delta; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* sign-extension - we're adding to signed values below */ 2588c2ecf20Sopenharmony_ci if ((s64)delta < 0) 2598c2ecf20Sopenharmony_ci delta_idx = -1; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci scb->epoch += delta; 2628c2ecf20Sopenharmony_ci if (scb->ecd & ECD_MEF) { 2638c2ecf20Sopenharmony_ci scb->epdx += delta_idx; 2648c2ecf20Sopenharmony_ci if (scb->epoch < delta) 2658c2ecf20Sopenharmony_ci scb->epdx += 1; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* 2708c2ecf20Sopenharmony_ci * This callback is executed during stop_machine(). All CPUs are therefore 2718c2ecf20Sopenharmony_ci * temporarily stopped. In order not to change guest behavior, we have to 2728c2ecf20Sopenharmony_ci * disable preemption whenever we touch the epoch of kvm and the VCPUs, 2738c2ecf20Sopenharmony_ci * so a CPU won't be stopped while calculating with the epoch. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_cistatic int kvm_clock_sync(struct notifier_block *notifier, unsigned long val, 2768c2ecf20Sopenharmony_ci void *v) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct kvm *kvm; 2798c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 2808c2ecf20Sopenharmony_ci int i; 2818c2ecf20Sopenharmony_ci unsigned long long *delta = v; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci list_for_each_entry(kvm, &vm_list, vm_list) { 2848c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 2858c2ecf20Sopenharmony_ci kvm_clock_sync_scb(vcpu->arch.sie_block, *delta); 2868c2ecf20Sopenharmony_ci if (i == 0) { 2878c2ecf20Sopenharmony_ci kvm->arch.epoch = vcpu->arch.sie_block->epoch; 2888c2ecf20Sopenharmony_ci kvm->arch.epdx = vcpu->arch.sie_block->epdx; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci if (vcpu->arch.cputm_enabled) 2918c2ecf20Sopenharmony_ci vcpu->arch.cputm_start += *delta; 2928c2ecf20Sopenharmony_ci if (vcpu->arch.vsie_block) 2938c2ecf20Sopenharmony_ci kvm_clock_sync_scb(vcpu->arch.vsie_block, 2948c2ecf20Sopenharmony_ci *delta); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci return NOTIFY_OK; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic struct notifier_block kvm_clock_notifier = { 3018c2ecf20Sopenharmony_ci .notifier_call = kvm_clock_sync, 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciint kvm_arch_hardware_setup(void *opaque) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci gmap_notifier.notifier_call = kvm_gmap_notifier; 3078c2ecf20Sopenharmony_ci gmap_register_pte_notifier(&gmap_notifier); 3088c2ecf20Sopenharmony_ci vsie_gmap_notifier.notifier_call = kvm_s390_vsie_gmap_notifier; 3098c2ecf20Sopenharmony_ci gmap_register_pte_notifier(&vsie_gmap_notifier); 3108c2ecf20Sopenharmony_ci atomic_notifier_chain_register(&s390_epoch_delta_notifier, 3118c2ecf20Sopenharmony_ci &kvm_clock_notifier); 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_civoid kvm_arch_hardware_unsetup(void) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci gmap_unregister_pte_notifier(&gmap_notifier); 3188c2ecf20Sopenharmony_ci gmap_unregister_pte_notifier(&vsie_gmap_notifier); 3198c2ecf20Sopenharmony_ci atomic_notifier_chain_unregister(&s390_epoch_delta_notifier, 3208c2ecf20Sopenharmony_ci &kvm_clock_notifier); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void allow_cpu_feat(unsigned long nr) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci set_bit_inv(nr, kvm_s390_available_cpu_feat); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic inline int plo_test_bit(unsigned char nr) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci unsigned long function = (unsigned long)nr | 0x100; 3318c2ecf20Sopenharmony_ci int cc; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci asm volatile( 3348c2ecf20Sopenharmony_ci " lgr 0,%[function]\n" 3358c2ecf20Sopenharmony_ci /* Parameter registers are ignored for "test bit" */ 3368c2ecf20Sopenharmony_ci " plo 0,0,0,0(0)\n" 3378c2ecf20Sopenharmony_ci " ipm %0\n" 3388c2ecf20Sopenharmony_ci " srl %0,28\n" 3398c2ecf20Sopenharmony_ci : "=d" (cc) 3408c2ecf20Sopenharmony_ci : [function] "d" (function) 3418c2ecf20Sopenharmony_ci : "cc", "0"); 3428c2ecf20Sopenharmony_ci return cc == 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic __always_inline void __insn32_query(unsigned int opcode, u8 *query) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci asm volatile( 3488c2ecf20Sopenharmony_ci " lghi 0,0\n" 3498c2ecf20Sopenharmony_ci " lgr 1,%[query]\n" 3508c2ecf20Sopenharmony_ci /* Parameter registers are ignored */ 3518c2ecf20Sopenharmony_ci " .insn rrf,%[opc] << 16,2,4,6,0\n" 3528c2ecf20Sopenharmony_ci : 3538c2ecf20Sopenharmony_ci : [query] "d" ((unsigned long)query), [opc] "i" (opcode) 3548c2ecf20Sopenharmony_ci : "cc", "memory", "0", "1"); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci#define INSN_SORTL 0xb938 3588c2ecf20Sopenharmony_ci#define INSN_DFLTCC 0xb939 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic void kvm_s390_cpu_feat_init(void) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci int i; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci for (i = 0; i < 256; ++i) { 3658c2ecf20Sopenharmony_ci if (plo_test_bit(i)) 3668c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.plo[i >> 3] |= 0x80 >> (i & 7); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (test_facility(28)) /* TOD-clock steering */ 3708c2ecf20Sopenharmony_ci ptff(kvm_s390_available_subfunc.ptff, 3718c2ecf20Sopenharmony_ci sizeof(kvm_s390_available_subfunc.ptff), 3728c2ecf20Sopenharmony_ci PTFF_QAF); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (test_facility(17)) { /* MSA */ 3758c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KMAC, (cpacf_mask_t *) 3768c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kmac); 3778c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KMC, (cpacf_mask_t *) 3788c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kmc); 3798c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KM, (cpacf_mask_t *) 3808c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.km); 3818c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KIMD, (cpacf_mask_t *) 3828c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kimd); 3838c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KLMD, (cpacf_mask_t *) 3848c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.klmd); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci if (test_facility(76)) /* MSA3 */ 3878c2ecf20Sopenharmony_ci __cpacf_query(CPACF_PCKMO, (cpacf_mask_t *) 3888c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.pckmo); 3898c2ecf20Sopenharmony_ci if (test_facility(77)) { /* MSA4 */ 3908c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KMCTR, (cpacf_mask_t *) 3918c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kmctr); 3928c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KMF, (cpacf_mask_t *) 3938c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kmf); 3948c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KMO, (cpacf_mask_t *) 3958c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kmo); 3968c2ecf20Sopenharmony_ci __cpacf_query(CPACF_PCC, (cpacf_mask_t *) 3978c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.pcc); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci if (test_facility(57)) /* MSA5 */ 4008c2ecf20Sopenharmony_ci __cpacf_query(CPACF_PRNO, (cpacf_mask_t *) 4018c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.ppno); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (test_facility(146)) /* MSA8 */ 4048c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KMA, (cpacf_mask_t *) 4058c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kma); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (test_facility(155)) /* MSA9 */ 4088c2ecf20Sopenharmony_ci __cpacf_query(CPACF_KDSA, (cpacf_mask_t *) 4098c2ecf20Sopenharmony_ci kvm_s390_available_subfunc.kdsa); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (test_facility(150)) /* SORTL */ 4128c2ecf20Sopenharmony_ci __insn32_query(INSN_SORTL, kvm_s390_available_subfunc.sortl); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (test_facility(151)) /* DFLTCC */ 4158c2ecf20Sopenharmony_ci __insn32_query(INSN_DFLTCC, kvm_s390_available_subfunc.dfltcc); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (MACHINE_HAS_ESOP) 4188c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_ESOP); 4198c2ecf20Sopenharmony_ci /* 4208c2ecf20Sopenharmony_ci * We need SIE support, ESOP (PROT_READ protection for gmap_shadow), 4218c2ecf20Sopenharmony_ci * 64bit SCAO (SCA passthrough) and IDTE (for gmap_shadow unshadowing). 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ci if (!sclp.has_sief2 || !MACHINE_HAS_ESOP || !sclp.has_64bscao || 4248c2ecf20Sopenharmony_ci !test_facility(3) || !nested) 4258c2ecf20Sopenharmony_ci return; 4268c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2); 4278c2ecf20Sopenharmony_ci if (sclp.has_64bscao) 4288c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO); 4298c2ecf20Sopenharmony_ci if (sclp.has_siif) 4308c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF); 4318c2ecf20Sopenharmony_ci if (sclp.has_gpere) 4328c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_GPERE); 4338c2ecf20Sopenharmony_ci if (sclp.has_gsls) 4348c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_GSLS); 4358c2ecf20Sopenharmony_ci if (sclp.has_ib) 4368c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IB); 4378c2ecf20Sopenharmony_ci if (sclp.has_cei) 4388c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_CEI); 4398c2ecf20Sopenharmony_ci if (sclp.has_ibs) 4408c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IBS); 4418c2ecf20Sopenharmony_ci if (sclp.has_kss) 4428c2ecf20Sopenharmony_ci allow_cpu_feat(KVM_S390_VM_CPU_FEAT_KSS); 4438c2ecf20Sopenharmony_ci /* 4448c2ecf20Sopenharmony_ci * KVM_S390_VM_CPU_FEAT_SKEY: Wrong shadow of PTE.I bits will make 4458c2ecf20Sopenharmony_ci * all skey handling functions read/set the skey from the PGSTE 4468c2ecf20Sopenharmony_ci * instead of the real storage key. 4478c2ecf20Sopenharmony_ci * 4488c2ecf20Sopenharmony_ci * KVM_S390_VM_CPU_FEAT_CMMA: Wrong shadow of PTE.I bits will make 4498c2ecf20Sopenharmony_ci * pages being detected as preserved although they are resident. 4508c2ecf20Sopenharmony_ci * 4518c2ecf20Sopenharmony_ci * KVM_S390_VM_CPU_FEAT_PFMFI: Wrong shadow of PTE.I bits will 4528c2ecf20Sopenharmony_ci * have the same effect as for KVM_S390_VM_CPU_FEAT_SKEY. 4538c2ecf20Sopenharmony_ci * 4548c2ecf20Sopenharmony_ci * For KVM_S390_VM_CPU_FEAT_SKEY, KVM_S390_VM_CPU_FEAT_CMMA and 4558c2ecf20Sopenharmony_ci * KVM_S390_VM_CPU_FEAT_PFMFI, all PTE.I and PGSTE bits have to be 4568c2ecf20Sopenharmony_ci * correctly shadowed. We can do that for the PGSTE but not for PTE.I. 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci * KVM_S390_VM_CPU_FEAT_SIGPIF: Wrong SCB addresses in the SCA. We 4598c2ecf20Sopenharmony_ci * cannot easily shadow the SCA because of the ipte lock. 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ciint kvm_arch_init(void *opaque) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci int rc = -ENOMEM; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci kvm_s390_dbf = debug_register("kvm-trace", 32, 1, 7 * sizeof(long)); 4688c2ecf20Sopenharmony_ci if (!kvm_s390_dbf) 4698c2ecf20Sopenharmony_ci return -ENOMEM; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci kvm_s390_dbf_uv = debug_register("kvm-uv", 32, 1, 7 * sizeof(long)); 4728c2ecf20Sopenharmony_ci if (!kvm_s390_dbf_uv) 4738c2ecf20Sopenharmony_ci goto out; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (debug_register_view(kvm_s390_dbf, &debug_sprintf_view) || 4768c2ecf20Sopenharmony_ci debug_register_view(kvm_s390_dbf_uv, &debug_sprintf_view)) 4778c2ecf20Sopenharmony_ci goto out; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci kvm_s390_cpu_feat_init(); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* Register floating interrupt controller interface. */ 4828c2ecf20Sopenharmony_ci rc = kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC); 4838c2ecf20Sopenharmony_ci if (rc) { 4848c2ecf20Sopenharmony_ci pr_err("A FLIC registration call failed with rc=%d\n", rc); 4858c2ecf20Sopenharmony_ci goto out; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci rc = kvm_s390_gib_init(GAL_ISC); 4898c2ecf20Sopenharmony_ci if (rc) 4908c2ecf20Sopenharmony_ci goto out; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ciout: 4958c2ecf20Sopenharmony_ci kvm_arch_exit(); 4968c2ecf20Sopenharmony_ci return rc; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_civoid kvm_arch_exit(void) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci kvm_s390_gib_destroy(); 5028c2ecf20Sopenharmony_ci debug_unregister(kvm_s390_dbf); 5038c2ecf20Sopenharmony_ci debug_unregister(kvm_s390_dbf_uv); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci/* Section: device related */ 5078c2ecf20Sopenharmony_cilong kvm_arch_dev_ioctl(struct file *filp, 5088c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci if (ioctl == KVM_S390_ENABLE_SIE) 5118c2ecf20Sopenharmony_ci return s390_enable_sie(); 5128c2ecf20Sopenharmony_ci return -EINVAL; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ciint kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci int r; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci switch (ext) { 5208c2ecf20Sopenharmony_ci case KVM_CAP_S390_PSW: 5218c2ecf20Sopenharmony_ci case KVM_CAP_S390_GMAP: 5228c2ecf20Sopenharmony_ci case KVM_CAP_SYNC_MMU: 5238c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_S390_UCONTROL 5248c2ecf20Sopenharmony_ci case KVM_CAP_S390_UCONTROL: 5258c2ecf20Sopenharmony_ci#endif 5268c2ecf20Sopenharmony_ci case KVM_CAP_ASYNC_PF: 5278c2ecf20Sopenharmony_ci case KVM_CAP_SYNC_REGS: 5288c2ecf20Sopenharmony_ci case KVM_CAP_ONE_REG: 5298c2ecf20Sopenharmony_ci case KVM_CAP_ENABLE_CAP: 5308c2ecf20Sopenharmony_ci case KVM_CAP_S390_CSS_SUPPORT: 5318c2ecf20Sopenharmony_ci case KVM_CAP_IOEVENTFD: 5328c2ecf20Sopenharmony_ci case KVM_CAP_DEVICE_CTRL: 5338c2ecf20Sopenharmony_ci case KVM_CAP_S390_IRQCHIP: 5348c2ecf20Sopenharmony_ci case KVM_CAP_VM_ATTRIBUTES: 5358c2ecf20Sopenharmony_ci case KVM_CAP_MP_STATE: 5368c2ecf20Sopenharmony_ci case KVM_CAP_IMMEDIATE_EXIT: 5378c2ecf20Sopenharmony_ci case KVM_CAP_S390_INJECT_IRQ: 5388c2ecf20Sopenharmony_ci case KVM_CAP_S390_USER_SIGP: 5398c2ecf20Sopenharmony_ci case KVM_CAP_S390_USER_STSI: 5408c2ecf20Sopenharmony_ci case KVM_CAP_S390_SKEYS: 5418c2ecf20Sopenharmony_ci case KVM_CAP_S390_IRQ_STATE: 5428c2ecf20Sopenharmony_ci case KVM_CAP_S390_USER_INSTR0: 5438c2ecf20Sopenharmony_ci case KVM_CAP_S390_CMMA_MIGRATION: 5448c2ecf20Sopenharmony_ci case KVM_CAP_S390_AIS: 5458c2ecf20Sopenharmony_ci case KVM_CAP_S390_AIS_MIGRATION: 5468c2ecf20Sopenharmony_ci case KVM_CAP_S390_VCPU_RESETS: 5478c2ecf20Sopenharmony_ci case KVM_CAP_SET_GUEST_DEBUG: 5488c2ecf20Sopenharmony_ci case KVM_CAP_S390_DIAG318: 5498c2ecf20Sopenharmony_ci r = 1; 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case KVM_CAP_S390_HPAGE_1M: 5528c2ecf20Sopenharmony_ci r = 0; 5538c2ecf20Sopenharmony_ci if (hpage && !kvm_is_ucontrol(kvm)) 5548c2ecf20Sopenharmony_ci r = 1; 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci case KVM_CAP_S390_MEM_OP: 5578c2ecf20Sopenharmony_ci r = MEM_OP_MAX_SIZE; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case KVM_CAP_NR_VCPUS: 5608c2ecf20Sopenharmony_ci case KVM_CAP_MAX_VCPUS: 5618c2ecf20Sopenharmony_ci case KVM_CAP_MAX_VCPU_ID: 5628c2ecf20Sopenharmony_ci r = KVM_S390_BSCA_CPU_SLOTS; 5638c2ecf20Sopenharmony_ci if (!kvm_s390_use_sca_entries()) 5648c2ecf20Sopenharmony_ci r = KVM_MAX_VCPUS; 5658c2ecf20Sopenharmony_ci else if (sclp.has_esca && sclp.has_64bscao) 5668c2ecf20Sopenharmony_ci r = KVM_S390_ESCA_CPU_SLOTS; 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci case KVM_CAP_S390_COW: 5698c2ecf20Sopenharmony_ci r = MACHINE_HAS_ESOP; 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci case KVM_CAP_S390_VECTOR_REGISTERS: 5728c2ecf20Sopenharmony_ci r = MACHINE_HAS_VX; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci case KVM_CAP_S390_RI: 5758c2ecf20Sopenharmony_ci r = test_facility(64); 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci case KVM_CAP_S390_GS: 5788c2ecf20Sopenharmony_ci r = test_facility(133); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci case KVM_CAP_S390_BPB: 5818c2ecf20Sopenharmony_ci r = test_facility(82); 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci case KVM_CAP_S390_PROTECTED: 5848c2ecf20Sopenharmony_ci r = is_prot_virt_host(); 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci default: 5878c2ecf20Sopenharmony_ci r = 0; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci return r; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_civoid kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci int i; 5958c2ecf20Sopenharmony_ci gfn_t cur_gfn, last_gfn; 5968c2ecf20Sopenharmony_ci unsigned long gaddr, vmaddr; 5978c2ecf20Sopenharmony_ci struct gmap *gmap = kvm->arch.gmap; 5988c2ecf20Sopenharmony_ci DECLARE_BITMAP(bitmap, _PAGE_ENTRIES); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Loop over all guest segments */ 6018c2ecf20Sopenharmony_ci cur_gfn = memslot->base_gfn; 6028c2ecf20Sopenharmony_ci last_gfn = memslot->base_gfn + memslot->npages; 6038c2ecf20Sopenharmony_ci for (; cur_gfn <= last_gfn; cur_gfn += _PAGE_ENTRIES) { 6048c2ecf20Sopenharmony_ci gaddr = gfn_to_gpa(cur_gfn); 6058c2ecf20Sopenharmony_ci vmaddr = gfn_to_hva_memslot(memslot, cur_gfn); 6068c2ecf20Sopenharmony_ci if (kvm_is_error_hva(vmaddr)) 6078c2ecf20Sopenharmony_ci continue; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci bitmap_zero(bitmap, _PAGE_ENTRIES); 6108c2ecf20Sopenharmony_ci gmap_sync_dirty_log_pmd(gmap, bitmap, gaddr, vmaddr); 6118c2ecf20Sopenharmony_ci for (i = 0; i < _PAGE_ENTRIES; i++) { 6128c2ecf20Sopenharmony_ci if (test_bit(i, bitmap)) 6138c2ecf20Sopenharmony_ci mark_page_dirty(kvm, cur_gfn + i); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) 6178c2ecf20Sopenharmony_ci return; 6188c2ecf20Sopenharmony_ci cond_resched(); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci/* Section: vm related */ 6238c2ecf20Sopenharmony_cistatic void sca_del_vcpu(struct kvm_vcpu *vcpu); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci/* 6268c2ecf20Sopenharmony_ci * Get (and clear) the dirty memory log for a memory slot. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ciint kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, 6298c2ecf20Sopenharmony_ci struct kvm_dirty_log *log) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci int r; 6328c2ecf20Sopenharmony_ci unsigned long n; 6338c2ecf20Sopenharmony_ci struct kvm_memory_slot *memslot; 6348c2ecf20Sopenharmony_ci int is_dirty; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (kvm_is_ucontrol(kvm)) 6378c2ecf20Sopenharmony_ci return -EINVAL; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci mutex_lock(&kvm->slots_lock); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci r = -EINVAL; 6428c2ecf20Sopenharmony_ci if (log->slot >= KVM_USER_MEM_SLOTS) 6438c2ecf20Sopenharmony_ci goto out; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci r = kvm_get_dirty_log(kvm, log, &is_dirty, &memslot); 6468c2ecf20Sopenharmony_ci if (r) 6478c2ecf20Sopenharmony_ci goto out; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Clear the dirty log */ 6508c2ecf20Sopenharmony_ci if (is_dirty) { 6518c2ecf20Sopenharmony_ci n = kvm_dirty_bitmap_bytes(memslot); 6528c2ecf20Sopenharmony_ci memset(memslot->dirty_bitmap, 0, n); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci r = 0; 6558c2ecf20Sopenharmony_ciout: 6568c2ecf20Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 6578c2ecf20Sopenharmony_ci return r; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void icpt_operexc_on_all_vcpus(struct kvm *kvm) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci unsigned int i; 6638c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 6668c2ecf20Sopenharmony_ci kvm_s390_sync_request(KVM_REQ_ICPT_OPEREXC, vcpu); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ciint kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci int r; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (cap->flags) 6758c2ecf20Sopenharmony_ci return -EINVAL; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci switch (cap->cap) { 6788c2ecf20Sopenharmony_ci case KVM_CAP_S390_IRQCHIP: 6798c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_IRQCHIP"); 6808c2ecf20Sopenharmony_ci kvm->arch.use_irqchip = 1; 6818c2ecf20Sopenharmony_ci r = 0; 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci case KVM_CAP_S390_USER_SIGP: 6848c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_SIGP"); 6858c2ecf20Sopenharmony_ci kvm->arch.user_sigp = 1; 6868c2ecf20Sopenharmony_ci r = 0; 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci case KVM_CAP_S390_VECTOR_REGISTERS: 6898c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 6908c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 6918c2ecf20Sopenharmony_ci r = -EBUSY; 6928c2ecf20Sopenharmony_ci } else if (MACHINE_HAS_VX) { 6938c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 129); 6948c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 129); 6958c2ecf20Sopenharmony_ci if (test_facility(134)) { 6968c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 134); 6978c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 134); 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci if (test_facility(135)) { 7008c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 135); 7018c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 135); 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci if (test_facility(148)) { 7048c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 148); 7058c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 148); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci if (test_facility(152)) { 7088c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 152); 7098c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 152); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci r = 0; 7128c2ecf20Sopenharmony_ci } else 7138c2ecf20Sopenharmony_ci r = -EINVAL; 7148c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 7158c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s", 7168c2ecf20Sopenharmony_ci r ? "(not available)" : "(success)"); 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci case KVM_CAP_S390_RI: 7198c2ecf20Sopenharmony_ci r = -EINVAL; 7208c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 7218c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 7228c2ecf20Sopenharmony_ci r = -EBUSY; 7238c2ecf20Sopenharmony_ci } else if (test_facility(64)) { 7248c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 64); 7258c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 64); 7268c2ecf20Sopenharmony_ci r = 0; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 7298c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s", 7308c2ecf20Sopenharmony_ci r ? "(not available)" : "(success)"); 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci case KVM_CAP_S390_AIS: 7338c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 7348c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 7358c2ecf20Sopenharmony_ci r = -EBUSY; 7368c2ecf20Sopenharmony_ci } else { 7378c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 72); 7388c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 72); 7398c2ecf20Sopenharmony_ci r = 0; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 7428c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "ENABLE: AIS %s", 7438c2ecf20Sopenharmony_ci r ? "(not available)" : "(success)"); 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci case KVM_CAP_S390_GS: 7468c2ecf20Sopenharmony_ci r = -EINVAL; 7478c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 7488c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 7498c2ecf20Sopenharmony_ci r = -EBUSY; 7508c2ecf20Sopenharmony_ci } else if (test_facility(133)) { 7518c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 133); 7528c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 133); 7538c2ecf20Sopenharmony_ci r = 0; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 7568c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "ENABLE: CAP_S390_GS %s", 7578c2ecf20Sopenharmony_ci r ? "(not available)" : "(success)"); 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci case KVM_CAP_S390_HPAGE_1M: 7608c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 7618c2ecf20Sopenharmony_ci if (kvm->created_vcpus) 7628c2ecf20Sopenharmony_ci r = -EBUSY; 7638c2ecf20Sopenharmony_ci else if (!hpage || kvm->arch.use_cmma || kvm_is_ucontrol(kvm)) 7648c2ecf20Sopenharmony_ci r = -EINVAL; 7658c2ecf20Sopenharmony_ci else { 7668c2ecf20Sopenharmony_ci r = 0; 7678c2ecf20Sopenharmony_ci mmap_write_lock(kvm->mm); 7688c2ecf20Sopenharmony_ci kvm->mm->context.allow_gmap_hpage_1m = 1; 7698c2ecf20Sopenharmony_ci mmap_write_unlock(kvm->mm); 7708c2ecf20Sopenharmony_ci /* 7718c2ecf20Sopenharmony_ci * We might have to create fake 4k page 7728c2ecf20Sopenharmony_ci * tables. To avoid that the hardware works on 7738c2ecf20Sopenharmony_ci * stale PGSTEs, we emulate these instructions. 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci kvm->arch.use_skf = 0; 7768c2ecf20Sopenharmony_ci kvm->arch.use_pfmfi = 0; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 7798c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "ENABLE: CAP_S390_HPAGE %s", 7808c2ecf20Sopenharmony_ci r ? "(not available)" : "(success)"); 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case KVM_CAP_S390_USER_STSI: 7838c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI"); 7848c2ecf20Sopenharmony_ci kvm->arch.user_stsi = 1; 7858c2ecf20Sopenharmony_ci r = 0; 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci case KVM_CAP_S390_USER_INSTR0: 7888c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_INSTR0"); 7898c2ecf20Sopenharmony_ci kvm->arch.user_instr0 = 1; 7908c2ecf20Sopenharmony_ci icpt_operexc_on_all_vcpus(kvm); 7918c2ecf20Sopenharmony_ci r = 0; 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci default: 7948c2ecf20Sopenharmony_ci r = -EINVAL; 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci return r; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic int kvm_s390_get_mem_control(struct kvm *kvm, struct kvm_device_attr *attr) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci int ret; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci switch (attr->attr) { 8058c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_LIMIT_SIZE: 8068c2ecf20Sopenharmony_ci ret = 0; 8078c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "QUERY: max guest memory: %lu bytes", 8088c2ecf20Sopenharmony_ci kvm->arch.mem_limit); 8098c2ecf20Sopenharmony_ci if (put_user(kvm->arch.mem_limit, (u64 __user *)attr->addr)) 8108c2ecf20Sopenharmony_ci ret = -EFAULT; 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci default: 8138c2ecf20Sopenharmony_ci ret = -ENXIO; 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci return ret; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *attr) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci int ret; 8228c2ecf20Sopenharmony_ci unsigned int idx; 8238c2ecf20Sopenharmony_ci switch (attr->attr) { 8248c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_ENABLE_CMMA: 8258c2ecf20Sopenharmony_ci ret = -ENXIO; 8268c2ecf20Sopenharmony_ci if (!sclp.has_cmma) 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: CMMA support"); 8308c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 8318c2ecf20Sopenharmony_ci if (kvm->created_vcpus) 8328c2ecf20Sopenharmony_ci ret = -EBUSY; 8338c2ecf20Sopenharmony_ci else if (kvm->mm->context.allow_gmap_hpage_1m) 8348c2ecf20Sopenharmony_ci ret = -EINVAL; 8358c2ecf20Sopenharmony_ci else { 8368c2ecf20Sopenharmony_ci kvm->arch.use_cmma = 1; 8378c2ecf20Sopenharmony_ci /* Not compatible with cmma. */ 8388c2ecf20Sopenharmony_ci kvm->arch.use_pfmfi = 0; 8398c2ecf20Sopenharmony_ci ret = 0; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 8428c2ecf20Sopenharmony_ci break; 8438c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_CLR_CMMA: 8448c2ecf20Sopenharmony_ci ret = -ENXIO; 8458c2ecf20Sopenharmony_ci if (!sclp.has_cmma) 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci ret = -EINVAL; 8488c2ecf20Sopenharmony_ci if (!kvm->arch.use_cmma) 8498c2ecf20Sopenharmony_ci break; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "RESET: CMMA states"); 8528c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 8538c2ecf20Sopenharmony_ci idx = srcu_read_lock(&kvm->srcu); 8548c2ecf20Sopenharmony_ci s390_reset_cmma(kvm->arch.gmap->mm); 8558c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->srcu, idx); 8568c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 8578c2ecf20Sopenharmony_ci ret = 0; 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_LIMIT_SIZE: { 8608c2ecf20Sopenharmony_ci unsigned long new_limit; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (kvm_is_ucontrol(kvm)) 8638c2ecf20Sopenharmony_ci return -EINVAL; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (get_user(new_limit, (u64 __user *)attr->addr)) 8668c2ecf20Sopenharmony_ci return -EFAULT; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT && 8698c2ecf20Sopenharmony_ci new_limit > kvm->arch.mem_limit) 8708c2ecf20Sopenharmony_ci return -E2BIG; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (!new_limit) 8738c2ecf20Sopenharmony_ci return -EINVAL; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* gmap_create takes last usable address */ 8768c2ecf20Sopenharmony_ci if (new_limit != KVM_S390_NO_MEM_LIMIT) 8778c2ecf20Sopenharmony_ci new_limit -= 1; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci ret = -EBUSY; 8808c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 8818c2ecf20Sopenharmony_ci if (!kvm->created_vcpus) { 8828c2ecf20Sopenharmony_ci /* gmap_create will round the limit up */ 8838c2ecf20Sopenharmony_ci struct gmap *new = gmap_create(current->mm, new_limit); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!new) { 8868c2ecf20Sopenharmony_ci ret = -ENOMEM; 8878c2ecf20Sopenharmony_ci } else { 8888c2ecf20Sopenharmony_ci gmap_remove(kvm->arch.gmap); 8898c2ecf20Sopenharmony_ci new->private = kvm; 8908c2ecf20Sopenharmony_ci kvm->arch.gmap = new; 8918c2ecf20Sopenharmony_ci ret = 0; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 8958c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit); 8968c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "New guest asce: 0x%pK", 8978c2ecf20Sopenharmony_ci (void *) kvm->arch.gmap->asce); 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci default: 9018c2ecf20Sopenharmony_ci ret = -ENXIO; 9028c2ecf20Sopenharmony_ci break; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci return ret; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_civoid kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 9128c2ecf20Sopenharmony_ci int i; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci kvm_s390_vcpu_block_all(kvm); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 9178c2ecf20Sopenharmony_ci kvm_s390_vcpu_crypto_setup(vcpu); 9188c2ecf20Sopenharmony_ci /* recreate the shadow crycb by leaving the VSIE handler */ 9198c2ecf20Sopenharmony_ci kvm_s390_sync_request(KVM_REQ_VSIE_RESTART, vcpu); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci kvm_s390_vcpu_unblock_all(kvm); 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 9288c2ecf20Sopenharmony_ci switch (attr->attr) { 9298c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_ENABLE_AES_KW: 9308c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 76)) { 9318c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9328c2ecf20Sopenharmony_ci return -EINVAL; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci get_random_bytes( 9358c2ecf20Sopenharmony_ci kvm->arch.crypto.crycb->aes_wrapping_key_mask, 9368c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); 9378c2ecf20Sopenharmony_ci kvm->arch.crypto.aes_kw = 1; 9388c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: AES keywrapping support"); 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW: 9418c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 76)) { 9428c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9438c2ecf20Sopenharmony_ci return -EINVAL; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci get_random_bytes( 9468c2ecf20Sopenharmony_ci kvm->arch.crypto.crycb->dea_wrapping_key_mask, 9478c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); 9488c2ecf20Sopenharmony_ci kvm->arch.crypto.dea_kw = 1; 9498c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "ENABLE: DEA keywrapping support"); 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_DISABLE_AES_KW: 9528c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 76)) { 9538c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9548c2ecf20Sopenharmony_ci return -EINVAL; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci kvm->arch.crypto.aes_kw = 0; 9578c2ecf20Sopenharmony_ci memset(kvm->arch.crypto.crycb->aes_wrapping_key_mask, 0, 9588c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); 9598c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "DISABLE: AES keywrapping support"); 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW: 9628c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 76)) { 9638c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9648c2ecf20Sopenharmony_ci return -EINVAL; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci kvm->arch.crypto.dea_kw = 0; 9678c2ecf20Sopenharmony_ci memset(kvm->arch.crypto.crycb->dea_wrapping_key_mask, 0, 9688c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); 9698c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "DISABLE: DEA keywrapping support"); 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_ENABLE_APIE: 9728c2ecf20Sopenharmony_ci if (!ap_instructions_available()) { 9738c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9748c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci kvm->arch.crypto.apie = 1; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_DISABLE_APIE: 9798c2ecf20Sopenharmony_ci if (!ap_instructions_available()) { 9808c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9818c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci kvm->arch.crypto.apie = 0; 9848c2ecf20Sopenharmony_ci break; 9858c2ecf20Sopenharmony_ci default: 9868c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9878c2ecf20Sopenharmony_ci return -ENXIO; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci kvm_s390_vcpu_crypto_reset_all(kvm); 9918c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 9928c2ecf20Sopenharmony_ci return 0; 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci int cx; 9988c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci kvm_for_each_vcpu(cx, vcpu, kvm) 10018c2ecf20Sopenharmony_ci kvm_s390_sync_request(req, vcpu); 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/* 10058c2ecf20Sopenharmony_ci * Must be called with kvm->srcu held to avoid races on memslots, and with 10068c2ecf20Sopenharmony_ci * kvm->slots_lock to avoid races with ourselves and kvm_s390_vm_stop_migration. 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_cistatic int kvm_s390_vm_start_migration(struct kvm *kvm) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci struct kvm_memory_slot *ms; 10118c2ecf20Sopenharmony_ci struct kvm_memslots *slots; 10128c2ecf20Sopenharmony_ci unsigned long ram_pages = 0; 10138c2ecf20Sopenharmony_ci int slotnr; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci /* migration mode already enabled */ 10168c2ecf20Sopenharmony_ci if (kvm->arch.migration_mode) 10178c2ecf20Sopenharmony_ci return 0; 10188c2ecf20Sopenharmony_ci slots = kvm_memslots(kvm); 10198c2ecf20Sopenharmony_ci if (!slots || !slots->used_slots) 10208c2ecf20Sopenharmony_ci return -EINVAL; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (!kvm->arch.use_cmma) { 10238c2ecf20Sopenharmony_ci kvm->arch.migration_mode = 1; 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci /* mark all the pages in active slots as dirty */ 10278c2ecf20Sopenharmony_ci for (slotnr = 0; slotnr < slots->used_slots; slotnr++) { 10288c2ecf20Sopenharmony_ci ms = slots->memslots + slotnr; 10298c2ecf20Sopenharmony_ci if (!ms->dirty_bitmap) 10308c2ecf20Sopenharmony_ci return -EINVAL; 10318c2ecf20Sopenharmony_ci /* 10328c2ecf20Sopenharmony_ci * The second half of the bitmap is only used on x86, 10338c2ecf20Sopenharmony_ci * and would be wasted otherwise, so we put it to good 10348c2ecf20Sopenharmony_ci * use here to keep track of the state of the storage 10358c2ecf20Sopenharmony_ci * attributes. 10368c2ecf20Sopenharmony_ci */ 10378c2ecf20Sopenharmony_ci memset(kvm_second_dirty_bitmap(ms), 0xff, kvm_dirty_bitmap_bytes(ms)); 10388c2ecf20Sopenharmony_ci ram_pages += ms->npages; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci atomic64_set(&kvm->arch.cmma_dirty_pages, ram_pages); 10418c2ecf20Sopenharmony_ci kvm->arch.migration_mode = 1; 10428c2ecf20Sopenharmony_ci kvm_s390_sync_request_broadcast(kvm, KVM_REQ_START_MIGRATION); 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci/* 10478c2ecf20Sopenharmony_ci * Must be called with kvm->slots_lock to avoid races with ourselves and 10488c2ecf20Sopenharmony_ci * kvm_s390_vm_start_migration. 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_cistatic int kvm_s390_vm_stop_migration(struct kvm *kvm) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci /* migration mode already disabled */ 10538c2ecf20Sopenharmony_ci if (!kvm->arch.migration_mode) 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci kvm->arch.migration_mode = 0; 10568c2ecf20Sopenharmony_ci if (kvm->arch.use_cmma) 10578c2ecf20Sopenharmony_ci kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION); 10588c2ecf20Sopenharmony_ci return 0; 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic int kvm_s390_vm_set_migration(struct kvm *kvm, 10628c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci int res = -ENXIO; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci mutex_lock(&kvm->slots_lock); 10678c2ecf20Sopenharmony_ci switch (attr->attr) { 10688c2ecf20Sopenharmony_ci case KVM_S390_VM_MIGRATION_START: 10698c2ecf20Sopenharmony_ci res = kvm_s390_vm_start_migration(kvm); 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci case KVM_S390_VM_MIGRATION_STOP: 10728c2ecf20Sopenharmony_ci res = kvm_s390_vm_stop_migration(kvm); 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci default: 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci return res; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic int kvm_s390_vm_get_migration(struct kvm *kvm, 10838c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci u64 mig = kvm->arch.migration_mode; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (attr->attr != KVM_S390_VM_MIGRATION_STATUS) 10888c2ecf20Sopenharmony_ci return -ENXIO; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, &mig, sizeof(mig))) 10918c2ecf20Sopenharmony_ci return -EFAULT; 10928c2ecf20Sopenharmony_ci return 0; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct kvm_s390_vm_tod_clock gtod; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod))) 11028c2ecf20Sopenharmony_ci return -EFAULT; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx) 11058c2ecf20Sopenharmony_ci return -EINVAL; 11068c2ecf20Sopenharmony_ci __kvm_s390_set_tod_clock(kvm, >od); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx", 11098c2ecf20Sopenharmony_ci gtod.epoch_idx, gtod.tod); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci u8 gtod_high; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (copy_from_user(>od_high, (void __user *)attr->addr, 11198c2ecf20Sopenharmony_ci sizeof(gtod_high))) 11208c2ecf20Sopenharmony_ci return -EFAULT; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (gtod_high != 0) 11238c2ecf20Sopenharmony_ci return -EINVAL; 11248c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x", gtod_high); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci return 0; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct kvm_s390_vm_tod_clock gtod = { 0 }; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (copy_from_user(>od.tod, (void __user *)attr->addr, 11348c2ecf20Sopenharmony_ci sizeof(gtod.tod))) 11358c2ecf20Sopenharmony_ci return -EFAULT; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci __kvm_s390_set_tod_clock(kvm, >od); 11388c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod); 11398c2ecf20Sopenharmony_ci return 0; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci int ret; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (attr->flags) 11478c2ecf20Sopenharmony_ci return -EINVAL; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 11508c2ecf20Sopenharmony_ci /* 11518c2ecf20Sopenharmony_ci * For protected guests, the TOD is managed by the ultravisor, so trying 11528c2ecf20Sopenharmony_ci * to change it will never bring the expected results. 11538c2ecf20Sopenharmony_ci */ 11548c2ecf20Sopenharmony_ci if (kvm_s390_pv_is_protected(kvm)) { 11558c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 11568c2ecf20Sopenharmony_ci goto out_unlock; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci switch (attr->attr) { 11608c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_EXT: 11618c2ecf20Sopenharmony_ci ret = kvm_s390_set_tod_ext(kvm, attr); 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_HIGH: 11648c2ecf20Sopenharmony_ci ret = kvm_s390_set_tod_high(kvm, attr); 11658c2ecf20Sopenharmony_ci break; 11668c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_LOW: 11678c2ecf20Sopenharmony_ci ret = kvm_s390_set_tod_low(kvm, attr); 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci default: 11708c2ecf20Sopenharmony_ci ret = -ENXIO; 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ciout_unlock: 11758c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 11768c2ecf20Sopenharmony_ci return ret; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic void kvm_s390_get_tod_clock(struct kvm *kvm, 11808c2ecf20Sopenharmony_ci struct kvm_s390_vm_tod_clock *gtod) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci struct kvm_s390_tod_clock_ext htod; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci preempt_disable(); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci get_tod_clock_ext((char *)&htod); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci gtod->tod = htod.tod + kvm->arch.epoch; 11898c2ecf20Sopenharmony_ci gtod->epoch_idx = 0; 11908c2ecf20Sopenharmony_ci if (test_kvm_facility(kvm, 139)) { 11918c2ecf20Sopenharmony_ci gtod->epoch_idx = htod.epoch_idx + kvm->arch.epdx; 11928c2ecf20Sopenharmony_ci if (gtod->tod < htod.tod) 11938c2ecf20Sopenharmony_ci gtod->epoch_idx += 1; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci preempt_enable(); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int kvm_s390_get_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci struct kvm_s390_vm_tod_clock gtod; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci memset(>od, 0, sizeof(gtod)); 12048c2ecf20Sopenharmony_ci kvm_s390_get_tod_clock(kvm, >od); 12058c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod))) 12068c2ecf20Sopenharmony_ci return -EFAULT; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "QUERY: TOD extension: 0x%x, TOD base: 0x%llx", 12098c2ecf20Sopenharmony_ci gtod.epoch_idx, gtod.tod); 12108c2ecf20Sopenharmony_ci return 0; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci u8 gtod_high = 0; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, >od_high, 12188c2ecf20Sopenharmony_ci sizeof(gtod_high))) 12198c2ecf20Sopenharmony_ci return -EFAULT; 12208c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "QUERY: TOD extension: 0x%x", gtod_high); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci return 0; 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci u64 gtod; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci gtod = kvm_s390_get_tod_clock_fast(kvm); 12308c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod))) 12318c2ecf20Sopenharmony_ci return -EFAULT; 12328c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "QUERY: TOD base: 0x%llx", gtod); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci return 0; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci int ret; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (attr->flags) 12428c2ecf20Sopenharmony_ci return -EINVAL; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci switch (attr->attr) { 12458c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_EXT: 12468c2ecf20Sopenharmony_ci ret = kvm_s390_get_tod_ext(kvm, attr); 12478c2ecf20Sopenharmony_ci break; 12488c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_HIGH: 12498c2ecf20Sopenharmony_ci ret = kvm_s390_get_tod_high(kvm, attr); 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_LOW: 12528c2ecf20Sopenharmony_ci ret = kvm_s390_get_tod_low(kvm, attr); 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci default: 12558c2ecf20Sopenharmony_ci ret = -ENXIO; 12568c2ecf20Sopenharmony_ci break; 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci return ret; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct kvm_s390_vm_cpu_processor *proc; 12648c2ecf20Sopenharmony_ci u16 lowest_ibc, unblocked_ibc; 12658c2ecf20Sopenharmony_ci int ret = 0; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 12688c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 12698c2ecf20Sopenharmony_ci ret = -EBUSY; 12708c2ecf20Sopenharmony_ci goto out; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci proc = kzalloc(sizeof(*proc), GFP_KERNEL); 12738c2ecf20Sopenharmony_ci if (!proc) { 12748c2ecf20Sopenharmony_ci ret = -ENOMEM; 12758c2ecf20Sopenharmony_ci goto out; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci if (!copy_from_user(proc, (void __user *)attr->addr, 12788c2ecf20Sopenharmony_ci sizeof(*proc))) { 12798c2ecf20Sopenharmony_ci kvm->arch.model.cpuid = proc->cpuid; 12808c2ecf20Sopenharmony_ci lowest_ibc = sclp.ibc >> 16 & 0xfff; 12818c2ecf20Sopenharmony_ci unblocked_ibc = sclp.ibc & 0xfff; 12828c2ecf20Sopenharmony_ci if (lowest_ibc && proc->ibc) { 12838c2ecf20Sopenharmony_ci if (proc->ibc > unblocked_ibc) 12848c2ecf20Sopenharmony_ci kvm->arch.model.ibc = unblocked_ibc; 12858c2ecf20Sopenharmony_ci else if (proc->ibc < lowest_ibc) 12868c2ecf20Sopenharmony_ci kvm->arch.model.ibc = lowest_ibc; 12878c2ecf20Sopenharmony_ci else 12888c2ecf20Sopenharmony_ci kvm->arch.model.ibc = proc->ibc; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci memcpy(kvm->arch.model.fac_list, proc->fac_list, 12918c2ecf20Sopenharmony_ci S390_ARCH_FAC_LIST_SIZE_BYTE); 12928c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest ibc: 0x%4.4x, guest cpuid: 0x%16.16llx", 12938c2ecf20Sopenharmony_ci kvm->arch.model.ibc, 12948c2ecf20Sopenharmony_ci kvm->arch.model.cpuid); 12958c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest faclist: 0x%16.16llx.%16.16llx.%16.16llx", 12968c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[0], 12978c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[1], 12988c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[2]); 12998c2ecf20Sopenharmony_ci } else 13008c2ecf20Sopenharmony_ci ret = -EFAULT; 13018c2ecf20Sopenharmony_ci kfree(proc); 13028c2ecf20Sopenharmony_ciout: 13038c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 13048c2ecf20Sopenharmony_ci return ret; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic int kvm_s390_set_processor_feat(struct kvm *kvm, 13088c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct kvm_s390_vm_cpu_feat data; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (copy_from_user(&data, (void __user *)attr->addr, sizeof(data))) 13138c2ecf20Sopenharmony_ci return -EFAULT; 13148c2ecf20Sopenharmony_ci if (!bitmap_subset((unsigned long *) data.feat, 13158c2ecf20Sopenharmony_ci kvm_s390_available_cpu_feat, 13168c2ecf20Sopenharmony_ci KVM_S390_VM_CPU_FEAT_NR_BITS)) 13178c2ecf20Sopenharmony_ci return -EINVAL; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 13208c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 13218c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 13228c2ecf20Sopenharmony_ci return -EBUSY; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci bitmap_copy(kvm->arch.cpu_feat, (unsigned long *) data.feat, 13258c2ecf20Sopenharmony_ci KVM_S390_VM_CPU_FEAT_NR_BITS); 13268c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 13278c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx", 13288c2ecf20Sopenharmony_ci data.feat[0], 13298c2ecf20Sopenharmony_ci data.feat[1], 13308c2ecf20Sopenharmony_ci data.feat[2]); 13318c2ecf20Sopenharmony_ci return 0; 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic int kvm_s390_set_processor_subfunc(struct kvm *kvm, 13358c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 13368c2ecf20Sopenharmony_ci{ 13378c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 13388c2ecf20Sopenharmony_ci if (kvm->created_vcpus) { 13398c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 13408c2ecf20Sopenharmony_ci return -EBUSY; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (copy_from_user(&kvm->arch.model.subfuncs, (void __user *)attr->addr, 13448c2ecf20Sopenharmony_ci sizeof(struct kvm_s390_vm_cpu_subfunc))) { 13458c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 13468c2ecf20Sopenharmony_ci return -EFAULT; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest PLO subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 13518c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[0], 13528c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[1], 13538c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[2], 13548c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[3]); 13558c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest PTFF subfunc 0x%16.16lx.%16.16lx", 13568c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[0], 13578c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[1]); 13588c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KMAC subfunc 0x%16.16lx.%16.16lx", 13598c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[0], 13608c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[1]); 13618c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KMC subfunc 0x%16.16lx.%16.16lx", 13628c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[0], 13638c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[1]); 13648c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KM subfunc 0x%16.16lx.%16.16lx", 13658c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.km)[0], 13668c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.km)[1]); 13678c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KIMD subfunc 0x%16.16lx.%16.16lx", 13688c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[0], 13698c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[1]); 13708c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KLMD subfunc 0x%16.16lx.%16.16lx", 13718c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[0], 13728c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[1]); 13738c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest PCKMO subfunc 0x%16.16lx.%16.16lx", 13748c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[0], 13758c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[1]); 13768c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KMCTR subfunc 0x%16.16lx.%16.16lx", 13778c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[0], 13788c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[1]); 13798c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KMF subfunc 0x%16.16lx.%16.16lx", 13808c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[0], 13818c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[1]); 13828c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KMO subfunc 0x%16.16lx.%16.16lx", 13838c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[0], 13848c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[1]); 13858c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest PCC subfunc 0x%16.16lx.%16.16lx", 13868c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[0], 13878c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[1]); 13888c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest PPNO subfunc 0x%16.16lx.%16.16lx", 13898c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[0], 13908c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[1]); 13918c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KMA subfunc 0x%16.16lx.%16.16lx", 13928c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kma)[0], 13938c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kma)[1]); 13948c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest KDSA subfunc 0x%16.16lx.%16.16lx", 13958c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[0], 13968c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[1]); 13978c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest SORTL subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 13988c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[0], 13998c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[1], 14008c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[2], 14018c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[3]); 14028c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET: guest DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 14038c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[0], 14048c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1], 14058c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2], 14068c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci return 0; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_cistatic int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci int ret = -ENXIO; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci switch (attr->attr) { 14168c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR: 14178c2ecf20Sopenharmony_ci ret = kvm_s390_set_processor(kvm, attr); 14188c2ecf20Sopenharmony_ci break; 14198c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR_FEAT: 14208c2ecf20Sopenharmony_ci ret = kvm_s390_set_processor_feat(kvm, attr); 14218c2ecf20Sopenharmony_ci break; 14228c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC: 14238c2ecf20Sopenharmony_ci ret = kvm_s390_set_processor_subfunc(kvm, attr); 14248c2ecf20Sopenharmony_ci break; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci return ret; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic int kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci struct kvm_s390_vm_cpu_processor *proc; 14328c2ecf20Sopenharmony_ci int ret = 0; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci proc = kzalloc(sizeof(*proc), GFP_KERNEL); 14358c2ecf20Sopenharmony_ci if (!proc) { 14368c2ecf20Sopenharmony_ci ret = -ENOMEM; 14378c2ecf20Sopenharmony_ci goto out; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci proc->cpuid = kvm->arch.model.cpuid; 14408c2ecf20Sopenharmony_ci proc->ibc = kvm->arch.model.ibc; 14418c2ecf20Sopenharmony_ci memcpy(&proc->fac_list, kvm->arch.model.fac_list, 14428c2ecf20Sopenharmony_ci S390_ARCH_FAC_LIST_SIZE_BYTE); 14438c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest ibc: 0x%4.4x, guest cpuid: 0x%16.16llx", 14448c2ecf20Sopenharmony_ci kvm->arch.model.ibc, 14458c2ecf20Sopenharmony_ci kvm->arch.model.cpuid); 14468c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest faclist: 0x%16.16llx.%16.16llx.%16.16llx", 14478c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[0], 14488c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[1], 14498c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[2]); 14508c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, proc, sizeof(*proc))) 14518c2ecf20Sopenharmony_ci ret = -EFAULT; 14528c2ecf20Sopenharmony_ci kfree(proc); 14538c2ecf20Sopenharmony_ciout: 14548c2ecf20Sopenharmony_ci return ret; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct kvm_s390_vm_cpu_machine *mach; 14608c2ecf20Sopenharmony_ci int ret = 0; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci mach = kzalloc(sizeof(*mach), GFP_KERNEL); 14638c2ecf20Sopenharmony_ci if (!mach) { 14648c2ecf20Sopenharmony_ci ret = -ENOMEM; 14658c2ecf20Sopenharmony_ci goto out; 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci get_cpu_id((struct cpuid *) &mach->cpuid); 14688c2ecf20Sopenharmony_ci mach->ibc = sclp.ibc; 14698c2ecf20Sopenharmony_ci memcpy(&mach->fac_mask, kvm->arch.model.fac_mask, 14708c2ecf20Sopenharmony_ci S390_ARCH_FAC_LIST_SIZE_BYTE); 14718c2ecf20Sopenharmony_ci memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list, 14728c2ecf20Sopenharmony_ci sizeof(S390_lowcore.stfle_fac_list)); 14738c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host ibc: 0x%4.4x, host cpuid: 0x%16.16llx", 14748c2ecf20Sopenharmony_ci kvm->arch.model.ibc, 14758c2ecf20Sopenharmony_ci kvm->arch.model.cpuid); 14768c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host facmask: 0x%16.16llx.%16.16llx.%16.16llx", 14778c2ecf20Sopenharmony_ci mach->fac_mask[0], 14788c2ecf20Sopenharmony_ci mach->fac_mask[1], 14798c2ecf20Sopenharmony_ci mach->fac_mask[2]); 14808c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host faclist: 0x%16.16llx.%16.16llx.%16.16llx", 14818c2ecf20Sopenharmony_ci mach->fac_list[0], 14828c2ecf20Sopenharmony_ci mach->fac_list[1], 14838c2ecf20Sopenharmony_ci mach->fac_list[2]); 14848c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, mach, sizeof(*mach))) 14858c2ecf20Sopenharmony_ci ret = -EFAULT; 14868c2ecf20Sopenharmony_ci kfree(mach); 14878c2ecf20Sopenharmony_ciout: 14888c2ecf20Sopenharmony_ci return ret; 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic int kvm_s390_get_processor_feat(struct kvm *kvm, 14928c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct kvm_s390_vm_cpu_feat data; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci bitmap_copy((unsigned long *) data.feat, kvm->arch.cpu_feat, 14978c2ecf20Sopenharmony_ci KVM_S390_VM_CPU_FEAT_NR_BITS); 14988c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, &data, sizeof(data))) 14998c2ecf20Sopenharmony_ci return -EFAULT; 15008c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx", 15018c2ecf20Sopenharmony_ci data.feat[0], 15028c2ecf20Sopenharmony_ci data.feat[1], 15038c2ecf20Sopenharmony_ci data.feat[2]); 15048c2ecf20Sopenharmony_ci return 0; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic int kvm_s390_get_machine_feat(struct kvm *kvm, 15088c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci struct kvm_s390_vm_cpu_feat data; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci bitmap_copy((unsigned long *) data.feat, 15138c2ecf20Sopenharmony_ci kvm_s390_available_cpu_feat, 15148c2ecf20Sopenharmony_ci KVM_S390_VM_CPU_FEAT_NR_BITS); 15158c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, &data, sizeof(data))) 15168c2ecf20Sopenharmony_ci return -EFAULT; 15178c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx", 15188c2ecf20Sopenharmony_ci data.feat[0], 15198c2ecf20Sopenharmony_ci data.feat[1], 15208c2ecf20Sopenharmony_ci data.feat[2]); 15218c2ecf20Sopenharmony_ci return 0; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic int kvm_s390_get_processor_subfunc(struct kvm *kvm, 15258c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, &kvm->arch.model.subfuncs, 15288c2ecf20Sopenharmony_ci sizeof(struct kvm_s390_vm_cpu_subfunc))) 15298c2ecf20Sopenharmony_ci return -EFAULT; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest PLO subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 15328c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[0], 15338c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[1], 15348c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[2], 15358c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.plo)[3]); 15368c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest PTFF subfunc 0x%16.16lx.%16.16lx", 15378c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[0], 15388c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[1]); 15398c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KMAC subfunc 0x%16.16lx.%16.16lx", 15408c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[0], 15418c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[1]); 15428c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KMC subfunc 0x%16.16lx.%16.16lx", 15438c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[0], 15448c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[1]); 15458c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KM subfunc 0x%16.16lx.%16.16lx", 15468c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.km)[0], 15478c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.km)[1]); 15488c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KIMD subfunc 0x%16.16lx.%16.16lx", 15498c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[0], 15508c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[1]); 15518c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KLMD subfunc 0x%16.16lx.%16.16lx", 15528c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[0], 15538c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[1]); 15548c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest PCKMO subfunc 0x%16.16lx.%16.16lx", 15558c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[0], 15568c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[1]); 15578c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KMCTR subfunc 0x%16.16lx.%16.16lx", 15588c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[0], 15598c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[1]); 15608c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KMF subfunc 0x%16.16lx.%16.16lx", 15618c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[0], 15628c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[1]); 15638c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KMO subfunc 0x%16.16lx.%16.16lx", 15648c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[0], 15658c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[1]); 15668c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest PCC subfunc 0x%16.16lx.%16.16lx", 15678c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[0], 15688c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[1]); 15698c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest PPNO subfunc 0x%16.16lx.%16.16lx", 15708c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[0], 15718c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[1]); 15728c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KMA subfunc 0x%16.16lx.%16.16lx", 15738c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kma)[0], 15748c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kma)[1]); 15758c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest KDSA subfunc 0x%16.16lx.%16.16lx", 15768c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[0], 15778c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[1]); 15788c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest SORTL subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 15798c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[0], 15808c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[1], 15818c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[2], 15828c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[3]); 15838c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: guest DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 15848c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[0], 15858c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1], 15868c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2], 15878c2ecf20Sopenharmony_ci ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci return 0; 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_cistatic int kvm_s390_get_machine_subfunc(struct kvm *kvm, 15938c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)attr->addr, &kvm_s390_available_subfunc, 15968c2ecf20Sopenharmony_ci sizeof(struct kvm_s390_vm_cpu_subfunc))) 15978c2ecf20Sopenharmony_ci return -EFAULT; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host PLO subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 16008c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.plo)[0], 16018c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.plo)[1], 16028c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.plo)[2], 16038c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.plo)[3]); 16048c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host PTFF subfunc 0x%16.16lx.%16.16lx", 16058c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.ptff)[0], 16068c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.ptff)[1]); 16078c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KMAC subfunc 0x%16.16lx.%16.16lx", 16088c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmac)[0], 16098c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmac)[1]); 16108c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KMC subfunc 0x%16.16lx.%16.16lx", 16118c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmc)[0], 16128c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmc)[1]); 16138c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KM subfunc 0x%16.16lx.%16.16lx", 16148c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.km)[0], 16158c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.km)[1]); 16168c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KIMD subfunc 0x%16.16lx.%16.16lx", 16178c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kimd)[0], 16188c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kimd)[1]); 16198c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KLMD subfunc 0x%16.16lx.%16.16lx", 16208c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.klmd)[0], 16218c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.klmd)[1]); 16228c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host PCKMO subfunc 0x%16.16lx.%16.16lx", 16238c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.pckmo)[0], 16248c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.pckmo)[1]); 16258c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KMCTR subfunc 0x%16.16lx.%16.16lx", 16268c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmctr)[0], 16278c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmctr)[1]); 16288c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KMF subfunc 0x%16.16lx.%16.16lx", 16298c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmf)[0], 16308c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmf)[1]); 16318c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KMO subfunc 0x%16.16lx.%16.16lx", 16328c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmo)[0], 16338c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kmo)[1]); 16348c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host PCC subfunc 0x%16.16lx.%16.16lx", 16358c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.pcc)[0], 16368c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.pcc)[1]); 16378c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host PPNO subfunc 0x%16.16lx.%16.16lx", 16388c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.ppno)[0], 16398c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.ppno)[1]); 16408c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KMA subfunc 0x%16.16lx.%16.16lx", 16418c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kma)[0], 16428c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kma)[1]); 16438c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host KDSA subfunc 0x%16.16lx.%16.16lx", 16448c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kdsa)[0], 16458c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.kdsa)[1]); 16468c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host SORTL subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 16478c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.sortl)[0], 16488c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.sortl)[1], 16498c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.sortl)[2], 16508c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.sortl)[3]); 16518c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "GET: host DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx", 16528c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[0], 16538c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[1], 16548c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[2], 16558c2ecf20Sopenharmony_ci ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[3]); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci return 0; 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_cistatic int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci int ret = -ENXIO; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci switch (attr->attr) { 16658c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR: 16668c2ecf20Sopenharmony_ci ret = kvm_s390_get_processor(kvm, attr); 16678c2ecf20Sopenharmony_ci break; 16688c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MACHINE: 16698c2ecf20Sopenharmony_ci ret = kvm_s390_get_machine(kvm, attr); 16708c2ecf20Sopenharmony_ci break; 16718c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR_FEAT: 16728c2ecf20Sopenharmony_ci ret = kvm_s390_get_processor_feat(kvm, attr); 16738c2ecf20Sopenharmony_ci break; 16748c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MACHINE_FEAT: 16758c2ecf20Sopenharmony_ci ret = kvm_s390_get_machine_feat(kvm, attr); 16768c2ecf20Sopenharmony_ci break; 16778c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC: 16788c2ecf20Sopenharmony_ci ret = kvm_s390_get_processor_subfunc(kvm, attr); 16798c2ecf20Sopenharmony_ci break; 16808c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MACHINE_SUBFUNC: 16818c2ecf20Sopenharmony_ci ret = kvm_s390_get_machine_subfunc(kvm, attr); 16828c2ecf20Sopenharmony_ci break; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci return ret; 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci int ret; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci switch (attr->group) { 16928c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_CTRL: 16938c2ecf20Sopenharmony_ci ret = kvm_s390_set_mem_control(kvm, attr); 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD: 16968c2ecf20Sopenharmony_ci ret = kvm_s390_set_tod(kvm, attr); 16978c2ecf20Sopenharmony_ci break; 16988c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MODEL: 16998c2ecf20Sopenharmony_ci ret = kvm_s390_set_cpu_model(kvm, attr); 17008c2ecf20Sopenharmony_ci break; 17018c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO: 17028c2ecf20Sopenharmony_ci ret = kvm_s390_vm_set_crypto(kvm, attr); 17038c2ecf20Sopenharmony_ci break; 17048c2ecf20Sopenharmony_ci case KVM_S390_VM_MIGRATION: 17058c2ecf20Sopenharmony_ci ret = kvm_s390_vm_set_migration(kvm, attr); 17068c2ecf20Sopenharmony_ci break; 17078c2ecf20Sopenharmony_ci default: 17088c2ecf20Sopenharmony_ci ret = -ENXIO; 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci return ret; 17138c2ecf20Sopenharmony_ci} 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_cistatic int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr) 17168c2ecf20Sopenharmony_ci{ 17178c2ecf20Sopenharmony_ci int ret; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci switch (attr->group) { 17208c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_CTRL: 17218c2ecf20Sopenharmony_ci ret = kvm_s390_get_mem_control(kvm, attr); 17228c2ecf20Sopenharmony_ci break; 17238c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD: 17248c2ecf20Sopenharmony_ci ret = kvm_s390_get_tod(kvm, attr); 17258c2ecf20Sopenharmony_ci break; 17268c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MODEL: 17278c2ecf20Sopenharmony_ci ret = kvm_s390_get_cpu_model(kvm, attr); 17288c2ecf20Sopenharmony_ci break; 17298c2ecf20Sopenharmony_ci case KVM_S390_VM_MIGRATION: 17308c2ecf20Sopenharmony_ci ret = kvm_s390_vm_get_migration(kvm, attr); 17318c2ecf20Sopenharmony_ci break; 17328c2ecf20Sopenharmony_ci default: 17338c2ecf20Sopenharmony_ci ret = -ENXIO; 17348c2ecf20Sopenharmony_ci break; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci return ret; 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cistatic int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci int ret; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci switch (attr->group) { 17458c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_CTRL: 17468c2ecf20Sopenharmony_ci switch (attr->attr) { 17478c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_ENABLE_CMMA: 17488c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_CLR_CMMA: 17498c2ecf20Sopenharmony_ci ret = sclp.has_cmma ? 0 : -ENXIO; 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci case KVM_S390_VM_MEM_LIMIT_SIZE: 17528c2ecf20Sopenharmony_ci ret = 0; 17538c2ecf20Sopenharmony_ci break; 17548c2ecf20Sopenharmony_ci default: 17558c2ecf20Sopenharmony_ci ret = -ENXIO; 17568c2ecf20Sopenharmony_ci break; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci break; 17598c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD: 17608c2ecf20Sopenharmony_ci switch (attr->attr) { 17618c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_LOW: 17628c2ecf20Sopenharmony_ci case KVM_S390_VM_TOD_HIGH: 17638c2ecf20Sopenharmony_ci ret = 0; 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci default: 17668c2ecf20Sopenharmony_ci ret = -ENXIO; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci break; 17708c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MODEL: 17718c2ecf20Sopenharmony_ci switch (attr->attr) { 17728c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR: 17738c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MACHINE: 17748c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR_FEAT: 17758c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MACHINE_FEAT: 17768c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_MACHINE_SUBFUNC: 17778c2ecf20Sopenharmony_ci case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC: 17788c2ecf20Sopenharmony_ci ret = 0; 17798c2ecf20Sopenharmony_ci break; 17808c2ecf20Sopenharmony_ci default: 17818c2ecf20Sopenharmony_ci ret = -ENXIO; 17828c2ecf20Sopenharmony_ci break; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci break; 17858c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO: 17868c2ecf20Sopenharmony_ci switch (attr->attr) { 17878c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_ENABLE_AES_KW: 17888c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW: 17898c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_DISABLE_AES_KW: 17908c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW: 17918c2ecf20Sopenharmony_ci ret = 0; 17928c2ecf20Sopenharmony_ci break; 17938c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_ENABLE_APIE: 17948c2ecf20Sopenharmony_ci case KVM_S390_VM_CRYPTO_DISABLE_APIE: 17958c2ecf20Sopenharmony_ci ret = ap_instructions_available() ? 0 : -ENXIO; 17968c2ecf20Sopenharmony_ci break; 17978c2ecf20Sopenharmony_ci default: 17988c2ecf20Sopenharmony_ci ret = -ENXIO; 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci break; 18028c2ecf20Sopenharmony_ci case KVM_S390_VM_MIGRATION: 18038c2ecf20Sopenharmony_ci ret = 0; 18048c2ecf20Sopenharmony_ci break; 18058c2ecf20Sopenharmony_ci default: 18068c2ecf20Sopenharmony_ci ret = -ENXIO; 18078c2ecf20Sopenharmony_ci break; 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci return ret; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic long kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci uint8_t *keys; 18168c2ecf20Sopenharmony_ci uint64_t hva; 18178c2ecf20Sopenharmony_ci int srcu_idx, i, r = 0; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if (args->flags != 0) 18208c2ecf20Sopenharmony_ci return -EINVAL; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci /* Is this guest using storage keys? */ 18238c2ecf20Sopenharmony_ci if (!mm_uses_skeys(current->mm)) 18248c2ecf20Sopenharmony_ci return KVM_S390_GET_SKEYS_NONE; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci /* Enforce sane limit on memory allocation */ 18278c2ecf20Sopenharmony_ci if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX) 18288c2ecf20Sopenharmony_ci return -EINVAL; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci keys = kvmalloc_array(args->count, sizeof(uint8_t), GFP_KERNEL); 18318c2ecf20Sopenharmony_ci if (!keys) 18328c2ecf20Sopenharmony_ci return -ENOMEM; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 18358c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&kvm->srcu); 18368c2ecf20Sopenharmony_ci for (i = 0; i < args->count; i++) { 18378c2ecf20Sopenharmony_ci hva = gfn_to_hva(kvm, args->start_gfn + i); 18388c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) { 18398c2ecf20Sopenharmony_ci r = -EFAULT; 18408c2ecf20Sopenharmony_ci break; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci r = get_guest_storage_key(current->mm, hva, &keys[i]); 18448c2ecf20Sopenharmony_ci if (r) 18458c2ecf20Sopenharmony_ci break; 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->srcu, srcu_idx); 18488c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (!r) { 18518c2ecf20Sopenharmony_ci r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys, 18528c2ecf20Sopenharmony_ci sizeof(uint8_t) * args->count); 18538c2ecf20Sopenharmony_ci if (r) 18548c2ecf20Sopenharmony_ci r = -EFAULT; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci kvfree(keys); 18588c2ecf20Sopenharmony_ci return r; 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_cistatic long kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args) 18628c2ecf20Sopenharmony_ci{ 18638c2ecf20Sopenharmony_ci uint8_t *keys; 18648c2ecf20Sopenharmony_ci uint64_t hva; 18658c2ecf20Sopenharmony_ci int srcu_idx, i, r = 0; 18668c2ecf20Sopenharmony_ci bool unlocked; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (args->flags != 0) 18698c2ecf20Sopenharmony_ci return -EINVAL; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci /* Enforce sane limit on memory allocation */ 18728c2ecf20Sopenharmony_ci if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX) 18738c2ecf20Sopenharmony_ci return -EINVAL; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci keys = kvmalloc_array(args->count, sizeof(uint8_t), GFP_KERNEL); 18768c2ecf20Sopenharmony_ci if (!keys) 18778c2ecf20Sopenharmony_ci return -ENOMEM; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci r = copy_from_user(keys, (uint8_t __user *)args->skeydata_addr, 18808c2ecf20Sopenharmony_ci sizeof(uint8_t) * args->count); 18818c2ecf20Sopenharmony_ci if (r) { 18828c2ecf20Sopenharmony_ci r = -EFAULT; 18838c2ecf20Sopenharmony_ci goto out; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* Enable storage key handling for the guest */ 18878c2ecf20Sopenharmony_ci r = s390_enable_skey(); 18888c2ecf20Sopenharmony_ci if (r) 18898c2ecf20Sopenharmony_ci goto out; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci i = 0; 18928c2ecf20Sopenharmony_ci mmap_read_lock(current->mm); 18938c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&kvm->srcu); 18948c2ecf20Sopenharmony_ci while (i < args->count) { 18958c2ecf20Sopenharmony_ci unlocked = false; 18968c2ecf20Sopenharmony_ci hva = gfn_to_hva(kvm, args->start_gfn + i); 18978c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) { 18988c2ecf20Sopenharmony_ci r = -EFAULT; 18998c2ecf20Sopenharmony_ci break; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* Lowest order bit is reserved */ 19038c2ecf20Sopenharmony_ci if (keys[i] & 0x01) { 19048c2ecf20Sopenharmony_ci r = -EINVAL; 19058c2ecf20Sopenharmony_ci break; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci r = set_guest_storage_key(current->mm, hva, keys[i], 0); 19098c2ecf20Sopenharmony_ci if (r) { 19108c2ecf20Sopenharmony_ci r = fixup_user_fault(current->mm, hva, 19118c2ecf20Sopenharmony_ci FAULT_FLAG_WRITE, &unlocked); 19128c2ecf20Sopenharmony_ci if (r) 19138c2ecf20Sopenharmony_ci break; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci if (!r) 19168c2ecf20Sopenharmony_ci i++; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->srcu, srcu_idx); 19198c2ecf20Sopenharmony_ci mmap_read_unlock(current->mm); 19208c2ecf20Sopenharmony_ciout: 19218c2ecf20Sopenharmony_ci kvfree(keys); 19228c2ecf20Sopenharmony_ci return r; 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci/* 19268c2ecf20Sopenharmony_ci * Base address and length must be sent at the start of each block, therefore 19278c2ecf20Sopenharmony_ci * it's cheaper to send some clean data, as long as it's less than the size of 19288c2ecf20Sopenharmony_ci * two longs. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci#define KVM_S390_MAX_BIT_DISTANCE (2 * sizeof(void *)) 19318c2ecf20Sopenharmony_ci/* for consistency */ 19328c2ecf20Sopenharmony_ci#define KVM_S390_CMMA_SIZE_MAX ((u32)KVM_S390_SKEYS_MAX) 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci/* 19358c2ecf20Sopenharmony_ci * Similar to gfn_to_memslot, but returns the index of a memslot also when the 19368c2ecf20Sopenharmony_ci * address falls in a hole. In that case the index of one of the memslots 19378c2ecf20Sopenharmony_ci * bordering the hole is returned. 19388c2ecf20Sopenharmony_ci */ 19398c2ecf20Sopenharmony_cistatic int gfn_to_memslot_approx(struct kvm_memslots *slots, gfn_t gfn) 19408c2ecf20Sopenharmony_ci{ 19418c2ecf20Sopenharmony_ci int start = 0, end = slots->used_slots; 19428c2ecf20Sopenharmony_ci int slot = atomic_read(&slots->lru_slot); 19438c2ecf20Sopenharmony_ci struct kvm_memory_slot *memslots = slots->memslots; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci if (gfn >= memslots[slot].base_gfn && 19468c2ecf20Sopenharmony_ci gfn < memslots[slot].base_gfn + memslots[slot].npages) 19478c2ecf20Sopenharmony_ci return slot; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci while (start < end) { 19508c2ecf20Sopenharmony_ci slot = start + (end - start) / 2; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci if (gfn >= memslots[slot].base_gfn) 19538c2ecf20Sopenharmony_ci end = slot; 19548c2ecf20Sopenharmony_ci else 19558c2ecf20Sopenharmony_ci start = slot + 1; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (start >= slots->used_slots) 19598c2ecf20Sopenharmony_ci return slots->used_slots - 1; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (gfn >= memslots[start].base_gfn && 19628c2ecf20Sopenharmony_ci gfn < memslots[start].base_gfn + memslots[start].npages) { 19638c2ecf20Sopenharmony_ci atomic_set(&slots->lru_slot, start); 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci return start; 19678c2ecf20Sopenharmony_ci} 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cistatic int kvm_s390_peek_cmma(struct kvm *kvm, struct kvm_s390_cmma_log *args, 19708c2ecf20Sopenharmony_ci u8 *res, unsigned long bufsize) 19718c2ecf20Sopenharmony_ci{ 19728c2ecf20Sopenharmony_ci unsigned long pgstev, hva, cur_gfn = args->start_gfn; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci args->count = 0; 19758c2ecf20Sopenharmony_ci while (args->count < bufsize) { 19768c2ecf20Sopenharmony_ci hva = gfn_to_hva(kvm, cur_gfn); 19778c2ecf20Sopenharmony_ci /* 19788c2ecf20Sopenharmony_ci * We return an error if the first value was invalid, but we 19798c2ecf20Sopenharmony_ci * return successfully if at least one value was copied. 19808c2ecf20Sopenharmony_ci */ 19818c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) 19828c2ecf20Sopenharmony_ci return args->count ? 0 : -EFAULT; 19838c2ecf20Sopenharmony_ci if (get_pgste(kvm->mm, hva, &pgstev) < 0) 19848c2ecf20Sopenharmony_ci pgstev = 0; 19858c2ecf20Sopenharmony_ci res[args->count++] = (pgstev >> 24) & 0x43; 19868c2ecf20Sopenharmony_ci cur_gfn++; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci return 0; 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cistatic unsigned long kvm_s390_next_dirty_cmma(struct kvm_memslots *slots, 19938c2ecf20Sopenharmony_ci unsigned long cur_gfn) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci int slotidx = gfn_to_memslot_approx(slots, cur_gfn); 19968c2ecf20Sopenharmony_ci struct kvm_memory_slot *ms = slots->memslots + slotidx; 19978c2ecf20Sopenharmony_ci unsigned long ofs = cur_gfn - ms->base_gfn; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci if (ms->base_gfn + ms->npages <= cur_gfn) { 20008c2ecf20Sopenharmony_ci slotidx--; 20018c2ecf20Sopenharmony_ci /* If we are above the highest slot, wrap around */ 20028c2ecf20Sopenharmony_ci if (slotidx < 0) 20038c2ecf20Sopenharmony_ci slotidx = slots->used_slots - 1; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci ms = slots->memslots + slotidx; 20068c2ecf20Sopenharmony_ci ofs = 0; 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if (cur_gfn < ms->base_gfn) 20108c2ecf20Sopenharmony_ci ofs = 0; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci ofs = find_next_bit(kvm_second_dirty_bitmap(ms), ms->npages, ofs); 20138c2ecf20Sopenharmony_ci while ((slotidx > 0) && (ofs >= ms->npages)) { 20148c2ecf20Sopenharmony_ci slotidx--; 20158c2ecf20Sopenharmony_ci ms = slots->memslots + slotidx; 20168c2ecf20Sopenharmony_ci ofs = find_next_bit(kvm_second_dirty_bitmap(ms), ms->npages, 0); 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci return ms->base_gfn + ofs; 20198c2ecf20Sopenharmony_ci} 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_cistatic int kvm_s390_get_cmma(struct kvm *kvm, struct kvm_s390_cmma_log *args, 20228c2ecf20Sopenharmony_ci u8 *res, unsigned long bufsize) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci unsigned long mem_end, cur_gfn, next_gfn, hva, pgstev; 20258c2ecf20Sopenharmony_ci struct kvm_memslots *slots = kvm_memslots(kvm); 20268c2ecf20Sopenharmony_ci struct kvm_memory_slot *ms; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci if (unlikely(!slots->used_slots)) 20298c2ecf20Sopenharmony_ci return 0; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci cur_gfn = kvm_s390_next_dirty_cmma(slots, args->start_gfn); 20328c2ecf20Sopenharmony_ci ms = gfn_to_memslot(kvm, cur_gfn); 20338c2ecf20Sopenharmony_ci args->count = 0; 20348c2ecf20Sopenharmony_ci args->start_gfn = cur_gfn; 20358c2ecf20Sopenharmony_ci if (!ms) 20368c2ecf20Sopenharmony_ci return 0; 20378c2ecf20Sopenharmony_ci next_gfn = kvm_s390_next_dirty_cmma(slots, cur_gfn + 1); 20388c2ecf20Sopenharmony_ci mem_end = slots->memslots[0].base_gfn + slots->memslots[0].npages; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci while (args->count < bufsize) { 20418c2ecf20Sopenharmony_ci hva = gfn_to_hva(kvm, cur_gfn); 20428c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) 20438c2ecf20Sopenharmony_ci return 0; 20448c2ecf20Sopenharmony_ci /* Decrement only if we actually flipped the bit to 0 */ 20458c2ecf20Sopenharmony_ci if (test_and_clear_bit(cur_gfn - ms->base_gfn, kvm_second_dirty_bitmap(ms))) 20468c2ecf20Sopenharmony_ci atomic64_dec(&kvm->arch.cmma_dirty_pages); 20478c2ecf20Sopenharmony_ci if (get_pgste(kvm->mm, hva, &pgstev) < 0) 20488c2ecf20Sopenharmony_ci pgstev = 0; 20498c2ecf20Sopenharmony_ci /* Save the value */ 20508c2ecf20Sopenharmony_ci res[args->count++] = (pgstev >> 24) & 0x43; 20518c2ecf20Sopenharmony_ci /* If the next bit is too far away, stop. */ 20528c2ecf20Sopenharmony_ci if (next_gfn > cur_gfn + KVM_S390_MAX_BIT_DISTANCE) 20538c2ecf20Sopenharmony_ci return 0; 20548c2ecf20Sopenharmony_ci /* If we reached the previous "next", find the next one */ 20558c2ecf20Sopenharmony_ci if (cur_gfn == next_gfn) 20568c2ecf20Sopenharmony_ci next_gfn = kvm_s390_next_dirty_cmma(slots, cur_gfn + 1); 20578c2ecf20Sopenharmony_ci /* Reached the end of memory or of the buffer, stop */ 20588c2ecf20Sopenharmony_ci if ((next_gfn >= mem_end) || 20598c2ecf20Sopenharmony_ci (next_gfn - args->start_gfn >= bufsize)) 20608c2ecf20Sopenharmony_ci return 0; 20618c2ecf20Sopenharmony_ci cur_gfn++; 20628c2ecf20Sopenharmony_ci /* Reached the end of the current memslot, take the next one. */ 20638c2ecf20Sopenharmony_ci if (cur_gfn - ms->base_gfn >= ms->npages) { 20648c2ecf20Sopenharmony_ci ms = gfn_to_memslot(kvm, cur_gfn); 20658c2ecf20Sopenharmony_ci if (!ms) 20668c2ecf20Sopenharmony_ci return 0; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci return 0; 20708c2ecf20Sopenharmony_ci} 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci/* 20738c2ecf20Sopenharmony_ci * This function searches for the next page with dirty CMMA attributes, and 20748c2ecf20Sopenharmony_ci * saves the attributes in the buffer up to either the end of the buffer or 20758c2ecf20Sopenharmony_ci * until a block of at least KVM_S390_MAX_BIT_DISTANCE clean bits is found; 20768c2ecf20Sopenharmony_ci * no trailing clean bytes are saved. 20778c2ecf20Sopenharmony_ci * In case no dirty bits were found, or if CMMA was not enabled or used, the 20788c2ecf20Sopenharmony_ci * output buffer will indicate 0 as length. 20798c2ecf20Sopenharmony_ci */ 20808c2ecf20Sopenharmony_cistatic int kvm_s390_get_cmma_bits(struct kvm *kvm, 20818c2ecf20Sopenharmony_ci struct kvm_s390_cmma_log *args) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci unsigned long bufsize; 20848c2ecf20Sopenharmony_ci int srcu_idx, peek, ret; 20858c2ecf20Sopenharmony_ci u8 *values; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci if (!kvm->arch.use_cmma) 20888c2ecf20Sopenharmony_ci return -ENXIO; 20898c2ecf20Sopenharmony_ci /* Invalid/unsupported flags were specified */ 20908c2ecf20Sopenharmony_ci if (args->flags & ~KVM_S390_CMMA_PEEK) 20918c2ecf20Sopenharmony_ci return -EINVAL; 20928c2ecf20Sopenharmony_ci /* Migration mode query, and we are not doing a migration */ 20938c2ecf20Sopenharmony_ci peek = !!(args->flags & KVM_S390_CMMA_PEEK); 20948c2ecf20Sopenharmony_ci if (!peek && !kvm->arch.migration_mode) 20958c2ecf20Sopenharmony_ci return -EINVAL; 20968c2ecf20Sopenharmony_ci /* CMMA is disabled or was not used, or the buffer has length zero */ 20978c2ecf20Sopenharmony_ci bufsize = min(args->count, KVM_S390_CMMA_SIZE_MAX); 20988c2ecf20Sopenharmony_ci if (!bufsize || !kvm->mm->context.uses_cmm) { 20998c2ecf20Sopenharmony_ci memset(args, 0, sizeof(*args)); 21008c2ecf20Sopenharmony_ci return 0; 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci /* We are not peeking, and there are no dirty pages */ 21038c2ecf20Sopenharmony_ci if (!peek && !atomic64_read(&kvm->arch.cmma_dirty_pages)) { 21048c2ecf20Sopenharmony_ci memset(args, 0, sizeof(*args)); 21058c2ecf20Sopenharmony_ci return 0; 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci values = vmalloc(bufsize); 21098c2ecf20Sopenharmony_ci if (!values) 21108c2ecf20Sopenharmony_ci return -ENOMEM; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci mmap_read_lock(kvm->mm); 21138c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&kvm->srcu); 21148c2ecf20Sopenharmony_ci if (peek) 21158c2ecf20Sopenharmony_ci ret = kvm_s390_peek_cmma(kvm, args, values, bufsize); 21168c2ecf20Sopenharmony_ci else 21178c2ecf20Sopenharmony_ci ret = kvm_s390_get_cmma(kvm, args, values, bufsize); 21188c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->srcu, srcu_idx); 21198c2ecf20Sopenharmony_ci mmap_read_unlock(kvm->mm); 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci if (kvm->arch.migration_mode) 21228c2ecf20Sopenharmony_ci args->remaining = atomic64_read(&kvm->arch.cmma_dirty_pages); 21238c2ecf20Sopenharmony_ci else 21248c2ecf20Sopenharmony_ci args->remaining = 0; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)args->values, values, args->count)) 21278c2ecf20Sopenharmony_ci ret = -EFAULT; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci vfree(values); 21308c2ecf20Sopenharmony_ci return ret; 21318c2ecf20Sopenharmony_ci} 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci/* 21348c2ecf20Sopenharmony_ci * This function sets the CMMA attributes for the given pages. If the input 21358c2ecf20Sopenharmony_ci * buffer has zero length, no action is taken, otherwise the attributes are 21368c2ecf20Sopenharmony_ci * set and the mm->context.uses_cmm flag is set. 21378c2ecf20Sopenharmony_ci */ 21388c2ecf20Sopenharmony_cistatic int kvm_s390_set_cmma_bits(struct kvm *kvm, 21398c2ecf20Sopenharmony_ci const struct kvm_s390_cmma_log *args) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci unsigned long hva, mask, pgstev, i; 21428c2ecf20Sopenharmony_ci uint8_t *bits; 21438c2ecf20Sopenharmony_ci int srcu_idx, r = 0; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci mask = args->mask; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci if (!kvm->arch.use_cmma) 21488c2ecf20Sopenharmony_ci return -ENXIO; 21498c2ecf20Sopenharmony_ci /* invalid/unsupported flags */ 21508c2ecf20Sopenharmony_ci if (args->flags != 0) 21518c2ecf20Sopenharmony_ci return -EINVAL; 21528c2ecf20Sopenharmony_ci /* Enforce sane limit on memory allocation */ 21538c2ecf20Sopenharmony_ci if (args->count > KVM_S390_CMMA_SIZE_MAX) 21548c2ecf20Sopenharmony_ci return -EINVAL; 21558c2ecf20Sopenharmony_ci /* Nothing to do */ 21568c2ecf20Sopenharmony_ci if (args->count == 0) 21578c2ecf20Sopenharmony_ci return 0; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci bits = vmalloc(array_size(sizeof(*bits), args->count)); 21608c2ecf20Sopenharmony_ci if (!bits) 21618c2ecf20Sopenharmony_ci return -ENOMEM; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci r = copy_from_user(bits, (void __user *)args->values, args->count); 21648c2ecf20Sopenharmony_ci if (r) { 21658c2ecf20Sopenharmony_ci r = -EFAULT; 21668c2ecf20Sopenharmony_ci goto out; 21678c2ecf20Sopenharmony_ci } 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci mmap_read_lock(kvm->mm); 21708c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&kvm->srcu); 21718c2ecf20Sopenharmony_ci for (i = 0; i < args->count; i++) { 21728c2ecf20Sopenharmony_ci hva = gfn_to_hva(kvm, args->start_gfn + i); 21738c2ecf20Sopenharmony_ci if (kvm_is_error_hva(hva)) { 21748c2ecf20Sopenharmony_ci r = -EFAULT; 21758c2ecf20Sopenharmony_ci break; 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci pgstev = bits[i]; 21798c2ecf20Sopenharmony_ci pgstev = pgstev << 24; 21808c2ecf20Sopenharmony_ci mask &= _PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT; 21818c2ecf20Sopenharmony_ci set_pgste_bits(kvm->mm, hva, mask, pgstev); 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci srcu_read_unlock(&kvm->srcu, srcu_idx); 21848c2ecf20Sopenharmony_ci mmap_read_unlock(kvm->mm); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if (!kvm->mm->context.uses_cmm) { 21878c2ecf20Sopenharmony_ci mmap_write_lock(kvm->mm); 21888c2ecf20Sopenharmony_ci kvm->mm->context.uses_cmm = 1; 21898c2ecf20Sopenharmony_ci mmap_write_unlock(kvm->mm); 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ciout: 21928c2ecf20Sopenharmony_ci vfree(bits); 21938c2ecf20Sopenharmony_ci return r; 21948c2ecf20Sopenharmony_ci} 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_cistatic int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rcp, u16 *rrcp) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 21998c2ecf20Sopenharmony_ci u16 rc, rrc; 22008c2ecf20Sopenharmony_ci int ret = 0; 22018c2ecf20Sopenharmony_ci int i; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci /* 22048c2ecf20Sopenharmony_ci * We ignore failures and try to destroy as many CPUs as possible. 22058c2ecf20Sopenharmony_ci * At the same time we must not free the assigned resources when 22068c2ecf20Sopenharmony_ci * this fails, as the ultravisor has still access to that memory. 22078c2ecf20Sopenharmony_ci * So kvm_s390_pv_destroy_cpu can leave a "wanted" memory leak 22088c2ecf20Sopenharmony_ci * behind. 22098c2ecf20Sopenharmony_ci * We want to return the first failure rc and rrc, though. 22108c2ecf20Sopenharmony_ci */ 22118c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 22128c2ecf20Sopenharmony_ci mutex_lock(&vcpu->mutex); 22138c2ecf20Sopenharmony_ci if (kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc) && !ret) { 22148c2ecf20Sopenharmony_ci *rcp = rc; 22158c2ecf20Sopenharmony_ci *rrcp = rrc; 22168c2ecf20Sopenharmony_ci ret = -EIO; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->mutex); 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci return ret; 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_cistatic int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc) 22248c2ecf20Sopenharmony_ci{ 22258c2ecf20Sopenharmony_ci int i, r = 0; 22268c2ecf20Sopenharmony_ci u16 dummy; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 22318c2ecf20Sopenharmony_ci mutex_lock(&vcpu->mutex); 22328c2ecf20Sopenharmony_ci r = kvm_s390_pv_create_cpu(vcpu, rc, rrc); 22338c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->mutex); 22348c2ecf20Sopenharmony_ci if (r) 22358c2ecf20Sopenharmony_ci break; 22368c2ecf20Sopenharmony_ci } 22378c2ecf20Sopenharmony_ci if (r) 22388c2ecf20Sopenharmony_ci kvm_s390_cpus_from_pv(kvm, &dummy, &dummy); 22398c2ecf20Sopenharmony_ci return r; 22408c2ecf20Sopenharmony_ci} 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_cistatic int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) 22438c2ecf20Sopenharmony_ci{ 22448c2ecf20Sopenharmony_ci int r = 0; 22458c2ecf20Sopenharmony_ci u16 dummy; 22468c2ecf20Sopenharmony_ci void __user *argp = (void __user *)cmd->data; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci switch (cmd->cmd) { 22498c2ecf20Sopenharmony_ci case KVM_PV_ENABLE: { 22508c2ecf20Sopenharmony_ci r = -EINVAL; 22518c2ecf20Sopenharmony_ci if (kvm_s390_pv_is_protected(kvm)) 22528c2ecf20Sopenharmony_ci break; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci /* 22558c2ecf20Sopenharmony_ci * FMT 4 SIE needs esca. As we never switch back to bsca from 22568c2ecf20Sopenharmony_ci * esca, we need no cleanup in the error cases below 22578c2ecf20Sopenharmony_ci */ 22588c2ecf20Sopenharmony_ci r = sca_switch_to_extended(kvm); 22598c2ecf20Sopenharmony_ci if (r) 22608c2ecf20Sopenharmony_ci break; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci mmap_write_lock(current->mm); 22638c2ecf20Sopenharmony_ci r = gmap_mark_unmergeable(); 22648c2ecf20Sopenharmony_ci mmap_write_unlock(current->mm); 22658c2ecf20Sopenharmony_ci if (r) 22668c2ecf20Sopenharmony_ci break; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci r = kvm_s390_pv_init_vm(kvm, &cmd->rc, &cmd->rrc); 22698c2ecf20Sopenharmony_ci if (r) 22708c2ecf20Sopenharmony_ci break; 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci r = kvm_s390_cpus_to_pv(kvm, &cmd->rc, &cmd->rrc); 22738c2ecf20Sopenharmony_ci if (r) 22748c2ecf20Sopenharmony_ci kvm_s390_pv_deinit_vm(kvm, &dummy, &dummy); 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci /* we need to block service interrupts from now on */ 22778c2ecf20Sopenharmony_ci set_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs); 22788c2ecf20Sopenharmony_ci break; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci case KVM_PV_DISABLE: { 22818c2ecf20Sopenharmony_ci r = -EINVAL; 22828c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm)) 22838c2ecf20Sopenharmony_ci break; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci r = kvm_s390_cpus_from_pv(kvm, &cmd->rc, &cmd->rrc); 22868c2ecf20Sopenharmony_ci /* 22878c2ecf20Sopenharmony_ci * If a CPU could not be destroyed, destroy VM will also fail. 22888c2ecf20Sopenharmony_ci * There is no point in trying to destroy it. Instead return 22898c2ecf20Sopenharmony_ci * the rc and rrc from the first CPU that failed destroying. 22908c2ecf20Sopenharmony_ci */ 22918c2ecf20Sopenharmony_ci if (r) 22928c2ecf20Sopenharmony_ci break; 22938c2ecf20Sopenharmony_ci r = kvm_s390_pv_deinit_vm(kvm, &cmd->rc, &cmd->rrc); 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci /* no need to block service interrupts any more */ 22968c2ecf20Sopenharmony_ci clear_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs); 22978c2ecf20Sopenharmony_ci break; 22988c2ecf20Sopenharmony_ci } 22998c2ecf20Sopenharmony_ci case KVM_PV_SET_SEC_PARMS: { 23008c2ecf20Sopenharmony_ci struct kvm_s390_pv_sec_parm parms = {}; 23018c2ecf20Sopenharmony_ci void *hdr; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci r = -EINVAL; 23048c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm)) 23058c2ecf20Sopenharmony_ci break; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci r = -EFAULT; 23088c2ecf20Sopenharmony_ci if (copy_from_user(&parms, argp, sizeof(parms))) 23098c2ecf20Sopenharmony_ci break; 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci /* Currently restricted to 8KB */ 23128c2ecf20Sopenharmony_ci r = -EINVAL; 23138c2ecf20Sopenharmony_ci if (parms.length > PAGE_SIZE * 2) 23148c2ecf20Sopenharmony_ci break; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci r = -ENOMEM; 23178c2ecf20Sopenharmony_ci hdr = vmalloc(parms.length); 23188c2ecf20Sopenharmony_ci if (!hdr) 23198c2ecf20Sopenharmony_ci break; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci r = -EFAULT; 23228c2ecf20Sopenharmony_ci if (!copy_from_user(hdr, (void __user *)parms.origin, 23238c2ecf20Sopenharmony_ci parms.length)) 23248c2ecf20Sopenharmony_ci r = kvm_s390_pv_set_sec_parms(kvm, hdr, parms.length, 23258c2ecf20Sopenharmony_ci &cmd->rc, &cmd->rrc); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci vfree(hdr); 23288c2ecf20Sopenharmony_ci break; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci case KVM_PV_UNPACK: { 23318c2ecf20Sopenharmony_ci struct kvm_s390_pv_unp unp = {}; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci r = -EINVAL; 23348c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm) || !mm_is_protected(kvm->mm)) 23358c2ecf20Sopenharmony_ci break; 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci r = -EFAULT; 23388c2ecf20Sopenharmony_ci if (copy_from_user(&unp, argp, sizeof(unp))) 23398c2ecf20Sopenharmony_ci break; 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci r = kvm_s390_pv_unpack(kvm, unp.addr, unp.size, unp.tweak, 23428c2ecf20Sopenharmony_ci &cmd->rc, &cmd->rrc); 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci case KVM_PV_VERIFY: { 23468c2ecf20Sopenharmony_ci r = -EINVAL; 23478c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm)) 23488c2ecf20Sopenharmony_ci break; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), 23518c2ecf20Sopenharmony_ci UVC_CMD_VERIFY_IMG, &cmd->rc, &cmd->rrc); 23528c2ecf20Sopenharmony_ci KVM_UV_EVENT(kvm, 3, "PROTVIRT VERIFY: rc %x rrc %x", cmd->rc, 23538c2ecf20Sopenharmony_ci cmd->rrc); 23548c2ecf20Sopenharmony_ci break; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci case KVM_PV_PREP_RESET: { 23578c2ecf20Sopenharmony_ci r = -EINVAL; 23588c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm)) 23598c2ecf20Sopenharmony_ci break; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), 23628c2ecf20Sopenharmony_ci UVC_CMD_PREPARE_RESET, &cmd->rc, &cmd->rrc); 23638c2ecf20Sopenharmony_ci KVM_UV_EVENT(kvm, 3, "PROTVIRT PREP RESET: rc %x rrc %x", 23648c2ecf20Sopenharmony_ci cmd->rc, cmd->rrc); 23658c2ecf20Sopenharmony_ci break; 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci case KVM_PV_UNSHARE_ALL: { 23688c2ecf20Sopenharmony_ci r = -EINVAL; 23698c2ecf20Sopenharmony_ci if (!kvm_s390_pv_is_protected(kvm)) 23708c2ecf20Sopenharmony_ci break; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), 23738c2ecf20Sopenharmony_ci UVC_CMD_SET_UNSHARE_ALL, &cmd->rc, &cmd->rrc); 23748c2ecf20Sopenharmony_ci KVM_UV_EVENT(kvm, 3, "PROTVIRT UNSHARE: rc %x rrc %x", 23758c2ecf20Sopenharmony_ci cmd->rc, cmd->rrc); 23768c2ecf20Sopenharmony_ci break; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci default: 23798c2ecf20Sopenharmony_ci r = -ENOTTY; 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci return r; 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_cilong kvm_arch_vm_ioctl(struct file *filp, 23858c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 23888c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 23898c2ecf20Sopenharmony_ci struct kvm_device_attr attr; 23908c2ecf20Sopenharmony_ci int r; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci switch (ioctl) { 23938c2ecf20Sopenharmony_ci case KVM_S390_INTERRUPT: { 23948c2ecf20Sopenharmony_ci struct kvm_s390_interrupt s390int; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci r = -EFAULT; 23978c2ecf20Sopenharmony_ci if (copy_from_user(&s390int, argp, sizeof(s390int))) 23988c2ecf20Sopenharmony_ci break; 23998c2ecf20Sopenharmony_ci r = kvm_s390_inject_vm(kvm, &s390int); 24008c2ecf20Sopenharmony_ci break; 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci case KVM_CREATE_IRQCHIP: { 24038c2ecf20Sopenharmony_ci struct kvm_irq_routing_entry routing; 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci r = -EINVAL; 24068c2ecf20Sopenharmony_ci if (kvm->arch.use_irqchip) { 24078c2ecf20Sopenharmony_ci /* Set up dummy routing. */ 24088c2ecf20Sopenharmony_ci memset(&routing, 0, sizeof(routing)); 24098c2ecf20Sopenharmony_ci r = kvm_set_irq_routing(kvm, &routing, 0, 0); 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci break; 24128c2ecf20Sopenharmony_ci } 24138c2ecf20Sopenharmony_ci case KVM_SET_DEVICE_ATTR: { 24148c2ecf20Sopenharmony_ci r = -EFAULT; 24158c2ecf20Sopenharmony_ci if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) 24168c2ecf20Sopenharmony_ci break; 24178c2ecf20Sopenharmony_ci r = kvm_s390_vm_set_attr(kvm, &attr); 24188c2ecf20Sopenharmony_ci break; 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci case KVM_GET_DEVICE_ATTR: { 24218c2ecf20Sopenharmony_ci r = -EFAULT; 24228c2ecf20Sopenharmony_ci if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) 24238c2ecf20Sopenharmony_ci break; 24248c2ecf20Sopenharmony_ci r = kvm_s390_vm_get_attr(kvm, &attr); 24258c2ecf20Sopenharmony_ci break; 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci case KVM_HAS_DEVICE_ATTR: { 24288c2ecf20Sopenharmony_ci r = -EFAULT; 24298c2ecf20Sopenharmony_ci if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) 24308c2ecf20Sopenharmony_ci break; 24318c2ecf20Sopenharmony_ci r = kvm_s390_vm_has_attr(kvm, &attr); 24328c2ecf20Sopenharmony_ci break; 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci case KVM_S390_GET_SKEYS: { 24358c2ecf20Sopenharmony_ci struct kvm_s390_skeys args; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci r = -EFAULT; 24388c2ecf20Sopenharmony_ci if (copy_from_user(&args, argp, 24398c2ecf20Sopenharmony_ci sizeof(struct kvm_s390_skeys))) 24408c2ecf20Sopenharmony_ci break; 24418c2ecf20Sopenharmony_ci r = kvm_s390_get_skeys(kvm, &args); 24428c2ecf20Sopenharmony_ci break; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci case KVM_S390_SET_SKEYS: { 24458c2ecf20Sopenharmony_ci struct kvm_s390_skeys args; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci r = -EFAULT; 24488c2ecf20Sopenharmony_ci if (copy_from_user(&args, argp, 24498c2ecf20Sopenharmony_ci sizeof(struct kvm_s390_skeys))) 24508c2ecf20Sopenharmony_ci break; 24518c2ecf20Sopenharmony_ci r = kvm_s390_set_skeys(kvm, &args); 24528c2ecf20Sopenharmony_ci break; 24538c2ecf20Sopenharmony_ci } 24548c2ecf20Sopenharmony_ci case KVM_S390_GET_CMMA_BITS: { 24558c2ecf20Sopenharmony_ci struct kvm_s390_cmma_log args; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci r = -EFAULT; 24588c2ecf20Sopenharmony_ci if (copy_from_user(&args, argp, sizeof(args))) 24598c2ecf20Sopenharmony_ci break; 24608c2ecf20Sopenharmony_ci mutex_lock(&kvm->slots_lock); 24618c2ecf20Sopenharmony_ci r = kvm_s390_get_cmma_bits(kvm, &args); 24628c2ecf20Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 24638c2ecf20Sopenharmony_ci if (!r) { 24648c2ecf20Sopenharmony_ci r = copy_to_user(argp, &args, sizeof(args)); 24658c2ecf20Sopenharmony_ci if (r) 24668c2ecf20Sopenharmony_ci r = -EFAULT; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci break; 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci case KVM_S390_SET_CMMA_BITS: { 24718c2ecf20Sopenharmony_ci struct kvm_s390_cmma_log args; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci r = -EFAULT; 24748c2ecf20Sopenharmony_ci if (copy_from_user(&args, argp, sizeof(args))) 24758c2ecf20Sopenharmony_ci break; 24768c2ecf20Sopenharmony_ci mutex_lock(&kvm->slots_lock); 24778c2ecf20Sopenharmony_ci r = kvm_s390_set_cmma_bits(kvm, &args); 24788c2ecf20Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 24798c2ecf20Sopenharmony_ci break; 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci case KVM_S390_PV_COMMAND: { 24828c2ecf20Sopenharmony_ci struct kvm_pv_cmd args; 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci /* protvirt means user sigp */ 24858c2ecf20Sopenharmony_ci kvm->arch.user_cpu_state_ctrl = 1; 24868c2ecf20Sopenharmony_ci r = 0; 24878c2ecf20Sopenharmony_ci if (!is_prot_virt_host()) { 24888c2ecf20Sopenharmony_ci r = -EINVAL; 24898c2ecf20Sopenharmony_ci break; 24908c2ecf20Sopenharmony_ci } 24918c2ecf20Sopenharmony_ci if (copy_from_user(&args, argp, sizeof(args))) { 24928c2ecf20Sopenharmony_ci r = -EFAULT; 24938c2ecf20Sopenharmony_ci break; 24948c2ecf20Sopenharmony_ci } 24958c2ecf20Sopenharmony_ci if (args.flags) { 24968c2ecf20Sopenharmony_ci r = -EINVAL; 24978c2ecf20Sopenharmony_ci break; 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 25008c2ecf20Sopenharmony_ci r = kvm_s390_handle_pv(kvm, &args); 25018c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 25028c2ecf20Sopenharmony_ci if (copy_to_user(argp, &args, sizeof(args))) { 25038c2ecf20Sopenharmony_ci r = -EFAULT; 25048c2ecf20Sopenharmony_ci break; 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci break; 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci default: 25098c2ecf20Sopenharmony_ci r = -ENOTTY; 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci return r; 25138c2ecf20Sopenharmony_ci} 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_cistatic int kvm_s390_apxa_installed(void) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci struct ap_config_info info; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci if (ap_instructions_available()) { 25208c2ecf20Sopenharmony_ci if (ap_qci(&info) == 0) 25218c2ecf20Sopenharmony_ci return info.apxa; 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci return 0; 25258c2ecf20Sopenharmony_ci} 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci/* 25288c2ecf20Sopenharmony_ci * The format of the crypto control block (CRYCB) is specified in the 3 low 25298c2ecf20Sopenharmony_ci * order bits of the CRYCB designation (CRYCBD) field as follows: 25308c2ecf20Sopenharmony_ci * Format 0: Neither the message security assist extension 3 (MSAX3) nor the 25318c2ecf20Sopenharmony_ci * AP extended addressing (APXA) facility are installed. 25328c2ecf20Sopenharmony_ci * Format 1: The APXA facility is not installed but the MSAX3 facility is. 25338c2ecf20Sopenharmony_ci * Format 2: Both the APXA and MSAX3 facilities are installed 25348c2ecf20Sopenharmony_ci */ 25358c2ecf20Sopenharmony_cistatic void kvm_s390_set_crycb_format(struct kvm *kvm) 25368c2ecf20Sopenharmony_ci{ 25378c2ecf20Sopenharmony_ci kvm->arch.crypto.crycbd = (__u32)(unsigned long) kvm->arch.crypto.crycb; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci /* Clear the CRYCB format bits - i.e., set format 0 by default */ 25408c2ecf20Sopenharmony_ci kvm->arch.crypto.crycbd &= ~(CRYCB_FORMAT_MASK); 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci /* Check whether MSAX3 is installed */ 25438c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 76)) 25448c2ecf20Sopenharmony_ci return; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci if (kvm_s390_apxa_installed()) 25478c2ecf20Sopenharmony_ci kvm->arch.crypto.crycbd |= CRYCB_FORMAT2; 25488c2ecf20Sopenharmony_ci else 25498c2ecf20Sopenharmony_ci kvm->arch.crypto.crycbd |= CRYCB_FORMAT1; 25508c2ecf20Sopenharmony_ci} 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_civoid kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm, 25538c2ecf20Sopenharmony_ci unsigned long *aqm, unsigned long *adm) 25548c2ecf20Sopenharmony_ci{ 25558c2ecf20Sopenharmony_ci struct kvm_s390_crypto_cb *crycb = kvm->arch.crypto.crycb; 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 25588c2ecf20Sopenharmony_ci kvm_s390_vcpu_block_all(kvm); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci switch (kvm->arch.crypto.crycbd & CRYCB_FORMAT_MASK) { 25618c2ecf20Sopenharmony_ci case CRYCB_FORMAT2: /* APCB1 use 256 bits */ 25628c2ecf20Sopenharmony_ci memcpy(crycb->apcb1.apm, apm, 32); 25638c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET CRYCB: apm %016lx %016lx %016lx %016lx", 25648c2ecf20Sopenharmony_ci apm[0], apm[1], apm[2], apm[3]); 25658c2ecf20Sopenharmony_ci memcpy(crycb->apcb1.aqm, aqm, 32); 25668c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET CRYCB: aqm %016lx %016lx %016lx %016lx", 25678c2ecf20Sopenharmony_ci aqm[0], aqm[1], aqm[2], aqm[3]); 25688c2ecf20Sopenharmony_ci memcpy(crycb->apcb1.adm, adm, 32); 25698c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET CRYCB: adm %016lx %016lx %016lx %016lx", 25708c2ecf20Sopenharmony_ci adm[0], adm[1], adm[2], adm[3]); 25718c2ecf20Sopenharmony_ci break; 25728c2ecf20Sopenharmony_ci case CRYCB_FORMAT1: 25738c2ecf20Sopenharmony_ci case CRYCB_FORMAT0: /* Fall through both use APCB0 */ 25748c2ecf20Sopenharmony_ci memcpy(crycb->apcb0.apm, apm, 8); 25758c2ecf20Sopenharmony_ci memcpy(crycb->apcb0.aqm, aqm, 2); 25768c2ecf20Sopenharmony_ci memcpy(crycb->apcb0.adm, adm, 2); 25778c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "SET CRYCB: apm %016lx aqm %04x adm %04x", 25788c2ecf20Sopenharmony_ci apm[0], *((unsigned short *)aqm), 25798c2ecf20Sopenharmony_ci *((unsigned short *)adm)); 25808c2ecf20Sopenharmony_ci break; 25818c2ecf20Sopenharmony_ci default: /* Can not happen */ 25828c2ecf20Sopenharmony_ci break; 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci /* recreate the shadow crycb for each vcpu */ 25868c2ecf20Sopenharmony_ci kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART); 25878c2ecf20Sopenharmony_ci kvm_s390_vcpu_unblock_all(kvm); 25888c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 25898c2ecf20Sopenharmony_ci} 25908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_arch_crypto_set_masks); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_civoid kvm_arch_crypto_clear_masks(struct kvm *kvm) 25938c2ecf20Sopenharmony_ci{ 25948c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 25958c2ecf20Sopenharmony_ci kvm_s390_vcpu_block_all(kvm); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci memset(&kvm->arch.crypto.crycb->apcb0, 0, 25988c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->apcb0)); 25998c2ecf20Sopenharmony_ci memset(&kvm->arch.crypto.crycb->apcb1, 0, 26008c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->apcb1)); 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "%s", "CLR CRYCB:"); 26038c2ecf20Sopenharmony_ci /* recreate the shadow crycb for each vcpu */ 26048c2ecf20Sopenharmony_ci kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART); 26058c2ecf20Sopenharmony_ci kvm_s390_vcpu_unblock_all(kvm); 26068c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 26078c2ecf20Sopenharmony_ci} 26088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvm_arch_crypto_clear_masks); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_cistatic u64 kvm_s390_get_initial_cpuid(void) 26118c2ecf20Sopenharmony_ci{ 26128c2ecf20Sopenharmony_ci struct cpuid cpuid; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci get_cpu_id(&cpuid); 26158c2ecf20Sopenharmony_ci cpuid.version = 0xff; 26168c2ecf20Sopenharmony_ci return *((u64 *) &cpuid); 26178c2ecf20Sopenharmony_ci} 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_cistatic void kvm_s390_crypto_init(struct kvm *kvm) 26208c2ecf20Sopenharmony_ci{ 26218c2ecf20Sopenharmony_ci kvm->arch.crypto.crycb = &kvm->arch.sie_page2->crycb; 26228c2ecf20Sopenharmony_ci kvm_s390_set_crycb_format(kvm); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (!test_kvm_facility(kvm, 76)) 26258c2ecf20Sopenharmony_ci return; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci /* Enable AES/DEA protected key functions by default */ 26288c2ecf20Sopenharmony_ci kvm->arch.crypto.aes_kw = 1; 26298c2ecf20Sopenharmony_ci kvm->arch.crypto.dea_kw = 1; 26308c2ecf20Sopenharmony_ci get_random_bytes(kvm->arch.crypto.crycb->aes_wrapping_key_mask, 26318c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask)); 26328c2ecf20Sopenharmony_ci get_random_bytes(kvm->arch.crypto.crycb->dea_wrapping_key_mask, 26338c2ecf20Sopenharmony_ci sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask)); 26348c2ecf20Sopenharmony_ci} 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_cistatic void sca_dispose(struct kvm *kvm) 26378c2ecf20Sopenharmony_ci{ 26388c2ecf20Sopenharmony_ci if (kvm->arch.use_esca) 26398c2ecf20Sopenharmony_ci free_pages_exact(kvm->arch.sca, sizeof(struct esca_block)); 26408c2ecf20Sopenharmony_ci else 26418c2ecf20Sopenharmony_ci free_page((unsigned long)(kvm->arch.sca)); 26428c2ecf20Sopenharmony_ci kvm->arch.sca = NULL; 26438c2ecf20Sopenharmony_ci} 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ciint kvm_arch_init_vm(struct kvm *kvm, unsigned long type) 26468c2ecf20Sopenharmony_ci{ 26478c2ecf20Sopenharmony_ci gfp_t alloc_flags = GFP_KERNEL; 26488c2ecf20Sopenharmony_ci int i, rc; 26498c2ecf20Sopenharmony_ci char debug_name[16]; 26508c2ecf20Sopenharmony_ci static unsigned long sca_offset; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci rc = -EINVAL; 26538c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_S390_UCONTROL 26548c2ecf20Sopenharmony_ci if (type & ~KVM_VM_S390_UCONTROL) 26558c2ecf20Sopenharmony_ci goto out_err; 26568c2ecf20Sopenharmony_ci if ((type & KVM_VM_S390_UCONTROL) && (!capable(CAP_SYS_ADMIN))) 26578c2ecf20Sopenharmony_ci goto out_err; 26588c2ecf20Sopenharmony_ci#else 26598c2ecf20Sopenharmony_ci if (type) 26608c2ecf20Sopenharmony_ci goto out_err; 26618c2ecf20Sopenharmony_ci#endif 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci rc = s390_enable_sie(); 26648c2ecf20Sopenharmony_ci if (rc) 26658c2ecf20Sopenharmony_ci goto out_err; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci rc = -ENOMEM; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci if (!sclp.has_64bscao) 26708c2ecf20Sopenharmony_ci alloc_flags |= GFP_DMA; 26718c2ecf20Sopenharmony_ci rwlock_init(&kvm->arch.sca_lock); 26728c2ecf20Sopenharmony_ci /* start with basic SCA */ 26738c2ecf20Sopenharmony_ci kvm->arch.sca = (struct bsca_block *) get_zeroed_page(alloc_flags); 26748c2ecf20Sopenharmony_ci if (!kvm->arch.sca) 26758c2ecf20Sopenharmony_ci goto out_err; 26768c2ecf20Sopenharmony_ci mutex_lock(&kvm_lock); 26778c2ecf20Sopenharmony_ci sca_offset += 16; 26788c2ecf20Sopenharmony_ci if (sca_offset + sizeof(struct bsca_block) > PAGE_SIZE) 26798c2ecf20Sopenharmony_ci sca_offset = 0; 26808c2ecf20Sopenharmony_ci kvm->arch.sca = (struct bsca_block *) 26818c2ecf20Sopenharmony_ci ((char *) kvm->arch.sca + sca_offset); 26828c2ecf20Sopenharmony_ci mutex_unlock(&kvm_lock); 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci sprintf(debug_name, "kvm-%u", current->pid); 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci kvm->arch.dbf = debug_register(debug_name, 32, 1, 7 * sizeof(long)); 26878c2ecf20Sopenharmony_ci if (!kvm->arch.dbf) 26888c2ecf20Sopenharmony_ci goto out_err; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sie_page2) != 4096); 26918c2ecf20Sopenharmony_ci kvm->arch.sie_page2 = 26928c2ecf20Sopenharmony_ci (struct sie_page2 *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 26938c2ecf20Sopenharmony_ci if (!kvm->arch.sie_page2) 26948c2ecf20Sopenharmony_ci goto out_err; 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci kvm->arch.sie_page2->kvm = kvm; 26978c2ecf20Sopenharmony_ci kvm->arch.model.fac_list = kvm->arch.sie_page2->fac_list; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci for (i = 0; i < kvm_s390_fac_size(); i++) { 27008c2ecf20Sopenharmony_ci kvm->arch.model.fac_mask[i] = S390_lowcore.stfle_fac_list[i] & 27018c2ecf20Sopenharmony_ci (kvm_s390_fac_base[i] | 27028c2ecf20Sopenharmony_ci kvm_s390_fac_ext[i]); 27038c2ecf20Sopenharmony_ci kvm->arch.model.fac_list[i] = S390_lowcore.stfle_fac_list[i] & 27048c2ecf20Sopenharmony_ci kvm_s390_fac_base[i]; 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci kvm->arch.model.subfuncs = kvm_s390_available_subfunc; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci /* we are always in czam mode - even on pre z14 machines */ 27098c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 138); 27108c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 138); 27118c2ecf20Sopenharmony_ci /* we emulate STHYI in kvm */ 27128c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 74); 27138c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 74); 27148c2ecf20Sopenharmony_ci if (MACHINE_HAS_TLB_GUEST) { 27158c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 147); 27168c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_list, 147); 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci if (css_general_characteristics.aiv && test_facility(65)) 27208c2ecf20Sopenharmony_ci set_kvm_facility(kvm->arch.model.fac_mask, 65); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci kvm->arch.model.cpuid = kvm_s390_get_initial_cpuid(); 27238c2ecf20Sopenharmony_ci kvm->arch.model.ibc = sclp.ibc & 0x0fff; 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci kvm_s390_crypto_init(kvm); 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci mutex_init(&kvm->arch.float_int.ais_lock); 27288c2ecf20Sopenharmony_ci spin_lock_init(&kvm->arch.float_int.lock); 27298c2ecf20Sopenharmony_ci for (i = 0; i < FIRQ_LIST_COUNT; i++) 27308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&kvm->arch.float_int.lists[i]); 27318c2ecf20Sopenharmony_ci init_waitqueue_head(&kvm->arch.ipte_wq); 27328c2ecf20Sopenharmony_ci mutex_init(&kvm->arch.ipte_mutex); 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci debug_register_view(kvm->arch.dbf, &debug_sprintf_view); 27358c2ecf20Sopenharmony_ci VM_EVENT(kvm, 3, "vm created with type %lu", type); 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci if (type & KVM_VM_S390_UCONTROL) { 27388c2ecf20Sopenharmony_ci kvm->arch.gmap = NULL; 27398c2ecf20Sopenharmony_ci kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT; 27408c2ecf20Sopenharmony_ci } else { 27418c2ecf20Sopenharmony_ci if (sclp.hamax == U64_MAX) 27428c2ecf20Sopenharmony_ci kvm->arch.mem_limit = TASK_SIZE_MAX; 27438c2ecf20Sopenharmony_ci else 27448c2ecf20Sopenharmony_ci kvm->arch.mem_limit = min_t(unsigned long, TASK_SIZE_MAX, 27458c2ecf20Sopenharmony_ci sclp.hamax + 1); 27468c2ecf20Sopenharmony_ci kvm->arch.gmap = gmap_create(current->mm, kvm->arch.mem_limit - 1); 27478c2ecf20Sopenharmony_ci if (!kvm->arch.gmap) 27488c2ecf20Sopenharmony_ci goto out_err; 27498c2ecf20Sopenharmony_ci kvm->arch.gmap->private = kvm; 27508c2ecf20Sopenharmony_ci kvm->arch.gmap->pfault_enabled = 0; 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci kvm->arch.use_pfmfi = sclp.has_pfmfi; 27548c2ecf20Sopenharmony_ci kvm->arch.use_skf = sclp.has_skey; 27558c2ecf20Sopenharmony_ci spin_lock_init(&kvm->arch.start_stop_lock); 27568c2ecf20Sopenharmony_ci kvm_s390_vsie_init(kvm); 27578c2ecf20Sopenharmony_ci if (use_gisa) 27588c2ecf20Sopenharmony_ci kvm_s390_gisa_init(kvm); 27598c2ecf20Sopenharmony_ci KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci return 0; 27628c2ecf20Sopenharmony_ciout_err: 27638c2ecf20Sopenharmony_ci free_page((unsigned long)kvm->arch.sie_page2); 27648c2ecf20Sopenharmony_ci debug_unregister(kvm->arch.dbf); 27658c2ecf20Sopenharmony_ci sca_dispose(kvm); 27668c2ecf20Sopenharmony_ci KVM_EVENT(3, "creation of vm failed: %d", rc); 27678c2ecf20Sopenharmony_ci return rc; 27688c2ecf20Sopenharmony_ci} 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_civoid kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci u16 rc, rrc; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "free cpu"); 27758c2ecf20Sopenharmony_ci trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id); 27768c2ecf20Sopenharmony_ci kvm_s390_clear_local_irqs(vcpu); 27778c2ecf20Sopenharmony_ci kvm_clear_async_pf_completion_queue(vcpu); 27788c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(vcpu->kvm)) 27798c2ecf20Sopenharmony_ci sca_del_vcpu(vcpu); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci if (kvm_is_ucontrol(vcpu->kvm)) 27828c2ecf20Sopenharmony_ci gmap_remove(vcpu->arch.gmap); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_cmma) 27858c2ecf20Sopenharmony_ci kvm_s390_vcpu_unsetup_cmma(vcpu); 27868c2ecf20Sopenharmony_ci /* We can not hold the vcpu mutex here, we are already dying */ 27878c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_get_handle(vcpu)) 27888c2ecf20Sopenharmony_ci kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc); 27898c2ecf20Sopenharmony_ci free_page((unsigned long)(vcpu->arch.sie_block)); 27908c2ecf20Sopenharmony_ci} 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_cistatic void kvm_free_vcpus(struct kvm *kvm) 27938c2ecf20Sopenharmony_ci{ 27948c2ecf20Sopenharmony_ci unsigned int i; 27958c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) 27988c2ecf20Sopenharmony_ci kvm_vcpu_destroy(vcpu); 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 28018c2ecf20Sopenharmony_ci for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) 28028c2ecf20Sopenharmony_ci kvm->vcpus[i] = NULL; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci atomic_set(&kvm->online_vcpus, 0); 28058c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 28068c2ecf20Sopenharmony_ci} 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_civoid kvm_arch_destroy_vm(struct kvm *kvm) 28098c2ecf20Sopenharmony_ci{ 28108c2ecf20Sopenharmony_ci u16 rc, rrc; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci kvm_free_vcpus(kvm); 28138c2ecf20Sopenharmony_ci sca_dispose(kvm); 28148c2ecf20Sopenharmony_ci kvm_s390_gisa_destroy(kvm); 28158c2ecf20Sopenharmony_ci /* 28168c2ecf20Sopenharmony_ci * We are already at the end of life and kvm->lock is not taken. 28178c2ecf20Sopenharmony_ci * This is ok as the file descriptor is closed by now and nobody 28188c2ecf20Sopenharmony_ci * can mess with the pv state. To avoid lockdep_assert_held from 28198c2ecf20Sopenharmony_ci * complaining we do not use kvm_s390_pv_is_protected. 28208c2ecf20Sopenharmony_ci */ 28218c2ecf20Sopenharmony_ci if (kvm_s390_pv_get_handle(kvm)) 28228c2ecf20Sopenharmony_ci kvm_s390_pv_deinit_vm(kvm, &rc, &rrc); 28238c2ecf20Sopenharmony_ci debug_unregister(kvm->arch.dbf); 28248c2ecf20Sopenharmony_ci free_page((unsigned long)kvm->arch.sie_page2); 28258c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(kvm)) 28268c2ecf20Sopenharmony_ci gmap_remove(kvm->arch.gmap); 28278c2ecf20Sopenharmony_ci kvm_s390_destroy_adapters(kvm); 28288c2ecf20Sopenharmony_ci kvm_s390_clear_float_irqs(kvm); 28298c2ecf20Sopenharmony_ci kvm_s390_vsie_destroy(kvm); 28308c2ecf20Sopenharmony_ci KVM_EVENT(3, "vm 0x%pK destroyed", kvm); 28318c2ecf20Sopenharmony_ci} 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci/* Section: vcpu related */ 28348c2ecf20Sopenharmony_cistatic int __kvm_ucontrol_vcpu_init(struct kvm_vcpu *vcpu) 28358c2ecf20Sopenharmony_ci{ 28368c2ecf20Sopenharmony_ci vcpu->arch.gmap = gmap_create(current->mm, -1UL); 28378c2ecf20Sopenharmony_ci if (!vcpu->arch.gmap) 28388c2ecf20Sopenharmony_ci return -ENOMEM; 28398c2ecf20Sopenharmony_ci vcpu->arch.gmap->private = vcpu->kvm; 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci return 0; 28428c2ecf20Sopenharmony_ci} 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_cistatic void sca_del_vcpu(struct kvm_vcpu *vcpu) 28458c2ecf20Sopenharmony_ci{ 28468c2ecf20Sopenharmony_ci if (!kvm_s390_use_sca_entries()) 28478c2ecf20Sopenharmony_ci return; 28488c2ecf20Sopenharmony_ci read_lock(&vcpu->kvm->arch.sca_lock); 28498c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_esca) { 28508c2ecf20Sopenharmony_ci struct esca_block *sca = vcpu->kvm->arch.sca; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci clear_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn); 28538c2ecf20Sopenharmony_ci sca->cpu[vcpu->vcpu_id].sda = 0; 28548c2ecf20Sopenharmony_ci } else { 28558c2ecf20Sopenharmony_ci struct bsca_block *sca = vcpu->kvm->arch.sca; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci clear_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn); 28588c2ecf20Sopenharmony_ci sca->cpu[vcpu->vcpu_id].sda = 0; 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci read_unlock(&vcpu->kvm->arch.sca_lock); 28618c2ecf20Sopenharmony_ci} 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_cistatic void sca_add_vcpu(struct kvm_vcpu *vcpu) 28648c2ecf20Sopenharmony_ci{ 28658c2ecf20Sopenharmony_ci if (!kvm_s390_use_sca_entries()) { 28668c2ecf20Sopenharmony_ci struct bsca_block *sca = vcpu->kvm->arch.sca; 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci /* we still need the basic sca for the ipte control */ 28698c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); 28708c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaol = (__u32)(__u64)sca; 28718c2ecf20Sopenharmony_ci return; 28728c2ecf20Sopenharmony_ci } 28738c2ecf20Sopenharmony_ci read_lock(&vcpu->kvm->arch.sca_lock); 28748c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_esca) { 28758c2ecf20Sopenharmony_ci struct esca_block *sca = vcpu->kvm->arch.sca; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block; 28788c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); 28798c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaol = (__u32)(__u64)sca & ~0x3fU; 28808c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 |= ECB2_ESCA; 28818c2ecf20Sopenharmony_ci set_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn); 28828c2ecf20Sopenharmony_ci } else { 28838c2ecf20Sopenharmony_ci struct bsca_block *sca = vcpu->kvm->arch.sca; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block; 28868c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); 28878c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaol = (__u32)(__u64)sca; 28888c2ecf20Sopenharmony_ci set_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn); 28898c2ecf20Sopenharmony_ci } 28908c2ecf20Sopenharmony_ci read_unlock(&vcpu->kvm->arch.sca_lock); 28918c2ecf20Sopenharmony_ci} 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci/* Basic SCA to Extended SCA data copy routines */ 28948c2ecf20Sopenharmony_cistatic inline void sca_copy_entry(struct esca_entry *d, struct bsca_entry *s) 28958c2ecf20Sopenharmony_ci{ 28968c2ecf20Sopenharmony_ci d->sda = s->sda; 28978c2ecf20Sopenharmony_ci d->sigp_ctrl.c = s->sigp_ctrl.c; 28988c2ecf20Sopenharmony_ci d->sigp_ctrl.scn = s->sigp_ctrl.scn; 28998c2ecf20Sopenharmony_ci} 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_cistatic void sca_copy_b_to_e(struct esca_block *d, struct bsca_block *s) 29028c2ecf20Sopenharmony_ci{ 29038c2ecf20Sopenharmony_ci int i; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci d->ipte_control = s->ipte_control; 29068c2ecf20Sopenharmony_ci d->mcn[0] = s->mcn; 29078c2ecf20Sopenharmony_ci for (i = 0; i < KVM_S390_BSCA_CPU_SLOTS; i++) 29088c2ecf20Sopenharmony_ci sca_copy_entry(&d->cpu[i], &s->cpu[i]); 29098c2ecf20Sopenharmony_ci} 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_cistatic int sca_switch_to_extended(struct kvm *kvm) 29128c2ecf20Sopenharmony_ci{ 29138c2ecf20Sopenharmony_ci struct bsca_block *old_sca = kvm->arch.sca; 29148c2ecf20Sopenharmony_ci struct esca_block *new_sca; 29158c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 29168c2ecf20Sopenharmony_ci unsigned int vcpu_idx; 29178c2ecf20Sopenharmony_ci u32 scaol, scaoh; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci if (kvm->arch.use_esca) 29208c2ecf20Sopenharmony_ci return 0; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci new_sca = alloc_pages_exact(sizeof(*new_sca), GFP_KERNEL|__GFP_ZERO); 29238c2ecf20Sopenharmony_ci if (!new_sca) 29248c2ecf20Sopenharmony_ci return -ENOMEM; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci scaoh = (u32)((u64)(new_sca) >> 32); 29278c2ecf20Sopenharmony_ci scaol = (u32)(u64)(new_sca) & ~0x3fU; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci kvm_s390_vcpu_block_all(kvm); 29308c2ecf20Sopenharmony_ci write_lock(&kvm->arch.sca_lock); 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci sca_copy_b_to_e(new_sca, old_sca); 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci kvm_for_each_vcpu(vcpu_idx, vcpu, kvm) { 29358c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaoh = scaoh; 29368c2ecf20Sopenharmony_ci vcpu->arch.sie_block->scaol = scaol; 29378c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 |= ECB2_ESCA; 29388c2ecf20Sopenharmony_ci } 29398c2ecf20Sopenharmony_ci kvm->arch.sca = new_sca; 29408c2ecf20Sopenharmony_ci kvm->arch.use_esca = 1; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci write_unlock(&kvm->arch.sca_lock); 29438c2ecf20Sopenharmony_ci kvm_s390_vcpu_unblock_all(kvm); 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci free_page((unsigned long)old_sca); 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci VM_EVENT(kvm, 2, "Switched to ESCA (0x%pK -> 0x%pK)", 29488c2ecf20Sopenharmony_ci old_sca, kvm->arch.sca); 29498c2ecf20Sopenharmony_ci return 0; 29508c2ecf20Sopenharmony_ci} 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_cistatic int sca_can_add_vcpu(struct kvm *kvm, unsigned int id) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci int rc; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci if (!kvm_s390_use_sca_entries()) { 29578c2ecf20Sopenharmony_ci if (id < KVM_MAX_VCPUS) 29588c2ecf20Sopenharmony_ci return true; 29598c2ecf20Sopenharmony_ci return false; 29608c2ecf20Sopenharmony_ci } 29618c2ecf20Sopenharmony_ci if (id < KVM_S390_BSCA_CPU_SLOTS) 29628c2ecf20Sopenharmony_ci return true; 29638c2ecf20Sopenharmony_ci if (!sclp.has_esca || !sclp.has_64bscao) 29648c2ecf20Sopenharmony_ci return false; 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 29678c2ecf20Sopenharmony_ci rc = kvm->arch.use_esca ? 0 : sca_switch_to_extended(kvm); 29688c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS; 29718c2ecf20Sopenharmony_ci} 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ 29748c2ecf20Sopenharmony_cistatic void __start_cpu_timer_accounting(struct kvm_vcpu *vcpu) 29758c2ecf20Sopenharmony_ci{ 29768c2ecf20Sopenharmony_ci WARN_ON_ONCE(vcpu->arch.cputm_start != 0); 29778c2ecf20Sopenharmony_ci raw_write_seqcount_begin(&vcpu->arch.cputm_seqcount); 29788c2ecf20Sopenharmony_ci vcpu->arch.cputm_start = get_tod_clock_fast(); 29798c2ecf20Sopenharmony_ci raw_write_seqcount_end(&vcpu->arch.cputm_seqcount); 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ 29838c2ecf20Sopenharmony_cistatic void __stop_cpu_timer_accounting(struct kvm_vcpu *vcpu) 29848c2ecf20Sopenharmony_ci{ 29858c2ecf20Sopenharmony_ci WARN_ON_ONCE(vcpu->arch.cputm_start == 0); 29868c2ecf20Sopenharmony_ci raw_write_seqcount_begin(&vcpu->arch.cputm_seqcount); 29878c2ecf20Sopenharmony_ci vcpu->arch.sie_block->cputm -= get_tod_clock_fast() - vcpu->arch.cputm_start; 29888c2ecf20Sopenharmony_ci vcpu->arch.cputm_start = 0; 29898c2ecf20Sopenharmony_ci raw_write_seqcount_end(&vcpu->arch.cputm_seqcount); 29908c2ecf20Sopenharmony_ci} 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ 29938c2ecf20Sopenharmony_cistatic void __enable_cpu_timer_accounting(struct kvm_vcpu *vcpu) 29948c2ecf20Sopenharmony_ci{ 29958c2ecf20Sopenharmony_ci WARN_ON_ONCE(vcpu->arch.cputm_enabled); 29968c2ecf20Sopenharmony_ci vcpu->arch.cputm_enabled = true; 29978c2ecf20Sopenharmony_ci __start_cpu_timer_accounting(vcpu); 29988c2ecf20Sopenharmony_ci} 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ 30018c2ecf20Sopenharmony_cistatic void __disable_cpu_timer_accounting(struct kvm_vcpu *vcpu) 30028c2ecf20Sopenharmony_ci{ 30038c2ecf20Sopenharmony_ci WARN_ON_ONCE(!vcpu->arch.cputm_enabled); 30048c2ecf20Sopenharmony_ci __stop_cpu_timer_accounting(vcpu); 30058c2ecf20Sopenharmony_ci vcpu->arch.cputm_enabled = false; 30068c2ecf20Sopenharmony_ci} 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_cistatic void enable_cpu_timer_accounting(struct kvm_vcpu *vcpu) 30098c2ecf20Sopenharmony_ci{ 30108c2ecf20Sopenharmony_ci preempt_disable(); /* protect from TOD sync and vcpu_load/put */ 30118c2ecf20Sopenharmony_ci __enable_cpu_timer_accounting(vcpu); 30128c2ecf20Sopenharmony_ci preempt_enable(); 30138c2ecf20Sopenharmony_ci} 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_cistatic void disable_cpu_timer_accounting(struct kvm_vcpu *vcpu) 30168c2ecf20Sopenharmony_ci{ 30178c2ecf20Sopenharmony_ci preempt_disable(); /* protect from TOD sync and vcpu_load/put */ 30188c2ecf20Sopenharmony_ci __disable_cpu_timer_accounting(vcpu); 30198c2ecf20Sopenharmony_ci preempt_enable(); 30208c2ecf20Sopenharmony_ci} 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci/* set the cpu timer - may only be called from the VCPU thread itself */ 30238c2ecf20Sopenharmony_civoid kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci preempt_disable(); /* protect from TOD sync and vcpu_load/put */ 30268c2ecf20Sopenharmony_ci raw_write_seqcount_begin(&vcpu->arch.cputm_seqcount); 30278c2ecf20Sopenharmony_ci if (vcpu->arch.cputm_enabled) 30288c2ecf20Sopenharmony_ci vcpu->arch.cputm_start = get_tod_clock_fast(); 30298c2ecf20Sopenharmony_ci vcpu->arch.sie_block->cputm = cputm; 30308c2ecf20Sopenharmony_ci raw_write_seqcount_end(&vcpu->arch.cputm_seqcount); 30318c2ecf20Sopenharmony_ci preempt_enable(); 30328c2ecf20Sopenharmony_ci} 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci/* update and get the cpu timer - can also be called from other VCPU threads */ 30358c2ecf20Sopenharmony_ci__u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu) 30368c2ecf20Sopenharmony_ci{ 30378c2ecf20Sopenharmony_ci unsigned int seq; 30388c2ecf20Sopenharmony_ci __u64 value; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci if (unlikely(!vcpu->arch.cputm_enabled)) 30418c2ecf20Sopenharmony_ci return vcpu->arch.sie_block->cputm; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci preempt_disable(); /* protect from TOD sync and vcpu_load/put */ 30448c2ecf20Sopenharmony_ci do { 30458c2ecf20Sopenharmony_ci seq = raw_read_seqcount(&vcpu->arch.cputm_seqcount); 30468c2ecf20Sopenharmony_ci /* 30478c2ecf20Sopenharmony_ci * If the writer would ever execute a read in the critical 30488c2ecf20Sopenharmony_ci * section, e.g. in irq context, we have a deadlock. 30498c2ecf20Sopenharmony_ci */ 30508c2ecf20Sopenharmony_ci WARN_ON_ONCE((seq & 1) && smp_processor_id() == vcpu->cpu); 30518c2ecf20Sopenharmony_ci value = vcpu->arch.sie_block->cputm; 30528c2ecf20Sopenharmony_ci /* if cputm_start is 0, accounting is being started/stopped */ 30538c2ecf20Sopenharmony_ci if (likely(vcpu->arch.cputm_start)) 30548c2ecf20Sopenharmony_ci value -= get_tod_clock_fast() - vcpu->arch.cputm_start; 30558c2ecf20Sopenharmony_ci } while (read_seqcount_retry(&vcpu->arch.cputm_seqcount, seq & ~1)); 30568c2ecf20Sopenharmony_ci preempt_enable(); 30578c2ecf20Sopenharmony_ci return value; 30588c2ecf20Sopenharmony_ci} 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_civoid kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 30618c2ecf20Sopenharmony_ci{ 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci gmap_enable(vcpu->arch.enabled_gmap); 30648c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_RUNNING); 30658c2ecf20Sopenharmony_ci if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu)) 30668c2ecf20Sopenharmony_ci __start_cpu_timer_accounting(vcpu); 30678c2ecf20Sopenharmony_ci vcpu->cpu = cpu; 30688c2ecf20Sopenharmony_ci} 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_civoid kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 30718c2ecf20Sopenharmony_ci{ 30728c2ecf20Sopenharmony_ci vcpu->cpu = -1; 30738c2ecf20Sopenharmony_ci if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu)) 30748c2ecf20Sopenharmony_ci __stop_cpu_timer_accounting(vcpu); 30758c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_RUNNING); 30768c2ecf20Sopenharmony_ci vcpu->arch.enabled_gmap = gmap_get_enabled(); 30778c2ecf20Sopenharmony_ci gmap_disable(vcpu->arch.enabled_gmap); 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci} 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_civoid kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) 30828c2ecf20Sopenharmony_ci{ 30838c2ecf20Sopenharmony_ci mutex_lock(&vcpu->kvm->lock); 30848c2ecf20Sopenharmony_ci preempt_disable(); 30858c2ecf20Sopenharmony_ci vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch; 30868c2ecf20Sopenharmony_ci vcpu->arch.sie_block->epdx = vcpu->kvm->arch.epdx; 30878c2ecf20Sopenharmony_ci preempt_enable(); 30888c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->kvm->lock); 30898c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(vcpu->kvm)) { 30908c2ecf20Sopenharmony_ci vcpu->arch.gmap = vcpu->kvm->arch.gmap; 30918c2ecf20Sopenharmony_ci sca_add_vcpu(vcpu); 30928c2ecf20Sopenharmony_ci } 30938c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0) 30948c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl |= ICTL_OPEREXC; 30958c2ecf20Sopenharmony_ci /* make vcpu_load load the right gmap on the first trigger */ 30968c2ecf20Sopenharmony_ci vcpu->arch.enabled_gmap = vcpu->arch.gmap; 30978c2ecf20Sopenharmony_ci} 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_cistatic bool kvm_has_pckmo_subfunc(struct kvm *kvm, unsigned long nr) 31008c2ecf20Sopenharmony_ci{ 31018c2ecf20Sopenharmony_ci if (test_bit_inv(nr, (unsigned long *)&kvm->arch.model.subfuncs.pckmo) && 31028c2ecf20Sopenharmony_ci test_bit_inv(nr, (unsigned long *)&kvm_s390_available_subfunc.pckmo)) 31038c2ecf20Sopenharmony_ci return true; 31048c2ecf20Sopenharmony_ci return false; 31058c2ecf20Sopenharmony_ci} 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_cistatic bool kvm_has_pckmo_ecc(struct kvm *kvm) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci /* At least one ECC subfunction must be present */ 31108c2ecf20Sopenharmony_ci return kvm_has_pckmo_subfunc(kvm, 32) || 31118c2ecf20Sopenharmony_ci kvm_has_pckmo_subfunc(kvm, 33) || 31128c2ecf20Sopenharmony_ci kvm_has_pckmo_subfunc(kvm, 34) || 31138c2ecf20Sopenharmony_ci kvm_has_pckmo_subfunc(kvm, 40) || 31148c2ecf20Sopenharmony_ci kvm_has_pckmo_subfunc(kvm, 41); 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci} 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_cistatic void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu) 31198c2ecf20Sopenharmony_ci{ 31208c2ecf20Sopenharmony_ci /* 31218c2ecf20Sopenharmony_ci * If the AP instructions are not being interpreted and the MSAX3 31228c2ecf20Sopenharmony_ci * facility is not configured for the guest, there is nothing to set up. 31238c2ecf20Sopenharmony_ci */ 31248c2ecf20Sopenharmony_ci if (!vcpu->kvm->arch.crypto.apie && !test_kvm_facility(vcpu->kvm, 76)) 31258c2ecf20Sopenharmony_ci return; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd; 31288c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb3 &= ~(ECB3_AES | ECB3_DEA); 31298c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca &= ~ECA_APIE; 31308c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd &= ~ECD_ECC; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.crypto.apie) 31338c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_APIE; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci /* Set up protected key support */ 31368c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.crypto.aes_kw) { 31378c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb3 |= ECB3_AES; 31388c2ecf20Sopenharmony_ci /* ecc is also wrapped with AES key */ 31398c2ecf20Sopenharmony_ci if (kvm_has_pckmo_ecc(vcpu->kvm)) 31408c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd |= ECD_ECC; 31418c2ecf20Sopenharmony_ci } 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.crypto.dea_kw) 31448c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb3 |= ECB3_DEA; 31458c2ecf20Sopenharmony_ci} 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_civoid kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu) 31488c2ecf20Sopenharmony_ci{ 31498c2ecf20Sopenharmony_ci free_page(vcpu->arch.sie_block->cbrlo); 31508c2ecf20Sopenharmony_ci vcpu->arch.sie_block->cbrlo = 0; 31518c2ecf20Sopenharmony_ci} 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ciint kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu) 31548c2ecf20Sopenharmony_ci{ 31558c2ecf20Sopenharmony_ci vcpu->arch.sie_block->cbrlo = get_zeroed_page(GFP_KERNEL); 31568c2ecf20Sopenharmony_ci if (!vcpu->arch.sie_block->cbrlo) 31578c2ecf20Sopenharmony_ci return -ENOMEM; 31588c2ecf20Sopenharmony_ci return 0; 31598c2ecf20Sopenharmony_ci} 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_cistatic void kvm_s390_vcpu_setup_model(struct kvm_vcpu *vcpu) 31628c2ecf20Sopenharmony_ci{ 31638c2ecf20Sopenharmony_ci struct kvm_s390_cpu_model *model = &vcpu->kvm->arch.model; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ibc = model->ibc; 31668c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 7)) 31678c2ecf20Sopenharmony_ci vcpu->arch.sie_block->fac = (u32)(u64) model->fac_list; 31688c2ecf20Sopenharmony_ci} 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_cistatic int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu) 31718c2ecf20Sopenharmony_ci{ 31728c2ecf20Sopenharmony_ci int rc = 0; 31738c2ecf20Sopenharmony_ci u16 uvrc, uvrrc; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | 31768c2ecf20Sopenharmony_ci CPUSTAT_SM | 31778c2ecf20Sopenharmony_ci CPUSTAT_STOPPED); 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 78)) 31808c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_GED2); 31818c2ecf20Sopenharmony_ci else if (test_kvm_facility(vcpu->kvm, 8)) 31828c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_GED); 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci kvm_s390_vcpu_setup_model(vcpu); 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci /* pgste_set_pte has special handling for !MACHINE_HAS_ESOP */ 31878c2ecf20Sopenharmony_ci if (MACHINE_HAS_ESOP) 31888c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb |= ECB_HOSTPROTINT; 31898c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 9)) 31908c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb |= ECB_SRSI; 31918c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 73)) 31928c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb |= ECB_TE; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 8) && vcpu->kvm->arch.use_pfmfi) 31958c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 |= ECB2_PFMFI; 31968c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 130)) 31978c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 |= ECB2_IEP; 31988c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca = ECA_MVPGI | ECA_PROTEXCI; 31998c2ecf20Sopenharmony_ci if (sclp.has_cei) 32008c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_CEI; 32018c2ecf20Sopenharmony_ci if (sclp.has_ib) 32028c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_IB; 32038c2ecf20Sopenharmony_ci if (sclp.has_siif) 32048c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_SII; 32058c2ecf20Sopenharmony_ci if (sclp.has_sigpif) 32068c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_SIGPI; 32078c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 129)) { 32088c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_VX; 32098c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT; 32108c2ecf20Sopenharmony_ci } 32118c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 139)) 32128c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd |= ECD_MEF; 32138c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 156)) 32148c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd |= ECD_ETOKENF; 32158c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gd) { 32168c2ecf20Sopenharmony_ci vcpu->arch.sie_block->eca |= ECA_AIV; 32178c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "AIV gisa format-%u enabled for cpu %03u", 32188c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gd & 0x3, vcpu->vcpu_id); 32198c2ecf20Sopenharmony_ci } 32208c2ecf20Sopenharmony_ci vcpu->arch.sie_block->sdnxo = ((unsigned long) &vcpu->run->s.regs.sdnx) 32218c2ecf20Sopenharmony_ci | SDNXC; 32228c2ecf20Sopenharmony_ci vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb; 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci if (sclp.has_kss) 32258c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_KSS); 32268c2ecf20Sopenharmony_ci else 32278c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE; 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.use_cmma) { 32308c2ecf20Sopenharmony_ci rc = kvm_s390_vcpu_setup_cmma(vcpu); 32318c2ecf20Sopenharmony_ci if (rc) 32328c2ecf20Sopenharmony_ci return rc; 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 32358c2ecf20Sopenharmony_ci vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci vcpu->arch.sie_block->hpid = HPID_KVM; 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci kvm_s390_vcpu_crypto_setup(vcpu); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci mutex_lock(&vcpu->kvm->lock); 32428c2ecf20Sopenharmony_ci if (kvm_s390_pv_is_protected(vcpu->kvm)) { 32438c2ecf20Sopenharmony_ci rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc); 32448c2ecf20Sopenharmony_ci if (rc) 32458c2ecf20Sopenharmony_ci kvm_s390_vcpu_unsetup_cmma(vcpu); 32468c2ecf20Sopenharmony_ci } 32478c2ecf20Sopenharmony_ci mutex_unlock(&vcpu->kvm->lock); 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci return rc; 32508c2ecf20Sopenharmony_ci} 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ciint kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) 32538c2ecf20Sopenharmony_ci{ 32548c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(kvm) && !sca_can_add_vcpu(kvm, id)) 32558c2ecf20Sopenharmony_ci return -EINVAL; 32568c2ecf20Sopenharmony_ci return 0; 32578c2ecf20Sopenharmony_ci} 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ciint kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) 32608c2ecf20Sopenharmony_ci{ 32618c2ecf20Sopenharmony_ci struct sie_page *sie_page; 32628c2ecf20Sopenharmony_ci int rc; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sie_page) != 4096); 32658c2ecf20Sopenharmony_ci sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL); 32668c2ecf20Sopenharmony_ci if (!sie_page) 32678c2ecf20Sopenharmony_ci return -ENOMEM; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci vcpu->arch.sie_block = &sie_page->sie_block; 32708c2ecf20Sopenharmony_ci vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb; 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci /* the real guest size will always be smaller than msl */ 32738c2ecf20Sopenharmony_ci vcpu->arch.sie_block->mso = 0; 32748c2ecf20Sopenharmony_ci vcpu->arch.sie_block->msl = sclp.hamax; 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci vcpu->arch.sie_block->icpua = vcpu->vcpu_id; 32778c2ecf20Sopenharmony_ci spin_lock_init(&vcpu->arch.local_int.lock); 32788c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gd = (u32)(u64)vcpu->kvm->arch.gisa_int.origin; 32798c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->gd && sclp.has_gisaf) 32808c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gd |= GISA_FORMAT1; 32818c2ecf20Sopenharmony_ci seqcount_init(&vcpu->arch.cputm_seqcount); 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; 32848c2ecf20Sopenharmony_ci kvm_clear_async_pf_completion_queue(vcpu); 32858c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX | 32868c2ecf20Sopenharmony_ci KVM_SYNC_GPRS | 32878c2ecf20Sopenharmony_ci KVM_SYNC_ACRS | 32888c2ecf20Sopenharmony_ci KVM_SYNC_CRS | 32898c2ecf20Sopenharmony_ci KVM_SYNC_ARCH0 | 32908c2ecf20Sopenharmony_ci KVM_SYNC_PFAULT | 32918c2ecf20Sopenharmony_ci KVM_SYNC_DIAG318; 32928c2ecf20Sopenharmony_ci kvm_s390_set_prefix(vcpu, 0); 32938c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 64)) 32948c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB; 32958c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 82)) 32968c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC; 32978c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 133)) 32988c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB; 32998c2ecf20Sopenharmony_ci if (test_kvm_facility(vcpu->kvm, 156)) 33008c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs |= KVM_SYNC_ETOKEN; 33018c2ecf20Sopenharmony_ci /* fprs can be synchronized via vrs, even if the guest has no vx. With 33028c2ecf20Sopenharmony_ci * MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format. 33038c2ecf20Sopenharmony_ci */ 33048c2ecf20Sopenharmony_ci if (MACHINE_HAS_VX) 33058c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS; 33068c2ecf20Sopenharmony_ci else 33078c2ecf20Sopenharmony_ci vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci if (kvm_is_ucontrol(vcpu->kvm)) { 33108c2ecf20Sopenharmony_ci rc = __kvm_ucontrol_vcpu_init(vcpu); 33118c2ecf20Sopenharmony_ci if (rc) 33128c2ecf20Sopenharmony_ci goto out_free_sie_block; 33138c2ecf20Sopenharmony_ci } 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", 33168c2ecf20Sopenharmony_ci vcpu->vcpu_id, vcpu, vcpu->arch.sie_block); 33178c2ecf20Sopenharmony_ci trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block); 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci rc = kvm_s390_vcpu_setup(vcpu); 33208c2ecf20Sopenharmony_ci if (rc) 33218c2ecf20Sopenharmony_ci goto out_ucontrol_uninit; 33228c2ecf20Sopenharmony_ci return 0; 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ciout_ucontrol_uninit: 33258c2ecf20Sopenharmony_ci if (kvm_is_ucontrol(vcpu->kvm)) 33268c2ecf20Sopenharmony_ci gmap_remove(vcpu->arch.gmap); 33278c2ecf20Sopenharmony_ciout_free_sie_block: 33288c2ecf20Sopenharmony_ci free_page((unsigned long)(vcpu->arch.sie_block)); 33298c2ecf20Sopenharmony_ci return rc; 33308c2ecf20Sopenharmony_ci} 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ciint kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) 33338c2ecf20Sopenharmony_ci{ 33348c2ecf20Sopenharmony_ci clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.gisa_int.kicked_mask); 33358c2ecf20Sopenharmony_ci return kvm_s390_vcpu_has_irq(vcpu, 0); 33368c2ecf20Sopenharmony_ci} 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_cibool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) 33398c2ecf20Sopenharmony_ci{ 33408c2ecf20Sopenharmony_ci return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE); 33418c2ecf20Sopenharmony_ci} 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_civoid kvm_s390_vcpu_block(struct kvm_vcpu *vcpu) 33448c2ecf20Sopenharmony_ci{ 33458c2ecf20Sopenharmony_ci atomic_or(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); 33468c2ecf20Sopenharmony_ci exit_sie(vcpu); 33478c2ecf20Sopenharmony_ci} 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_civoid kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu) 33508c2ecf20Sopenharmony_ci{ 33518c2ecf20Sopenharmony_ci atomic_andnot(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); 33528c2ecf20Sopenharmony_ci} 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_cistatic void kvm_s390_vcpu_request(struct kvm_vcpu *vcpu) 33558c2ecf20Sopenharmony_ci{ 33568c2ecf20Sopenharmony_ci atomic_or(PROG_REQUEST, &vcpu->arch.sie_block->prog20); 33578c2ecf20Sopenharmony_ci exit_sie(vcpu); 33588c2ecf20Sopenharmony_ci} 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_cibool kvm_s390_vcpu_sie_inhibited(struct kvm_vcpu *vcpu) 33618c2ecf20Sopenharmony_ci{ 33628c2ecf20Sopenharmony_ci return atomic_read(&vcpu->arch.sie_block->prog20) & 33638c2ecf20Sopenharmony_ci (PROG_BLOCK_SIE | PROG_REQUEST); 33648c2ecf20Sopenharmony_ci} 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_cistatic void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) 33678c2ecf20Sopenharmony_ci{ 33688c2ecf20Sopenharmony_ci atomic_andnot(PROG_REQUEST, &vcpu->arch.sie_block->prog20); 33698c2ecf20Sopenharmony_ci} 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci/* 33728c2ecf20Sopenharmony_ci * Kick a guest cpu out of (v)SIE and wait until (v)SIE is not running. 33738c2ecf20Sopenharmony_ci * If the CPU is not running (e.g. waiting as idle) the function will 33748c2ecf20Sopenharmony_ci * return immediately. */ 33758c2ecf20Sopenharmony_civoid exit_sie(struct kvm_vcpu *vcpu) 33768c2ecf20Sopenharmony_ci{ 33778c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOP_INT); 33788c2ecf20Sopenharmony_ci kvm_s390_vsie_kick(vcpu); 33798c2ecf20Sopenharmony_ci while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE) 33808c2ecf20Sopenharmony_ci cpu_relax(); 33818c2ecf20Sopenharmony_ci} 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci/* Kick a guest cpu out of SIE to process a request synchronously */ 33848c2ecf20Sopenharmony_civoid kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu) 33858c2ecf20Sopenharmony_ci{ 33868c2ecf20Sopenharmony_ci kvm_make_request(req, vcpu); 33878c2ecf20Sopenharmony_ci kvm_s390_vcpu_request(vcpu); 33888c2ecf20Sopenharmony_ci} 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_cistatic void kvm_gmap_notifier(struct gmap *gmap, unsigned long start, 33918c2ecf20Sopenharmony_ci unsigned long end) 33928c2ecf20Sopenharmony_ci{ 33938c2ecf20Sopenharmony_ci struct kvm *kvm = gmap->private; 33948c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 33958c2ecf20Sopenharmony_ci unsigned long prefix; 33968c2ecf20Sopenharmony_ci int i; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci if (gmap_is_shadow(gmap)) 33998c2ecf20Sopenharmony_ci return; 34008c2ecf20Sopenharmony_ci if (start >= 1UL << 31) 34018c2ecf20Sopenharmony_ci /* We are only interested in prefix pages */ 34028c2ecf20Sopenharmony_ci return; 34038c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 34048c2ecf20Sopenharmony_ci /* match against both prefix pages */ 34058c2ecf20Sopenharmony_ci prefix = kvm_s390_get_prefix(vcpu); 34068c2ecf20Sopenharmony_ci if (prefix <= end && start <= prefix + 2*PAGE_SIZE - 1) { 34078c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 2, "gmap notifier for %lx-%lx", 34088c2ecf20Sopenharmony_ci start, end); 34098c2ecf20Sopenharmony_ci kvm_s390_sync_request(KVM_REQ_MMU_RELOAD, vcpu); 34108c2ecf20Sopenharmony_ci } 34118c2ecf20Sopenharmony_ci } 34128c2ecf20Sopenharmony_ci} 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_cibool kvm_arch_no_poll(struct kvm_vcpu *vcpu) 34158c2ecf20Sopenharmony_ci{ 34168c2ecf20Sopenharmony_ci /* do not poll with more than halt_poll_max_steal percent of steal time */ 34178c2ecf20Sopenharmony_ci if (S390_lowcore.avg_steal_timer * 100 / (TICK_USEC << 12) >= 34188c2ecf20Sopenharmony_ci halt_poll_max_steal) { 34198c2ecf20Sopenharmony_ci vcpu->stat.halt_no_poll_steal++; 34208c2ecf20Sopenharmony_ci return true; 34218c2ecf20Sopenharmony_ci } 34228c2ecf20Sopenharmony_ci return false; 34238c2ecf20Sopenharmony_ci} 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ciint kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) 34268c2ecf20Sopenharmony_ci{ 34278c2ecf20Sopenharmony_ci /* kvm common code refers to this, but never calls it */ 34288c2ecf20Sopenharmony_ci BUG(); 34298c2ecf20Sopenharmony_ci return 0; 34308c2ecf20Sopenharmony_ci} 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_cistatic int kvm_arch_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, 34338c2ecf20Sopenharmony_ci struct kvm_one_reg *reg) 34348c2ecf20Sopenharmony_ci{ 34358c2ecf20Sopenharmony_ci int r = -EINVAL; 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci switch (reg->id) { 34388c2ecf20Sopenharmony_ci case KVM_REG_S390_TODPR: 34398c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.sie_block->todpr, 34408c2ecf20Sopenharmony_ci (u32 __user *)reg->addr); 34418c2ecf20Sopenharmony_ci break; 34428c2ecf20Sopenharmony_ci case KVM_REG_S390_EPOCHDIFF: 34438c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.sie_block->epoch, 34448c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34458c2ecf20Sopenharmony_ci break; 34468c2ecf20Sopenharmony_ci case KVM_REG_S390_CPU_TIMER: 34478c2ecf20Sopenharmony_ci r = put_user(kvm_s390_get_cpu_timer(vcpu), 34488c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34498c2ecf20Sopenharmony_ci break; 34508c2ecf20Sopenharmony_ci case KVM_REG_S390_CLOCK_COMP: 34518c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.sie_block->ckc, 34528c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34538c2ecf20Sopenharmony_ci break; 34548c2ecf20Sopenharmony_ci case KVM_REG_S390_PFTOKEN: 34558c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.pfault_token, 34568c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34578c2ecf20Sopenharmony_ci break; 34588c2ecf20Sopenharmony_ci case KVM_REG_S390_PFCOMPARE: 34598c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.pfault_compare, 34608c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34618c2ecf20Sopenharmony_ci break; 34628c2ecf20Sopenharmony_ci case KVM_REG_S390_PFSELECT: 34638c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.pfault_select, 34648c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34658c2ecf20Sopenharmony_ci break; 34668c2ecf20Sopenharmony_ci case KVM_REG_S390_PP: 34678c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.sie_block->pp, 34688c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34698c2ecf20Sopenharmony_ci break; 34708c2ecf20Sopenharmony_ci case KVM_REG_S390_GBEA: 34718c2ecf20Sopenharmony_ci r = put_user(vcpu->arch.sie_block->gbea, 34728c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34738c2ecf20Sopenharmony_ci break; 34748c2ecf20Sopenharmony_ci default: 34758c2ecf20Sopenharmony_ci break; 34768c2ecf20Sopenharmony_ci } 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci return r; 34798c2ecf20Sopenharmony_ci} 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_cistatic int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, 34828c2ecf20Sopenharmony_ci struct kvm_one_reg *reg) 34838c2ecf20Sopenharmony_ci{ 34848c2ecf20Sopenharmony_ci int r = -EINVAL; 34858c2ecf20Sopenharmony_ci __u64 val; 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci switch (reg->id) { 34888c2ecf20Sopenharmony_ci case KVM_REG_S390_TODPR: 34898c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.sie_block->todpr, 34908c2ecf20Sopenharmony_ci (u32 __user *)reg->addr); 34918c2ecf20Sopenharmony_ci break; 34928c2ecf20Sopenharmony_ci case KVM_REG_S390_EPOCHDIFF: 34938c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.sie_block->epoch, 34948c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 34958c2ecf20Sopenharmony_ci break; 34968c2ecf20Sopenharmony_ci case KVM_REG_S390_CPU_TIMER: 34978c2ecf20Sopenharmony_ci r = get_user(val, (u64 __user *)reg->addr); 34988c2ecf20Sopenharmony_ci if (!r) 34998c2ecf20Sopenharmony_ci kvm_s390_set_cpu_timer(vcpu, val); 35008c2ecf20Sopenharmony_ci break; 35018c2ecf20Sopenharmony_ci case KVM_REG_S390_CLOCK_COMP: 35028c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.sie_block->ckc, 35038c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 35048c2ecf20Sopenharmony_ci break; 35058c2ecf20Sopenharmony_ci case KVM_REG_S390_PFTOKEN: 35068c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.pfault_token, 35078c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 35088c2ecf20Sopenharmony_ci if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID) 35098c2ecf20Sopenharmony_ci kvm_clear_async_pf_completion_queue(vcpu); 35108c2ecf20Sopenharmony_ci break; 35118c2ecf20Sopenharmony_ci case KVM_REG_S390_PFCOMPARE: 35128c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.pfault_compare, 35138c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 35148c2ecf20Sopenharmony_ci break; 35158c2ecf20Sopenharmony_ci case KVM_REG_S390_PFSELECT: 35168c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.pfault_select, 35178c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 35188c2ecf20Sopenharmony_ci break; 35198c2ecf20Sopenharmony_ci case KVM_REG_S390_PP: 35208c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.sie_block->pp, 35218c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 35228c2ecf20Sopenharmony_ci break; 35238c2ecf20Sopenharmony_ci case KVM_REG_S390_GBEA: 35248c2ecf20Sopenharmony_ci r = get_user(vcpu->arch.sie_block->gbea, 35258c2ecf20Sopenharmony_ci (u64 __user *)reg->addr); 35268c2ecf20Sopenharmony_ci break; 35278c2ecf20Sopenharmony_ci default: 35288c2ecf20Sopenharmony_ci break; 35298c2ecf20Sopenharmony_ci } 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci return r; 35328c2ecf20Sopenharmony_ci} 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_cistatic void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu) 35358c2ecf20Sopenharmony_ci{ 35368c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI; 35378c2ecf20Sopenharmony_ci vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; 35388c2ecf20Sopenharmony_ci memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb)); 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci kvm_clear_async_pf_completion_queue(vcpu); 35418c2ecf20Sopenharmony_ci if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) 35428c2ecf20Sopenharmony_ci kvm_s390_vcpu_stop(vcpu); 35438c2ecf20Sopenharmony_ci kvm_s390_clear_local_irqs(vcpu); 35448c2ecf20Sopenharmony_ci} 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_cistatic void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) 35478c2ecf20Sopenharmony_ci{ 35488c2ecf20Sopenharmony_ci /* Initial reset is a superset of the normal reset */ 35498c2ecf20Sopenharmony_ci kvm_arch_vcpu_ioctl_normal_reset(vcpu); 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci /* 35528c2ecf20Sopenharmony_ci * This equals initial cpu reset in pop, but we don't switch to ESA. 35538c2ecf20Sopenharmony_ci * We do not only reset the internal data, but also ... 35548c2ecf20Sopenharmony_ci */ 35558c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask = 0; 35568c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.addr = 0; 35578c2ecf20Sopenharmony_ci kvm_s390_set_prefix(vcpu, 0); 35588c2ecf20Sopenharmony_ci kvm_s390_set_cpu_timer(vcpu, 0); 35598c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ckc = 0; 35608c2ecf20Sopenharmony_ci memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr)); 35618c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK; 35628c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci /* ... the data in sync regs */ 35658c2ecf20Sopenharmony_ci memset(vcpu->run->s.regs.crs, 0, sizeof(vcpu->run->s.regs.crs)); 35668c2ecf20Sopenharmony_ci vcpu->run->s.regs.ckc = 0; 35678c2ecf20Sopenharmony_ci vcpu->run->s.regs.crs[0] = CR0_INITIAL_MASK; 35688c2ecf20Sopenharmony_ci vcpu->run->s.regs.crs[14] = CR14_INITIAL_MASK; 35698c2ecf20Sopenharmony_ci vcpu->run->psw_addr = 0; 35708c2ecf20Sopenharmony_ci vcpu->run->psw_mask = 0; 35718c2ecf20Sopenharmony_ci vcpu->run->s.regs.todpr = 0; 35728c2ecf20Sopenharmony_ci vcpu->run->s.regs.cputm = 0; 35738c2ecf20Sopenharmony_ci vcpu->run->s.regs.ckc = 0; 35748c2ecf20Sopenharmony_ci vcpu->run->s.regs.pp = 0; 35758c2ecf20Sopenharmony_ci vcpu->run->s.regs.gbea = 1; 35768c2ecf20Sopenharmony_ci vcpu->run->s.regs.fpc = 0; 35778c2ecf20Sopenharmony_ci /* 35788c2ecf20Sopenharmony_ci * Do not reset these registers in the protected case, as some of 35798c2ecf20Sopenharmony_ci * them are overlayed and they are not accessible in this case 35808c2ecf20Sopenharmony_ci * anyway. 35818c2ecf20Sopenharmony_ci */ 35828c2ecf20Sopenharmony_ci if (!kvm_s390_pv_cpu_is_protected(vcpu)) { 35838c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gbea = 1; 35848c2ecf20Sopenharmony_ci vcpu->arch.sie_block->pp = 0; 35858c2ecf20Sopenharmony_ci vcpu->arch.sie_block->fpf &= ~FPF_BPBC; 35868c2ecf20Sopenharmony_ci vcpu->arch.sie_block->todpr = 0; 35878c2ecf20Sopenharmony_ci } 35888c2ecf20Sopenharmony_ci} 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_cistatic void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu) 35918c2ecf20Sopenharmony_ci{ 35928c2ecf20Sopenharmony_ci struct kvm_sync_regs *regs = &vcpu->run->s.regs; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci /* Clear reset is a superset of the initial reset */ 35958c2ecf20Sopenharmony_ci kvm_arch_vcpu_ioctl_initial_reset(vcpu); 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci memset(®s->gprs, 0, sizeof(regs->gprs)); 35988c2ecf20Sopenharmony_ci memset(®s->vrs, 0, sizeof(regs->vrs)); 35998c2ecf20Sopenharmony_ci memset(®s->acrs, 0, sizeof(regs->acrs)); 36008c2ecf20Sopenharmony_ci memset(®s->gscb, 0, sizeof(regs->gscb)); 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci regs->etoken = 0; 36038c2ecf20Sopenharmony_ci regs->etoken_extension = 0; 36048c2ecf20Sopenharmony_ci} 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 36078c2ecf20Sopenharmony_ci{ 36088c2ecf20Sopenharmony_ci vcpu_load(vcpu); 36098c2ecf20Sopenharmony_ci memcpy(&vcpu->run->s.regs.gprs, ®s->gprs, sizeof(regs->gprs)); 36108c2ecf20Sopenharmony_ci vcpu_put(vcpu); 36118c2ecf20Sopenharmony_ci return 0; 36128c2ecf20Sopenharmony_ci} 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 36158c2ecf20Sopenharmony_ci{ 36168c2ecf20Sopenharmony_ci vcpu_load(vcpu); 36178c2ecf20Sopenharmony_ci memcpy(®s->gprs, &vcpu->run->s.regs.gprs, sizeof(regs->gprs)); 36188c2ecf20Sopenharmony_ci vcpu_put(vcpu); 36198c2ecf20Sopenharmony_ci return 0; 36208c2ecf20Sopenharmony_ci} 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, 36238c2ecf20Sopenharmony_ci struct kvm_sregs *sregs) 36248c2ecf20Sopenharmony_ci{ 36258c2ecf20Sopenharmony_ci vcpu_load(vcpu); 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci memcpy(&vcpu->run->s.regs.acrs, &sregs->acrs, sizeof(sregs->acrs)); 36288c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs)); 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci vcpu_put(vcpu); 36318c2ecf20Sopenharmony_ci return 0; 36328c2ecf20Sopenharmony_ci} 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, 36358c2ecf20Sopenharmony_ci struct kvm_sregs *sregs) 36368c2ecf20Sopenharmony_ci{ 36378c2ecf20Sopenharmony_ci vcpu_load(vcpu); 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci memcpy(&sregs->acrs, &vcpu->run->s.regs.acrs, sizeof(sregs->acrs)); 36408c2ecf20Sopenharmony_ci memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs)); 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci vcpu_put(vcpu); 36438c2ecf20Sopenharmony_ci return 0; 36448c2ecf20Sopenharmony_ci} 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 36478c2ecf20Sopenharmony_ci{ 36488c2ecf20Sopenharmony_ci int ret = 0; 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci vcpu_load(vcpu); 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci vcpu->run->s.regs.fpc = fpu->fpc; 36538c2ecf20Sopenharmony_ci if (MACHINE_HAS_VX) 36548c2ecf20Sopenharmony_ci convert_fp_to_vx((__vector128 *) vcpu->run->s.regs.vrs, 36558c2ecf20Sopenharmony_ci (freg_t *) fpu->fprs); 36568c2ecf20Sopenharmony_ci else 36578c2ecf20Sopenharmony_ci memcpy(vcpu->run->s.regs.fprs, &fpu->fprs, sizeof(fpu->fprs)); 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci vcpu_put(vcpu); 36608c2ecf20Sopenharmony_ci return ret; 36618c2ecf20Sopenharmony_ci} 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 36648c2ecf20Sopenharmony_ci{ 36658c2ecf20Sopenharmony_ci vcpu_load(vcpu); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci /* make sure we have the latest values */ 36688c2ecf20Sopenharmony_ci save_fpu_regs(); 36698c2ecf20Sopenharmony_ci if (MACHINE_HAS_VX) 36708c2ecf20Sopenharmony_ci convert_vx_to_fp((freg_t *) fpu->fprs, 36718c2ecf20Sopenharmony_ci (__vector128 *) vcpu->run->s.regs.vrs); 36728c2ecf20Sopenharmony_ci else 36738c2ecf20Sopenharmony_ci memcpy(fpu->fprs, vcpu->run->s.regs.fprs, sizeof(fpu->fprs)); 36748c2ecf20Sopenharmony_ci fpu->fpc = vcpu->run->s.regs.fpc; 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci vcpu_put(vcpu); 36778c2ecf20Sopenharmony_ci return 0; 36788c2ecf20Sopenharmony_ci} 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_cistatic int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw) 36818c2ecf20Sopenharmony_ci{ 36828c2ecf20Sopenharmony_ci int rc = 0; 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci if (!is_vcpu_stopped(vcpu)) 36858c2ecf20Sopenharmony_ci rc = -EBUSY; 36868c2ecf20Sopenharmony_ci else { 36878c2ecf20Sopenharmony_ci vcpu->run->psw_mask = psw.mask; 36888c2ecf20Sopenharmony_ci vcpu->run->psw_addr = psw.addr; 36898c2ecf20Sopenharmony_ci } 36908c2ecf20Sopenharmony_ci return rc; 36918c2ecf20Sopenharmony_ci} 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, 36948c2ecf20Sopenharmony_ci struct kvm_translation *tr) 36958c2ecf20Sopenharmony_ci{ 36968c2ecf20Sopenharmony_ci return -EINVAL; /* not implemented yet */ 36978c2ecf20Sopenharmony_ci} 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_ci#define VALID_GUESTDBG_FLAGS (KVM_GUESTDBG_SINGLESTEP | \ 37008c2ecf20Sopenharmony_ci KVM_GUESTDBG_USE_HW_BP | \ 37018c2ecf20Sopenharmony_ci KVM_GUESTDBG_ENABLE) 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, 37048c2ecf20Sopenharmony_ci struct kvm_guest_debug *dbg) 37058c2ecf20Sopenharmony_ci{ 37068c2ecf20Sopenharmony_ci int rc = 0; 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci vcpu_load(vcpu); 37098c2ecf20Sopenharmony_ci 37108c2ecf20Sopenharmony_ci vcpu->guest_debug = 0; 37118c2ecf20Sopenharmony_ci kvm_s390_clear_bp_data(vcpu); 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci if (dbg->control & ~VALID_GUESTDBG_FLAGS) { 37148c2ecf20Sopenharmony_ci rc = -EINVAL; 37158c2ecf20Sopenharmony_ci goto out; 37168c2ecf20Sopenharmony_ci } 37178c2ecf20Sopenharmony_ci if (!sclp.has_gpere) { 37188c2ecf20Sopenharmony_ci rc = -EINVAL; 37198c2ecf20Sopenharmony_ci goto out; 37208c2ecf20Sopenharmony_ci } 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci if (dbg->control & KVM_GUESTDBG_ENABLE) { 37238c2ecf20Sopenharmony_ci vcpu->guest_debug = dbg->control; 37248c2ecf20Sopenharmony_ci /* enforce guest PER */ 37258c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_P); 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_ci if (dbg->control & KVM_GUESTDBG_USE_HW_BP) 37288c2ecf20Sopenharmony_ci rc = kvm_s390_import_bp_data(vcpu, dbg); 37298c2ecf20Sopenharmony_ci } else { 37308c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_P); 37318c2ecf20Sopenharmony_ci vcpu->arch.guestdbg.last_bp = 0; 37328c2ecf20Sopenharmony_ci } 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci if (rc) { 37358c2ecf20Sopenharmony_ci vcpu->guest_debug = 0; 37368c2ecf20Sopenharmony_ci kvm_s390_clear_bp_data(vcpu); 37378c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_P); 37388c2ecf20Sopenharmony_ci } 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ciout: 37418c2ecf20Sopenharmony_ci vcpu_put(vcpu); 37428c2ecf20Sopenharmony_ci return rc; 37438c2ecf20Sopenharmony_ci} 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, 37468c2ecf20Sopenharmony_ci struct kvm_mp_state *mp_state) 37478c2ecf20Sopenharmony_ci{ 37488c2ecf20Sopenharmony_ci int ret; 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_ci vcpu_load(vcpu); 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci /* CHECK_STOP and LOAD are not supported yet */ 37538c2ecf20Sopenharmony_ci ret = is_vcpu_stopped(vcpu) ? KVM_MP_STATE_STOPPED : 37548c2ecf20Sopenharmony_ci KVM_MP_STATE_OPERATING; 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci vcpu_put(vcpu); 37578c2ecf20Sopenharmony_ci return ret; 37588c2ecf20Sopenharmony_ci} 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, 37618c2ecf20Sopenharmony_ci struct kvm_mp_state *mp_state) 37628c2ecf20Sopenharmony_ci{ 37638c2ecf20Sopenharmony_ci int rc = 0; 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci vcpu_load(vcpu); 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci /* user space knows about this interface - let it control the state */ 37688c2ecf20Sopenharmony_ci vcpu->kvm->arch.user_cpu_state_ctrl = 1; 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci switch (mp_state->mp_state) { 37718c2ecf20Sopenharmony_ci case KVM_MP_STATE_STOPPED: 37728c2ecf20Sopenharmony_ci rc = kvm_s390_vcpu_stop(vcpu); 37738c2ecf20Sopenharmony_ci break; 37748c2ecf20Sopenharmony_ci case KVM_MP_STATE_OPERATING: 37758c2ecf20Sopenharmony_ci rc = kvm_s390_vcpu_start(vcpu); 37768c2ecf20Sopenharmony_ci break; 37778c2ecf20Sopenharmony_ci case KVM_MP_STATE_LOAD: 37788c2ecf20Sopenharmony_ci if (!kvm_s390_pv_cpu_is_protected(vcpu)) { 37798c2ecf20Sopenharmony_ci rc = -ENXIO; 37808c2ecf20Sopenharmony_ci break; 37818c2ecf20Sopenharmony_ci } 37828c2ecf20Sopenharmony_ci rc = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_OPR_LOAD); 37838c2ecf20Sopenharmony_ci break; 37848c2ecf20Sopenharmony_ci case KVM_MP_STATE_CHECK_STOP: 37858c2ecf20Sopenharmony_ci fallthrough; /* CHECK_STOP and LOAD are not supported yet */ 37868c2ecf20Sopenharmony_ci default: 37878c2ecf20Sopenharmony_ci rc = -ENXIO; 37888c2ecf20Sopenharmony_ci } 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci vcpu_put(vcpu); 37918c2ecf20Sopenharmony_ci return rc; 37928c2ecf20Sopenharmony_ci} 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_cistatic bool ibs_enabled(struct kvm_vcpu *vcpu) 37958c2ecf20Sopenharmony_ci{ 37968c2ecf20Sopenharmony_ci return kvm_s390_test_cpuflags(vcpu, CPUSTAT_IBS); 37978c2ecf20Sopenharmony_ci} 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_cistatic int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) 38008c2ecf20Sopenharmony_ci{ 38018c2ecf20Sopenharmony_ciretry: 38028c2ecf20Sopenharmony_ci kvm_s390_vcpu_request_handled(vcpu); 38038c2ecf20Sopenharmony_ci if (!kvm_request_pending(vcpu)) 38048c2ecf20Sopenharmony_ci return 0; 38058c2ecf20Sopenharmony_ci /* 38068c2ecf20Sopenharmony_ci * We use MMU_RELOAD just to re-arm the ipte notifier for the 38078c2ecf20Sopenharmony_ci * guest prefix page. gmap_mprotect_notify will wait on the ptl lock. 38088c2ecf20Sopenharmony_ci * This ensures that the ipte instruction for this request has 38098c2ecf20Sopenharmony_ci * already finished. We might race against a second unmapper that 38108c2ecf20Sopenharmony_ci * wants to set the blocking bit. Lets just retry the request loop. 38118c2ecf20Sopenharmony_ci */ 38128c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) { 38138c2ecf20Sopenharmony_ci int rc; 38148c2ecf20Sopenharmony_ci rc = gmap_mprotect_notify(vcpu->arch.gmap, 38158c2ecf20Sopenharmony_ci kvm_s390_get_prefix(vcpu), 38168c2ecf20Sopenharmony_ci PAGE_SIZE * 2, PROT_WRITE); 38178c2ecf20Sopenharmony_ci if (rc) { 38188c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu); 38198c2ecf20Sopenharmony_ci return rc; 38208c2ecf20Sopenharmony_ci } 38218c2ecf20Sopenharmony_ci goto retry; 38228c2ecf20Sopenharmony_ci } 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu)) { 38258c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ihcpu = 0xffff; 38268c2ecf20Sopenharmony_ci goto retry; 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) { 38308c2ecf20Sopenharmony_ci if (!ibs_enabled(vcpu)) { 38318c2ecf20Sopenharmony_ci trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1); 38328c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_IBS); 38338c2ecf20Sopenharmony_ci } 38348c2ecf20Sopenharmony_ci goto retry; 38358c2ecf20Sopenharmony_ci } 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) { 38388c2ecf20Sopenharmony_ci if (ibs_enabled(vcpu)) { 38398c2ecf20Sopenharmony_ci trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0); 38408c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_IBS); 38418c2ecf20Sopenharmony_ci } 38428c2ecf20Sopenharmony_ci goto retry; 38438c2ecf20Sopenharmony_ci } 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_ICPT_OPEREXC, vcpu)) { 38468c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ictl |= ICTL_OPEREXC; 38478c2ecf20Sopenharmony_ci goto retry; 38488c2ecf20Sopenharmony_ci } 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_START_MIGRATION, vcpu)) { 38518c2ecf20Sopenharmony_ci /* 38528c2ecf20Sopenharmony_ci * Disable CMM virtualization; we will emulate the ESSA 38538c2ecf20Sopenharmony_ci * instruction manually, in order to provide additional 38548c2ecf20Sopenharmony_ci * functionalities needed for live migration. 38558c2ecf20Sopenharmony_ci */ 38568c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 &= ~ECB2_CMMA; 38578c2ecf20Sopenharmony_ci goto retry; 38588c2ecf20Sopenharmony_ci } 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci if (kvm_check_request(KVM_REQ_STOP_MIGRATION, vcpu)) { 38618c2ecf20Sopenharmony_ci /* 38628c2ecf20Sopenharmony_ci * Re-enable CMM virtualization if CMMA is available and 38638c2ecf20Sopenharmony_ci * CMM has been used. 38648c2ecf20Sopenharmony_ci */ 38658c2ecf20Sopenharmony_ci if ((vcpu->kvm->arch.use_cmma) && 38668c2ecf20Sopenharmony_ci (vcpu->kvm->mm->context.uses_cmm)) 38678c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb2 |= ECB2_CMMA; 38688c2ecf20Sopenharmony_ci goto retry; 38698c2ecf20Sopenharmony_ci } 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci /* nothing to do, just clear the request */ 38728c2ecf20Sopenharmony_ci kvm_clear_request(KVM_REQ_UNHALT, vcpu); 38738c2ecf20Sopenharmony_ci /* we left the vsie handler, nothing to do, just clear the request */ 38748c2ecf20Sopenharmony_ci kvm_clear_request(KVM_REQ_VSIE_RESTART, vcpu); 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci return 0; 38778c2ecf20Sopenharmony_ci} 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_cistatic void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) 38808c2ecf20Sopenharmony_ci{ 38818c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 38828c2ecf20Sopenharmony_ci struct kvm_s390_tod_clock_ext htod; 38838c2ecf20Sopenharmony_ci int i; 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci preempt_disable(); 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci get_tod_clock_ext((char *)&htod); 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci kvm->arch.epoch = gtod->tod - htod.tod; 38908c2ecf20Sopenharmony_ci kvm->arch.epdx = 0; 38918c2ecf20Sopenharmony_ci if (test_kvm_facility(kvm, 139)) { 38928c2ecf20Sopenharmony_ci kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx; 38938c2ecf20Sopenharmony_ci if (kvm->arch.epoch > gtod->tod) 38948c2ecf20Sopenharmony_ci kvm->arch.epdx -= 1; 38958c2ecf20Sopenharmony_ci } 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci kvm_s390_vcpu_block_all(kvm); 38988c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 38998c2ecf20Sopenharmony_ci vcpu->arch.sie_block->epoch = kvm->arch.epoch; 39008c2ecf20Sopenharmony_ci vcpu->arch.sie_block->epdx = kvm->arch.epdx; 39018c2ecf20Sopenharmony_ci } 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci kvm_s390_vcpu_unblock_all(kvm); 39048c2ecf20Sopenharmony_ci preempt_enable(); 39058c2ecf20Sopenharmony_ci} 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ciint kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) 39088c2ecf20Sopenharmony_ci{ 39098c2ecf20Sopenharmony_ci if (!mutex_trylock(&kvm->lock)) 39108c2ecf20Sopenharmony_ci return 0; 39118c2ecf20Sopenharmony_ci __kvm_s390_set_tod_clock(kvm, gtod); 39128c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 39138c2ecf20Sopenharmony_ci return 1; 39148c2ecf20Sopenharmony_ci} 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci/** 39178c2ecf20Sopenharmony_ci * kvm_arch_fault_in_page - fault-in guest page if necessary 39188c2ecf20Sopenharmony_ci * @vcpu: The corresponding virtual cpu 39198c2ecf20Sopenharmony_ci * @gpa: Guest physical address 39208c2ecf20Sopenharmony_ci * @writable: Whether the page should be writable or not 39218c2ecf20Sopenharmony_ci * 39228c2ecf20Sopenharmony_ci * Make sure that a guest page has been faulted-in on the host. 39238c2ecf20Sopenharmony_ci * 39248c2ecf20Sopenharmony_ci * Return: Zero on success, negative error code otherwise. 39258c2ecf20Sopenharmony_ci */ 39268c2ecf20Sopenharmony_cilong kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable) 39278c2ecf20Sopenharmony_ci{ 39288c2ecf20Sopenharmony_ci return gmap_fault(vcpu->arch.gmap, gpa, 39298c2ecf20Sopenharmony_ci writable ? FAULT_FLAG_WRITE : 0); 39308c2ecf20Sopenharmony_ci} 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_cistatic void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token, 39338c2ecf20Sopenharmony_ci unsigned long token) 39348c2ecf20Sopenharmony_ci{ 39358c2ecf20Sopenharmony_ci struct kvm_s390_interrupt inti; 39368c2ecf20Sopenharmony_ci struct kvm_s390_irq irq; 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci if (start_token) { 39398c2ecf20Sopenharmony_ci irq.u.ext.ext_params2 = token; 39408c2ecf20Sopenharmony_ci irq.type = KVM_S390_INT_PFAULT_INIT; 39418c2ecf20Sopenharmony_ci WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq)); 39428c2ecf20Sopenharmony_ci } else { 39438c2ecf20Sopenharmony_ci inti.type = KVM_S390_INT_PFAULT_DONE; 39448c2ecf20Sopenharmony_ci inti.parm64 = token; 39458c2ecf20Sopenharmony_ci WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti)); 39468c2ecf20Sopenharmony_ci } 39478c2ecf20Sopenharmony_ci} 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_cibool kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu, 39508c2ecf20Sopenharmony_ci struct kvm_async_pf *work) 39518c2ecf20Sopenharmony_ci{ 39528c2ecf20Sopenharmony_ci trace_kvm_s390_pfault_init(vcpu, work->arch.pfault_token); 39538c2ecf20Sopenharmony_ci __kvm_inject_pfault_token(vcpu, true, work->arch.pfault_token); 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci return true; 39568c2ecf20Sopenharmony_ci} 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_civoid kvm_arch_async_page_present(struct kvm_vcpu *vcpu, 39598c2ecf20Sopenharmony_ci struct kvm_async_pf *work) 39608c2ecf20Sopenharmony_ci{ 39618c2ecf20Sopenharmony_ci trace_kvm_s390_pfault_done(vcpu, work->arch.pfault_token); 39628c2ecf20Sopenharmony_ci __kvm_inject_pfault_token(vcpu, false, work->arch.pfault_token); 39638c2ecf20Sopenharmony_ci} 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_civoid kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, 39668c2ecf20Sopenharmony_ci struct kvm_async_pf *work) 39678c2ecf20Sopenharmony_ci{ 39688c2ecf20Sopenharmony_ci /* s390 will always inject the page directly */ 39698c2ecf20Sopenharmony_ci} 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_cibool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu) 39728c2ecf20Sopenharmony_ci{ 39738c2ecf20Sopenharmony_ci /* 39748c2ecf20Sopenharmony_ci * s390 will always inject the page directly, 39758c2ecf20Sopenharmony_ci * but we still want check_async_completion to cleanup 39768c2ecf20Sopenharmony_ci */ 39778c2ecf20Sopenharmony_ci return true; 39788c2ecf20Sopenharmony_ci} 39798c2ecf20Sopenharmony_ci 39808c2ecf20Sopenharmony_cistatic bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu) 39818c2ecf20Sopenharmony_ci{ 39828c2ecf20Sopenharmony_ci hva_t hva; 39838c2ecf20Sopenharmony_ci struct kvm_arch_async_pf arch; 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID) 39868c2ecf20Sopenharmony_ci return false; 39878c2ecf20Sopenharmony_ci if ((vcpu->arch.sie_block->gpsw.mask & vcpu->arch.pfault_select) != 39888c2ecf20Sopenharmony_ci vcpu->arch.pfault_compare) 39898c2ecf20Sopenharmony_ci return false; 39908c2ecf20Sopenharmony_ci if (psw_extint_disabled(vcpu)) 39918c2ecf20Sopenharmony_ci return false; 39928c2ecf20Sopenharmony_ci if (kvm_s390_vcpu_has_irq(vcpu, 0)) 39938c2ecf20Sopenharmony_ci return false; 39948c2ecf20Sopenharmony_ci if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK)) 39958c2ecf20Sopenharmony_ci return false; 39968c2ecf20Sopenharmony_ci if (!vcpu->arch.gmap->pfault_enabled) 39978c2ecf20Sopenharmony_ci return false; 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_ci hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(current->thread.gmap_addr)); 40008c2ecf20Sopenharmony_ci hva += current->thread.gmap_addr & ~PAGE_MASK; 40018c2ecf20Sopenharmony_ci if (read_guest_real(vcpu, vcpu->arch.pfault_token, &arch.pfault_token, 8)) 40028c2ecf20Sopenharmony_ci return false; 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci return kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch); 40058c2ecf20Sopenharmony_ci} 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_cistatic int vcpu_pre_run(struct kvm_vcpu *vcpu) 40088c2ecf20Sopenharmony_ci{ 40098c2ecf20Sopenharmony_ci int rc, cpuflags; 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_ci /* 40128c2ecf20Sopenharmony_ci * On s390 notifications for arriving pages will be delivered directly 40138c2ecf20Sopenharmony_ci * to the guest but the house keeping for completed pfaults is 40148c2ecf20Sopenharmony_ci * handled outside the worker. 40158c2ecf20Sopenharmony_ci */ 40168c2ecf20Sopenharmony_ci kvm_check_async_pf_completion(vcpu); 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gg14 = vcpu->run->s.regs.gprs[14]; 40198c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gg15 = vcpu->run->s.regs.gprs[15]; 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci if (need_resched()) 40228c2ecf20Sopenharmony_ci schedule(); 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(vcpu->kvm)) { 40258c2ecf20Sopenharmony_ci rc = kvm_s390_deliver_pending_interrupts(vcpu); 40268c2ecf20Sopenharmony_ci if (rc) 40278c2ecf20Sopenharmony_ci return rc; 40288c2ecf20Sopenharmony_ci } 40298c2ecf20Sopenharmony_ci 40308c2ecf20Sopenharmony_ci rc = kvm_s390_handle_requests(vcpu); 40318c2ecf20Sopenharmony_ci if (rc) 40328c2ecf20Sopenharmony_ci return rc; 40338c2ecf20Sopenharmony_ci 40348c2ecf20Sopenharmony_ci if (guestdbg_enabled(vcpu)) { 40358c2ecf20Sopenharmony_ci kvm_s390_backup_guest_per_regs(vcpu); 40368c2ecf20Sopenharmony_ci kvm_s390_patch_guest_per_regs(vcpu); 40378c2ecf20Sopenharmony_ci } 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci clear_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.gisa_int.kicked_mask); 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci vcpu->arch.sie_block->icptcode = 0; 40428c2ecf20Sopenharmony_ci cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags); 40438c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags); 40448c2ecf20Sopenharmony_ci trace_kvm_s390_sie_enter(vcpu, cpuflags); 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci return 0; 40478c2ecf20Sopenharmony_ci} 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_cistatic int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu) 40508c2ecf20Sopenharmony_ci{ 40518c2ecf20Sopenharmony_ci struct kvm_s390_pgm_info pgm_info = { 40528c2ecf20Sopenharmony_ci .code = PGM_ADDRESSING, 40538c2ecf20Sopenharmony_ci }; 40548c2ecf20Sopenharmony_ci u8 opcode, ilen; 40558c2ecf20Sopenharmony_ci int rc; 40568c2ecf20Sopenharmony_ci 40578c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); 40588c2ecf20Sopenharmony_ci trace_kvm_s390_sie_fault(vcpu); 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_ci /* 40618c2ecf20Sopenharmony_ci * We want to inject an addressing exception, which is defined as a 40628c2ecf20Sopenharmony_ci * suppressing or terminating exception. However, since we came here 40638c2ecf20Sopenharmony_ci * by a DAT access exception, the PSW still points to the faulting 40648c2ecf20Sopenharmony_ci * instruction since DAT exceptions are nullifying. So we've got 40658c2ecf20Sopenharmony_ci * to look up the current opcode to get the length of the instruction 40668c2ecf20Sopenharmony_ci * to be able to forward the PSW. 40678c2ecf20Sopenharmony_ci */ 40688c2ecf20Sopenharmony_ci rc = read_guest_instr(vcpu, vcpu->arch.sie_block->gpsw.addr, &opcode, 1); 40698c2ecf20Sopenharmony_ci ilen = insn_length(opcode); 40708c2ecf20Sopenharmony_ci if (rc < 0) { 40718c2ecf20Sopenharmony_ci return rc; 40728c2ecf20Sopenharmony_ci } else if (rc) { 40738c2ecf20Sopenharmony_ci /* Instruction-Fetching Exceptions - we can't detect the ilen. 40748c2ecf20Sopenharmony_ci * Forward by arbitrary ilc, injection will take care of 40758c2ecf20Sopenharmony_ci * nullification if necessary. 40768c2ecf20Sopenharmony_ci */ 40778c2ecf20Sopenharmony_ci pgm_info = vcpu->arch.pgm; 40788c2ecf20Sopenharmony_ci ilen = 4; 40798c2ecf20Sopenharmony_ci } 40808c2ecf20Sopenharmony_ci pgm_info.flags = ilen | KVM_S390_PGM_FLAGS_ILC_VALID; 40818c2ecf20Sopenharmony_ci kvm_s390_forward_psw(vcpu, ilen); 40828c2ecf20Sopenharmony_ci return kvm_s390_inject_prog_irq(vcpu, &pgm_info); 40838c2ecf20Sopenharmony_ci} 40848c2ecf20Sopenharmony_ci 40858c2ecf20Sopenharmony_cistatic int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) 40868c2ecf20Sopenharmony_ci{ 40878c2ecf20Sopenharmony_ci struct mcck_volatile_info *mcck_info; 40888c2ecf20Sopenharmony_ci struct sie_page *sie_page; 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", 40918c2ecf20Sopenharmony_ci vcpu->arch.sie_block->icptcode); 40928c2ecf20Sopenharmony_ci trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci if (guestdbg_enabled(vcpu)) 40958c2ecf20Sopenharmony_ci kvm_s390_restore_guest_per_regs(vcpu); 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[14] = vcpu->arch.sie_block->gg14; 40988c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs[15] = vcpu->arch.sie_block->gg15; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci if (exit_reason == -EINTR) { 41018c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "machine check"); 41028c2ecf20Sopenharmony_ci sie_page = container_of(vcpu->arch.sie_block, 41038c2ecf20Sopenharmony_ci struct sie_page, sie_block); 41048c2ecf20Sopenharmony_ci mcck_info = &sie_page->mcck_info; 41058c2ecf20Sopenharmony_ci kvm_s390_reinject_machine_check(vcpu, mcck_info); 41068c2ecf20Sopenharmony_ci return 0; 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->icptcode > 0) { 41108c2ecf20Sopenharmony_ci int rc = kvm_handle_sie_intercept(vcpu); 41118c2ecf20Sopenharmony_ci 41128c2ecf20Sopenharmony_ci if (rc != -EOPNOTSUPP) 41138c2ecf20Sopenharmony_ci return rc; 41148c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_S390_SIEIC; 41158c2ecf20Sopenharmony_ci vcpu->run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode; 41168c2ecf20Sopenharmony_ci vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa; 41178c2ecf20Sopenharmony_ci vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb; 41188c2ecf20Sopenharmony_ci return -EREMOTE; 41198c2ecf20Sopenharmony_ci } else if (exit_reason != -EFAULT) { 41208c2ecf20Sopenharmony_ci vcpu->stat.exit_null++; 41218c2ecf20Sopenharmony_ci return 0; 41228c2ecf20Sopenharmony_ci } else if (kvm_is_ucontrol(vcpu->kvm)) { 41238c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL; 41248c2ecf20Sopenharmony_ci vcpu->run->s390_ucontrol.trans_exc_code = 41258c2ecf20Sopenharmony_ci current->thread.gmap_addr; 41268c2ecf20Sopenharmony_ci vcpu->run->s390_ucontrol.pgm_code = 0x10; 41278c2ecf20Sopenharmony_ci return -EREMOTE; 41288c2ecf20Sopenharmony_ci } else if (current->thread.gmap_pfault) { 41298c2ecf20Sopenharmony_ci trace_kvm_s390_major_guest_pfault(vcpu); 41308c2ecf20Sopenharmony_ci current->thread.gmap_pfault = 0; 41318c2ecf20Sopenharmony_ci if (kvm_arch_setup_async_pf(vcpu)) 41328c2ecf20Sopenharmony_ci return 0; 41338c2ecf20Sopenharmony_ci return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1); 41348c2ecf20Sopenharmony_ci } 41358c2ecf20Sopenharmony_ci return vcpu_post_run_fault_in_sie(vcpu); 41368c2ecf20Sopenharmony_ci} 41378c2ecf20Sopenharmony_ci 41388c2ecf20Sopenharmony_ci#define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK) 41398c2ecf20Sopenharmony_cistatic int __vcpu_run(struct kvm_vcpu *vcpu) 41408c2ecf20Sopenharmony_ci{ 41418c2ecf20Sopenharmony_ci int rc, exit_reason; 41428c2ecf20Sopenharmony_ci struct sie_page *sie_page = (struct sie_page *)vcpu->arch.sie_block; 41438c2ecf20Sopenharmony_ci 41448c2ecf20Sopenharmony_ci /* 41458c2ecf20Sopenharmony_ci * We try to hold kvm->srcu during most of vcpu_run (except when run- 41468c2ecf20Sopenharmony_ci * ning the guest), so that memslots (and other stuff) are protected 41478c2ecf20Sopenharmony_ci */ 41488c2ecf20Sopenharmony_ci vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci do { 41518c2ecf20Sopenharmony_ci rc = vcpu_pre_run(vcpu); 41528c2ecf20Sopenharmony_ci if (rc) 41538c2ecf20Sopenharmony_ci break; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); 41568c2ecf20Sopenharmony_ci /* 41578c2ecf20Sopenharmony_ci * As PF_VCPU will be used in fault handler, between 41588c2ecf20Sopenharmony_ci * guest_enter and guest_exit should be no uaccess. 41598c2ecf20Sopenharmony_ci */ 41608c2ecf20Sopenharmony_ci local_irq_disable(); 41618c2ecf20Sopenharmony_ci guest_enter_irqoff(); 41628c2ecf20Sopenharmony_ci __disable_cpu_timer_accounting(vcpu); 41638c2ecf20Sopenharmony_ci local_irq_enable(); 41648c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 41658c2ecf20Sopenharmony_ci memcpy(sie_page->pv_grregs, 41668c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs, 41678c2ecf20Sopenharmony_ci sizeof(sie_page->pv_grregs)); 41688c2ecf20Sopenharmony_ci } 41698c2ecf20Sopenharmony_ci exit_reason = sie64a(vcpu->arch.sie_block, 41708c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs); 41718c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 41728c2ecf20Sopenharmony_ci memcpy(vcpu->run->s.regs.gprs, 41738c2ecf20Sopenharmony_ci sie_page->pv_grregs, 41748c2ecf20Sopenharmony_ci sizeof(sie_page->pv_grregs)); 41758c2ecf20Sopenharmony_ci /* 41768c2ecf20Sopenharmony_ci * We're not allowed to inject interrupts on intercepts 41778c2ecf20Sopenharmony_ci * that leave the guest state in an "in-between" state 41788c2ecf20Sopenharmony_ci * where the next SIE entry will do a continuation. 41798c2ecf20Sopenharmony_ci * Fence interrupts in our "internal" PSW. 41808c2ecf20Sopenharmony_ci */ 41818c2ecf20Sopenharmony_ci if (vcpu->arch.sie_block->icptcode == ICPT_PV_INSTR || 41828c2ecf20Sopenharmony_ci vcpu->arch.sie_block->icptcode == ICPT_PV_PREF) { 41838c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask &= ~PSW_INT_MASK; 41848c2ecf20Sopenharmony_ci } 41858c2ecf20Sopenharmony_ci } 41868c2ecf20Sopenharmony_ci local_irq_disable(); 41878c2ecf20Sopenharmony_ci __enable_cpu_timer_accounting(vcpu); 41888c2ecf20Sopenharmony_ci guest_exit_irqoff(); 41898c2ecf20Sopenharmony_ci local_irq_enable(); 41908c2ecf20Sopenharmony_ci vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_ci rc = vcpu_post_run(vcpu, exit_reason); 41938c2ecf20Sopenharmony_ci } while (!signal_pending(current) && !guestdbg_exit_pending(vcpu) && !rc); 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); 41968c2ecf20Sopenharmony_ci return rc; 41978c2ecf20Sopenharmony_ci} 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_cistatic void sync_regs_fmt2(struct kvm_vcpu *vcpu) 42008c2ecf20Sopenharmony_ci{ 42018c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 42028c2ecf20Sopenharmony_ci struct runtime_instr_cb *riccb; 42038c2ecf20Sopenharmony_ci struct gs_cb *gscb; 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_ci riccb = (struct runtime_instr_cb *) &kvm_run->s.regs.riccb; 42068c2ecf20Sopenharmony_ci gscb = (struct gs_cb *) &kvm_run->s.regs.gscb; 42078c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask; 42088c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr; 42098c2ecf20Sopenharmony_ci if (kvm_run->kvm_dirty_regs & KVM_SYNC_ARCH0) { 42108c2ecf20Sopenharmony_ci vcpu->arch.sie_block->todpr = kvm_run->s.regs.todpr; 42118c2ecf20Sopenharmony_ci vcpu->arch.sie_block->pp = kvm_run->s.regs.pp; 42128c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gbea = kvm_run->s.regs.gbea; 42138c2ecf20Sopenharmony_ci } 42148c2ecf20Sopenharmony_ci if (kvm_run->kvm_dirty_regs & KVM_SYNC_PFAULT) { 42158c2ecf20Sopenharmony_ci vcpu->arch.pfault_token = kvm_run->s.regs.pft; 42168c2ecf20Sopenharmony_ci vcpu->arch.pfault_select = kvm_run->s.regs.pfs; 42178c2ecf20Sopenharmony_ci vcpu->arch.pfault_compare = kvm_run->s.regs.pfc; 42188c2ecf20Sopenharmony_ci if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID) 42198c2ecf20Sopenharmony_ci kvm_clear_async_pf_completion_queue(vcpu); 42208c2ecf20Sopenharmony_ci } 42218c2ecf20Sopenharmony_ci if (kvm_run->kvm_dirty_regs & KVM_SYNC_DIAG318) { 42228c2ecf20Sopenharmony_ci vcpu->arch.diag318_info.val = kvm_run->s.regs.diag318; 42238c2ecf20Sopenharmony_ci vcpu->arch.sie_block->cpnc = vcpu->arch.diag318_info.cpnc; 42248c2ecf20Sopenharmony_ci } 42258c2ecf20Sopenharmony_ci /* 42268c2ecf20Sopenharmony_ci * If userspace sets the riccb (e.g. after migration) to a valid state, 42278c2ecf20Sopenharmony_ci * we should enable RI here instead of doing the lazy enablement. 42288c2ecf20Sopenharmony_ci */ 42298c2ecf20Sopenharmony_ci if ((kvm_run->kvm_dirty_regs & KVM_SYNC_RICCB) && 42308c2ecf20Sopenharmony_ci test_kvm_facility(vcpu->kvm, 64) && 42318c2ecf20Sopenharmony_ci riccb->v && 42328c2ecf20Sopenharmony_ci !(vcpu->arch.sie_block->ecb3 & ECB3_RI)) { 42338c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (sync_regs)"); 42348c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb3 |= ECB3_RI; 42358c2ecf20Sopenharmony_ci } 42368c2ecf20Sopenharmony_ci /* 42378c2ecf20Sopenharmony_ci * If userspace sets the gscb (e.g. after migration) to non-zero, 42388c2ecf20Sopenharmony_ci * we should enable GS here instead of doing the lazy enablement. 42398c2ecf20Sopenharmony_ci */ 42408c2ecf20Sopenharmony_ci if ((kvm_run->kvm_dirty_regs & KVM_SYNC_GSCB) && 42418c2ecf20Sopenharmony_ci test_kvm_facility(vcpu->kvm, 133) && 42428c2ecf20Sopenharmony_ci gscb->gssm && 42438c2ecf20Sopenharmony_ci !vcpu->arch.gs_enabled) { 42448c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (sync_regs)"); 42458c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecb |= ECB_GS; 42468c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT; 42478c2ecf20Sopenharmony_ci vcpu->arch.gs_enabled = 1; 42488c2ecf20Sopenharmony_ci } 42498c2ecf20Sopenharmony_ci if ((kvm_run->kvm_dirty_regs & KVM_SYNC_BPBC) && 42508c2ecf20Sopenharmony_ci test_kvm_facility(vcpu->kvm, 82)) { 42518c2ecf20Sopenharmony_ci vcpu->arch.sie_block->fpf &= ~FPF_BPBC; 42528c2ecf20Sopenharmony_ci vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0; 42538c2ecf20Sopenharmony_ci } 42548c2ecf20Sopenharmony_ci if (MACHINE_HAS_GS) { 42558c2ecf20Sopenharmony_ci preempt_disable(); 42568c2ecf20Sopenharmony_ci __ctl_set_bit(2, 4); 42578c2ecf20Sopenharmony_ci if (current->thread.gs_cb) { 42588c2ecf20Sopenharmony_ci vcpu->arch.host_gscb = current->thread.gs_cb; 42598c2ecf20Sopenharmony_ci save_gs_cb(vcpu->arch.host_gscb); 42608c2ecf20Sopenharmony_ci } 42618c2ecf20Sopenharmony_ci if (vcpu->arch.gs_enabled) { 42628c2ecf20Sopenharmony_ci current->thread.gs_cb = (struct gs_cb *) 42638c2ecf20Sopenharmony_ci &vcpu->run->s.regs.gscb; 42648c2ecf20Sopenharmony_ci restore_gs_cb(current->thread.gs_cb); 42658c2ecf20Sopenharmony_ci } 42668c2ecf20Sopenharmony_ci preempt_enable(); 42678c2ecf20Sopenharmony_ci } 42688c2ecf20Sopenharmony_ci /* SIE will load etoken directly from SDNX and therefore kvm_run */ 42698c2ecf20Sopenharmony_ci} 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_cistatic void sync_regs(struct kvm_vcpu *vcpu) 42728c2ecf20Sopenharmony_ci{ 42738c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_ci if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX) 42768c2ecf20Sopenharmony_ci kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix); 42778c2ecf20Sopenharmony_ci if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) { 42788c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128); 42798c2ecf20Sopenharmony_ci /* some control register changes require a tlb flush */ 42808c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); 42818c2ecf20Sopenharmony_ci } 42828c2ecf20Sopenharmony_ci if (kvm_run->kvm_dirty_regs & KVM_SYNC_ARCH0) { 42838c2ecf20Sopenharmony_ci kvm_s390_set_cpu_timer(vcpu, kvm_run->s.regs.cputm); 42848c2ecf20Sopenharmony_ci vcpu->arch.sie_block->ckc = kvm_run->s.regs.ckc; 42858c2ecf20Sopenharmony_ci } 42868c2ecf20Sopenharmony_ci save_access_regs(vcpu->arch.host_acrs); 42878c2ecf20Sopenharmony_ci restore_access_regs(vcpu->run->s.regs.acrs); 42888c2ecf20Sopenharmony_ci /* save host (userspace) fprs/vrs */ 42898c2ecf20Sopenharmony_ci save_fpu_regs(); 42908c2ecf20Sopenharmony_ci vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc; 42918c2ecf20Sopenharmony_ci vcpu->arch.host_fpregs.regs = current->thread.fpu.regs; 42928c2ecf20Sopenharmony_ci if (MACHINE_HAS_VX) 42938c2ecf20Sopenharmony_ci current->thread.fpu.regs = vcpu->run->s.regs.vrs; 42948c2ecf20Sopenharmony_ci else 42958c2ecf20Sopenharmony_ci current->thread.fpu.regs = vcpu->run->s.regs.fprs; 42968c2ecf20Sopenharmony_ci current->thread.fpu.fpc = vcpu->run->s.regs.fpc; 42978c2ecf20Sopenharmony_ci if (test_fp_ctl(current->thread.fpu.fpc)) 42988c2ecf20Sopenharmony_ci /* User space provided an invalid FPC, let's clear it */ 42998c2ecf20Sopenharmony_ci current->thread.fpu.fpc = 0; 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ci /* Sync fmt2 only data */ 43028c2ecf20Sopenharmony_ci if (likely(!kvm_s390_pv_cpu_is_protected(vcpu))) { 43038c2ecf20Sopenharmony_ci sync_regs_fmt2(vcpu); 43048c2ecf20Sopenharmony_ci } else { 43058c2ecf20Sopenharmony_ci /* 43068c2ecf20Sopenharmony_ci * In several places we have to modify our internal view to 43078c2ecf20Sopenharmony_ci * not do things that are disallowed by the ultravisor. For 43088c2ecf20Sopenharmony_ci * example we must not inject interrupts after specific exits 43098c2ecf20Sopenharmony_ci * (e.g. 112 prefix page not secure). We do this by turning 43108c2ecf20Sopenharmony_ci * off the machine check, external and I/O interrupt bits 43118c2ecf20Sopenharmony_ci * of our PSW copy. To avoid getting validity intercepts, we 43128c2ecf20Sopenharmony_ci * do only accept the condition code from userspace. 43138c2ecf20Sopenharmony_ci */ 43148c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_CC; 43158c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask |= kvm_run->psw_mask & 43168c2ecf20Sopenharmony_ci PSW_MASK_CC; 43178c2ecf20Sopenharmony_ci } 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_ci kvm_run->kvm_dirty_regs = 0; 43208c2ecf20Sopenharmony_ci} 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_cistatic void store_regs_fmt2(struct kvm_vcpu *vcpu) 43238c2ecf20Sopenharmony_ci{ 43248c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 43258c2ecf20Sopenharmony_ci 43268c2ecf20Sopenharmony_ci kvm_run->s.regs.todpr = vcpu->arch.sie_block->todpr; 43278c2ecf20Sopenharmony_ci kvm_run->s.regs.pp = vcpu->arch.sie_block->pp; 43288c2ecf20Sopenharmony_ci kvm_run->s.regs.gbea = vcpu->arch.sie_block->gbea; 43298c2ecf20Sopenharmony_ci kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC; 43308c2ecf20Sopenharmony_ci kvm_run->s.regs.diag318 = vcpu->arch.diag318_info.val; 43318c2ecf20Sopenharmony_ci if (MACHINE_HAS_GS) { 43328c2ecf20Sopenharmony_ci preempt_disable(); 43338c2ecf20Sopenharmony_ci __ctl_set_bit(2, 4); 43348c2ecf20Sopenharmony_ci if (vcpu->arch.gs_enabled) 43358c2ecf20Sopenharmony_ci save_gs_cb(current->thread.gs_cb); 43368c2ecf20Sopenharmony_ci current->thread.gs_cb = vcpu->arch.host_gscb; 43378c2ecf20Sopenharmony_ci restore_gs_cb(vcpu->arch.host_gscb); 43388c2ecf20Sopenharmony_ci if (!vcpu->arch.host_gscb) 43398c2ecf20Sopenharmony_ci __ctl_clear_bit(2, 4); 43408c2ecf20Sopenharmony_ci vcpu->arch.host_gscb = NULL; 43418c2ecf20Sopenharmony_ci preempt_enable(); 43428c2ecf20Sopenharmony_ci } 43438c2ecf20Sopenharmony_ci /* SIE will save etoken directly into SDNX and therefore kvm_run */ 43448c2ecf20Sopenharmony_ci} 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_cistatic void store_regs(struct kvm_vcpu *vcpu) 43478c2ecf20Sopenharmony_ci{ 43488c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci kvm_run->psw_mask = vcpu->arch.sie_block->gpsw.mask; 43518c2ecf20Sopenharmony_ci kvm_run->psw_addr = vcpu->arch.sie_block->gpsw.addr; 43528c2ecf20Sopenharmony_ci kvm_run->s.regs.prefix = kvm_s390_get_prefix(vcpu); 43538c2ecf20Sopenharmony_ci memcpy(&kvm_run->s.regs.crs, &vcpu->arch.sie_block->gcr, 128); 43548c2ecf20Sopenharmony_ci kvm_run->s.regs.cputm = kvm_s390_get_cpu_timer(vcpu); 43558c2ecf20Sopenharmony_ci kvm_run->s.regs.ckc = vcpu->arch.sie_block->ckc; 43568c2ecf20Sopenharmony_ci kvm_run->s.regs.pft = vcpu->arch.pfault_token; 43578c2ecf20Sopenharmony_ci kvm_run->s.regs.pfs = vcpu->arch.pfault_select; 43588c2ecf20Sopenharmony_ci kvm_run->s.regs.pfc = vcpu->arch.pfault_compare; 43598c2ecf20Sopenharmony_ci save_access_regs(vcpu->run->s.regs.acrs); 43608c2ecf20Sopenharmony_ci restore_access_regs(vcpu->arch.host_acrs); 43618c2ecf20Sopenharmony_ci /* Save guest register state */ 43628c2ecf20Sopenharmony_ci save_fpu_regs(); 43638c2ecf20Sopenharmony_ci vcpu->run->s.regs.fpc = current->thread.fpu.fpc; 43648c2ecf20Sopenharmony_ci /* Restore will be done lazily at return */ 43658c2ecf20Sopenharmony_ci current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc; 43668c2ecf20Sopenharmony_ci current->thread.fpu.regs = vcpu->arch.host_fpregs.regs; 43678c2ecf20Sopenharmony_ci if (likely(!kvm_s390_pv_cpu_is_protected(vcpu))) 43688c2ecf20Sopenharmony_ci store_regs_fmt2(vcpu); 43698c2ecf20Sopenharmony_ci} 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) 43728c2ecf20Sopenharmony_ci{ 43738c2ecf20Sopenharmony_ci struct kvm_run *kvm_run = vcpu->run; 43748c2ecf20Sopenharmony_ci int rc; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci if (kvm_run->immediate_exit) 43778c2ecf20Sopenharmony_ci return -EINTR; 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_ci if (kvm_run->kvm_valid_regs & ~KVM_SYNC_S390_VALID_FIELDS || 43808c2ecf20Sopenharmony_ci kvm_run->kvm_dirty_regs & ~KVM_SYNC_S390_VALID_FIELDS) 43818c2ecf20Sopenharmony_ci return -EINVAL; 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci vcpu_load(vcpu); 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci if (guestdbg_exit_pending(vcpu)) { 43868c2ecf20Sopenharmony_ci kvm_s390_prepare_debug_exit(vcpu); 43878c2ecf20Sopenharmony_ci rc = 0; 43888c2ecf20Sopenharmony_ci goto out; 43898c2ecf20Sopenharmony_ci } 43908c2ecf20Sopenharmony_ci 43918c2ecf20Sopenharmony_ci kvm_sigset_activate(vcpu); 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci /* 43948c2ecf20Sopenharmony_ci * no need to check the return value of vcpu_start as it can only have 43958c2ecf20Sopenharmony_ci * an error for protvirt, but protvirt means user cpu state 43968c2ecf20Sopenharmony_ci */ 43978c2ecf20Sopenharmony_ci if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) { 43988c2ecf20Sopenharmony_ci kvm_s390_vcpu_start(vcpu); 43998c2ecf20Sopenharmony_ci } else if (is_vcpu_stopped(vcpu)) { 44008c2ecf20Sopenharmony_ci pr_err_ratelimited("can't run stopped vcpu %d\n", 44018c2ecf20Sopenharmony_ci vcpu->vcpu_id); 44028c2ecf20Sopenharmony_ci rc = -EINVAL; 44038c2ecf20Sopenharmony_ci goto out; 44048c2ecf20Sopenharmony_ci } 44058c2ecf20Sopenharmony_ci 44068c2ecf20Sopenharmony_ci sync_regs(vcpu); 44078c2ecf20Sopenharmony_ci enable_cpu_timer_accounting(vcpu); 44088c2ecf20Sopenharmony_ci 44098c2ecf20Sopenharmony_ci might_fault(); 44108c2ecf20Sopenharmony_ci rc = __vcpu_run(vcpu); 44118c2ecf20Sopenharmony_ci 44128c2ecf20Sopenharmony_ci if (signal_pending(current) && !rc) { 44138c2ecf20Sopenharmony_ci kvm_run->exit_reason = KVM_EXIT_INTR; 44148c2ecf20Sopenharmony_ci rc = -EINTR; 44158c2ecf20Sopenharmony_ci } 44168c2ecf20Sopenharmony_ci 44178c2ecf20Sopenharmony_ci if (guestdbg_exit_pending(vcpu) && !rc) { 44188c2ecf20Sopenharmony_ci kvm_s390_prepare_debug_exit(vcpu); 44198c2ecf20Sopenharmony_ci rc = 0; 44208c2ecf20Sopenharmony_ci } 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci if (rc == -EREMOTE) { 44238c2ecf20Sopenharmony_ci /* userspace support is needed, kvm_run has been prepared */ 44248c2ecf20Sopenharmony_ci rc = 0; 44258c2ecf20Sopenharmony_ci } 44268c2ecf20Sopenharmony_ci 44278c2ecf20Sopenharmony_ci disable_cpu_timer_accounting(vcpu); 44288c2ecf20Sopenharmony_ci store_regs(vcpu); 44298c2ecf20Sopenharmony_ci 44308c2ecf20Sopenharmony_ci kvm_sigset_deactivate(vcpu); 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci vcpu->stat.exit_userspace++; 44338c2ecf20Sopenharmony_ciout: 44348c2ecf20Sopenharmony_ci vcpu_put(vcpu); 44358c2ecf20Sopenharmony_ci return rc; 44368c2ecf20Sopenharmony_ci} 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci/* 44398c2ecf20Sopenharmony_ci * store status at address 44408c2ecf20Sopenharmony_ci * we use have two special cases: 44418c2ecf20Sopenharmony_ci * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit 44428c2ecf20Sopenharmony_ci * KVM_S390_STORE_STATUS_PREFIXED: -> prefix 44438c2ecf20Sopenharmony_ci */ 44448c2ecf20Sopenharmony_ciint kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa) 44458c2ecf20Sopenharmony_ci{ 44468c2ecf20Sopenharmony_ci unsigned char archmode = 1; 44478c2ecf20Sopenharmony_ci freg_t fprs[NUM_FPRS]; 44488c2ecf20Sopenharmony_ci unsigned int px; 44498c2ecf20Sopenharmony_ci u64 clkcomp, cputm; 44508c2ecf20Sopenharmony_ci int rc; 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci px = kvm_s390_get_prefix(vcpu); 44538c2ecf20Sopenharmony_ci if (gpa == KVM_S390_STORE_STATUS_NOADDR) { 44548c2ecf20Sopenharmony_ci if (write_guest_abs(vcpu, 163, &archmode, 1)) 44558c2ecf20Sopenharmony_ci return -EFAULT; 44568c2ecf20Sopenharmony_ci gpa = 0; 44578c2ecf20Sopenharmony_ci } else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) { 44588c2ecf20Sopenharmony_ci if (write_guest_real(vcpu, 163, &archmode, 1)) 44598c2ecf20Sopenharmony_ci return -EFAULT; 44608c2ecf20Sopenharmony_ci gpa = px; 44618c2ecf20Sopenharmony_ci } else 44628c2ecf20Sopenharmony_ci gpa -= __LC_FPREGS_SAVE_AREA; 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci /* manually convert vector registers if necessary */ 44658c2ecf20Sopenharmony_ci if (MACHINE_HAS_VX) { 44668c2ecf20Sopenharmony_ci convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs); 44678c2ecf20Sopenharmony_ci rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA, 44688c2ecf20Sopenharmony_ci fprs, 128); 44698c2ecf20Sopenharmony_ci } else { 44708c2ecf20Sopenharmony_ci rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA, 44718c2ecf20Sopenharmony_ci vcpu->run->s.regs.fprs, 128); 44728c2ecf20Sopenharmony_ci } 44738c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA, 44748c2ecf20Sopenharmony_ci vcpu->run->s.regs.gprs, 128); 44758c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA, 44768c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gpsw, 16); 44778c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA, 44788c2ecf20Sopenharmony_ci &px, 4); 44798c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA, 44808c2ecf20Sopenharmony_ci &vcpu->run->s.regs.fpc, 4); 44818c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA, 44828c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->todpr, 4); 44838c2ecf20Sopenharmony_ci cputm = kvm_s390_get_cpu_timer(vcpu); 44848c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA, 44858c2ecf20Sopenharmony_ci &cputm, 8); 44868c2ecf20Sopenharmony_ci clkcomp = vcpu->arch.sie_block->ckc >> 8; 44878c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_CLOCK_COMP_SAVE_AREA, 44888c2ecf20Sopenharmony_ci &clkcomp, 8); 44898c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_AREGS_SAVE_AREA, 44908c2ecf20Sopenharmony_ci &vcpu->run->s.regs.acrs, 64); 44918c2ecf20Sopenharmony_ci rc |= write_guest_abs(vcpu, gpa + __LC_CREGS_SAVE_AREA, 44928c2ecf20Sopenharmony_ci &vcpu->arch.sie_block->gcr, 128); 44938c2ecf20Sopenharmony_ci return rc ? -EFAULT : 0; 44948c2ecf20Sopenharmony_ci} 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ciint kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) 44978c2ecf20Sopenharmony_ci{ 44988c2ecf20Sopenharmony_ci /* 44998c2ecf20Sopenharmony_ci * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy 45008c2ecf20Sopenharmony_ci * switch in the run ioctl. Let's update our copies before we save 45018c2ecf20Sopenharmony_ci * it into the save area 45028c2ecf20Sopenharmony_ci */ 45038c2ecf20Sopenharmony_ci save_fpu_regs(); 45048c2ecf20Sopenharmony_ci vcpu->run->s.regs.fpc = current->thread.fpu.fpc; 45058c2ecf20Sopenharmony_ci save_access_regs(vcpu->run->s.regs.acrs); 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci return kvm_s390_store_status_unloaded(vcpu, addr); 45088c2ecf20Sopenharmony_ci} 45098c2ecf20Sopenharmony_ci 45108c2ecf20Sopenharmony_cistatic void __disable_ibs_on_vcpu(struct kvm_vcpu *vcpu) 45118c2ecf20Sopenharmony_ci{ 45128c2ecf20Sopenharmony_ci kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu); 45138c2ecf20Sopenharmony_ci kvm_s390_sync_request(KVM_REQ_DISABLE_IBS, vcpu); 45148c2ecf20Sopenharmony_ci} 45158c2ecf20Sopenharmony_ci 45168c2ecf20Sopenharmony_cistatic void __disable_ibs_on_all_vcpus(struct kvm *kvm) 45178c2ecf20Sopenharmony_ci{ 45188c2ecf20Sopenharmony_ci unsigned int i; 45198c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) { 45228c2ecf20Sopenharmony_ci __disable_ibs_on_vcpu(vcpu); 45238c2ecf20Sopenharmony_ci } 45248c2ecf20Sopenharmony_ci} 45258c2ecf20Sopenharmony_ci 45268c2ecf20Sopenharmony_cistatic void __enable_ibs_on_vcpu(struct kvm_vcpu *vcpu) 45278c2ecf20Sopenharmony_ci{ 45288c2ecf20Sopenharmony_ci if (!sclp.has_ibs) 45298c2ecf20Sopenharmony_ci return; 45308c2ecf20Sopenharmony_ci kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu); 45318c2ecf20Sopenharmony_ci kvm_s390_sync_request(KVM_REQ_ENABLE_IBS, vcpu); 45328c2ecf20Sopenharmony_ci} 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ciint kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) 45358c2ecf20Sopenharmony_ci{ 45368c2ecf20Sopenharmony_ci int i, online_vcpus, r = 0, started_vcpus = 0; 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_ci if (!is_vcpu_stopped(vcpu)) 45398c2ecf20Sopenharmony_ci return 0; 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1); 45428c2ecf20Sopenharmony_ci /* Only one cpu at a time may enter/leave the STOPPED state. */ 45438c2ecf20Sopenharmony_ci spin_lock(&vcpu->kvm->arch.start_stop_lock); 45448c2ecf20Sopenharmony_ci online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); 45458c2ecf20Sopenharmony_ci 45468c2ecf20Sopenharmony_ci /* Let's tell the UV that we want to change into the operating state */ 45478c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 45488c2ecf20Sopenharmony_ci r = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_OPR); 45498c2ecf20Sopenharmony_ci if (r) { 45508c2ecf20Sopenharmony_ci spin_unlock(&vcpu->kvm->arch.start_stop_lock); 45518c2ecf20Sopenharmony_ci return r; 45528c2ecf20Sopenharmony_ci } 45538c2ecf20Sopenharmony_ci } 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci for (i = 0; i < online_vcpus; i++) { 45568c2ecf20Sopenharmony_ci if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) 45578c2ecf20Sopenharmony_ci started_vcpus++; 45588c2ecf20Sopenharmony_ci } 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci if (started_vcpus == 0) { 45618c2ecf20Sopenharmony_ci /* we're the only active VCPU -> speed it up */ 45628c2ecf20Sopenharmony_ci __enable_ibs_on_vcpu(vcpu); 45638c2ecf20Sopenharmony_ci } else if (started_vcpus == 1) { 45648c2ecf20Sopenharmony_ci /* 45658c2ecf20Sopenharmony_ci * As we are starting a second VCPU, we have to disable 45668c2ecf20Sopenharmony_ci * the IBS facility on all VCPUs to remove potentially 45678c2ecf20Sopenharmony_ci * oustanding ENABLE requests. 45688c2ecf20Sopenharmony_ci */ 45698c2ecf20Sopenharmony_ci __disable_ibs_on_all_vcpus(vcpu->kvm); 45708c2ecf20Sopenharmony_ci } 45718c2ecf20Sopenharmony_ci 45728c2ecf20Sopenharmony_ci kvm_s390_clear_cpuflags(vcpu, CPUSTAT_STOPPED); 45738c2ecf20Sopenharmony_ci /* 45748c2ecf20Sopenharmony_ci * The real PSW might have changed due to a RESTART interpreted by the 45758c2ecf20Sopenharmony_ci * ultravisor. We block all interrupts and let the next sie exit 45768c2ecf20Sopenharmony_ci * refresh our view. 45778c2ecf20Sopenharmony_ci */ 45788c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) 45798c2ecf20Sopenharmony_ci vcpu->arch.sie_block->gpsw.mask &= ~PSW_INT_MASK; 45808c2ecf20Sopenharmony_ci /* 45818c2ecf20Sopenharmony_ci * Another VCPU might have used IBS while we were offline. 45828c2ecf20Sopenharmony_ci * Let's play safe and flush the VCPU at startup. 45838c2ecf20Sopenharmony_ci */ 45848c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); 45858c2ecf20Sopenharmony_ci spin_unlock(&vcpu->kvm->arch.start_stop_lock); 45868c2ecf20Sopenharmony_ci return 0; 45878c2ecf20Sopenharmony_ci} 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_ciint kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) 45908c2ecf20Sopenharmony_ci{ 45918c2ecf20Sopenharmony_ci int i, online_vcpus, r = 0, started_vcpus = 0; 45928c2ecf20Sopenharmony_ci struct kvm_vcpu *started_vcpu = NULL; 45938c2ecf20Sopenharmony_ci 45948c2ecf20Sopenharmony_ci if (is_vcpu_stopped(vcpu)) 45958c2ecf20Sopenharmony_ci return 0; 45968c2ecf20Sopenharmony_ci 45978c2ecf20Sopenharmony_ci trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0); 45988c2ecf20Sopenharmony_ci /* Only one cpu at a time may enter/leave the STOPPED state. */ 45998c2ecf20Sopenharmony_ci spin_lock(&vcpu->kvm->arch.start_stop_lock); 46008c2ecf20Sopenharmony_ci online_vcpus = atomic_read(&vcpu->kvm->online_vcpus); 46018c2ecf20Sopenharmony_ci 46028c2ecf20Sopenharmony_ci /* Let's tell the UV that we want to change into the stopped state */ 46038c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 46048c2ecf20Sopenharmony_ci r = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_STP); 46058c2ecf20Sopenharmony_ci if (r) { 46068c2ecf20Sopenharmony_ci spin_unlock(&vcpu->kvm->arch.start_stop_lock); 46078c2ecf20Sopenharmony_ci return r; 46088c2ecf20Sopenharmony_ci } 46098c2ecf20Sopenharmony_ci } 46108c2ecf20Sopenharmony_ci 46118c2ecf20Sopenharmony_ci /* 46128c2ecf20Sopenharmony_ci * Set the VCPU to STOPPED and THEN clear the interrupt flag, 46138c2ecf20Sopenharmony_ci * now that the SIGP STOP and SIGP STOP AND STORE STATUS orders 46148c2ecf20Sopenharmony_ci * have been fully processed. This will ensure that the VCPU 46158c2ecf20Sopenharmony_ci * is kept BUSY if another VCPU is inquiring with SIGP SENSE. 46168c2ecf20Sopenharmony_ci */ 46178c2ecf20Sopenharmony_ci kvm_s390_set_cpuflags(vcpu, CPUSTAT_STOPPED); 46188c2ecf20Sopenharmony_ci kvm_s390_clear_stop_irq(vcpu); 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ci __disable_ibs_on_vcpu(vcpu); 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci for (i = 0; i < online_vcpus; i++) { 46238c2ecf20Sopenharmony_ci if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) { 46248c2ecf20Sopenharmony_ci started_vcpus++; 46258c2ecf20Sopenharmony_ci started_vcpu = vcpu->kvm->vcpus[i]; 46268c2ecf20Sopenharmony_ci } 46278c2ecf20Sopenharmony_ci } 46288c2ecf20Sopenharmony_ci 46298c2ecf20Sopenharmony_ci if (started_vcpus == 1) { 46308c2ecf20Sopenharmony_ci /* 46318c2ecf20Sopenharmony_ci * As we only have one VCPU left, we want to enable the 46328c2ecf20Sopenharmony_ci * IBS facility for that VCPU to speed it up. 46338c2ecf20Sopenharmony_ci */ 46348c2ecf20Sopenharmony_ci __enable_ibs_on_vcpu(started_vcpu); 46358c2ecf20Sopenharmony_ci } 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_ci spin_unlock(&vcpu->kvm->arch.start_stop_lock); 46388c2ecf20Sopenharmony_ci return 0; 46398c2ecf20Sopenharmony_ci} 46408c2ecf20Sopenharmony_ci 46418c2ecf20Sopenharmony_cistatic int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, 46428c2ecf20Sopenharmony_ci struct kvm_enable_cap *cap) 46438c2ecf20Sopenharmony_ci{ 46448c2ecf20Sopenharmony_ci int r; 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_ci if (cap->flags) 46478c2ecf20Sopenharmony_ci return -EINVAL; 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_ci switch (cap->cap) { 46508c2ecf20Sopenharmony_ci case KVM_CAP_S390_CSS_SUPPORT: 46518c2ecf20Sopenharmony_ci if (!vcpu->kvm->arch.css_support) { 46528c2ecf20Sopenharmony_ci vcpu->kvm->arch.css_support = 1; 46538c2ecf20Sopenharmony_ci VM_EVENT(vcpu->kvm, 3, "%s", "ENABLE: CSS support"); 46548c2ecf20Sopenharmony_ci trace_kvm_s390_enable_css(vcpu->kvm); 46558c2ecf20Sopenharmony_ci } 46568c2ecf20Sopenharmony_ci r = 0; 46578c2ecf20Sopenharmony_ci break; 46588c2ecf20Sopenharmony_ci default: 46598c2ecf20Sopenharmony_ci r = -EINVAL; 46608c2ecf20Sopenharmony_ci break; 46618c2ecf20Sopenharmony_ci } 46628c2ecf20Sopenharmony_ci return r; 46638c2ecf20Sopenharmony_ci} 46648c2ecf20Sopenharmony_ci 46658c2ecf20Sopenharmony_cistatic long kvm_s390_guest_sida_op(struct kvm_vcpu *vcpu, 46668c2ecf20Sopenharmony_ci struct kvm_s390_mem_op *mop) 46678c2ecf20Sopenharmony_ci{ 46688c2ecf20Sopenharmony_ci void __user *uaddr = (void __user *)mop->buf; 46698c2ecf20Sopenharmony_ci int r = 0; 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci if (mop->flags || !mop->size) 46728c2ecf20Sopenharmony_ci return -EINVAL; 46738c2ecf20Sopenharmony_ci if (mop->size + mop->sida_offset < mop->size) 46748c2ecf20Sopenharmony_ci return -EINVAL; 46758c2ecf20Sopenharmony_ci if (mop->size + mop->sida_offset > sida_size(vcpu->arch.sie_block)) 46768c2ecf20Sopenharmony_ci return -E2BIG; 46778c2ecf20Sopenharmony_ci if (!kvm_s390_pv_cpu_is_protected(vcpu)) 46788c2ecf20Sopenharmony_ci return -EINVAL; 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci switch (mop->op) { 46818c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_SIDA_READ: 46828c2ecf20Sopenharmony_ci if (copy_to_user(uaddr, (void *)(sida_origin(vcpu->arch.sie_block) + 46838c2ecf20Sopenharmony_ci mop->sida_offset), mop->size)) 46848c2ecf20Sopenharmony_ci r = -EFAULT; 46858c2ecf20Sopenharmony_ci 46868c2ecf20Sopenharmony_ci break; 46878c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_SIDA_WRITE: 46888c2ecf20Sopenharmony_ci if (copy_from_user((void *)(sida_origin(vcpu->arch.sie_block) + 46898c2ecf20Sopenharmony_ci mop->sida_offset), uaddr, mop->size)) 46908c2ecf20Sopenharmony_ci r = -EFAULT; 46918c2ecf20Sopenharmony_ci break; 46928c2ecf20Sopenharmony_ci } 46938c2ecf20Sopenharmony_ci return r; 46948c2ecf20Sopenharmony_ci} 46958c2ecf20Sopenharmony_cistatic long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, 46968c2ecf20Sopenharmony_ci struct kvm_s390_mem_op *mop) 46978c2ecf20Sopenharmony_ci{ 46988c2ecf20Sopenharmony_ci void __user *uaddr = (void __user *)mop->buf; 46998c2ecf20Sopenharmony_ci void *tmpbuf = NULL; 47008c2ecf20Sopenharmony_ci int r = 0; 47018c2ecf20Sopenharmony_ci const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION 47028c2ecf20Sopenharmony_ci | KVM_S390_MEMOP_F_CHECK_ONLY; 47038c2ecf20Sopenharmony_ci 47048c2ecf20Sopenharmony_ci if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size) 47058c2ecf20Sopenharmony_ci return -EINVAL; 47068c2ecf20Sopenharmony_ci 47078c2ecf20Sopenharmony_ci if (mop->size > MEM_OP_MAX_SIZE) 47088c2ecf20Sopenharmony_ci return -E2BIG; 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) 47118c2ecf20Sopenharmony_ci return -EINVAL; 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci if (!(mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY)) { 47148c2ecf20Sopenharmony_ci tmpbuf = vmalloc(mop->size); 47158c2ecf20Sopenharmony_ci if (!tmpbuf) 47168c2ecf20Sopenharmony_ci return -ENOMEM; 47178c2ecf20Sopenharmony_ci } 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ci switch (mop->op) { 47208c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_LOGICAL_READ: 47218c2ecf20Sopenharmony_ci if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) { 47228c2ecf20Sopenharmony_ci r = check_gva_range(vcpu, mop->gaddr, mop->ar, 47238c2ecf20Sopenharmony_ci mop->size, GACC_FETCH); 47248c2ecf20Sopenharmony_ci break; 47258c2ecf20Sopenharmony_ci } 47268c2ecf20Sopenharmony_ci r = read_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size); 47278c2ecf20Sopenharmony_ci if (r == 0) { 47288c2ecf20Sopenharmony_ci if (copy_to_user(uaddr, tmpbuf, mop->size)) 47298c2ecf20Sopenharmony_ci r = -EFAULT; 47308c2ecf20Sopenharmony_ci } 47318c2ecf20Sopenharmony_ci break; 47328c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_LOGICAL_WRITE: 47338c2ecf20Sopenharmony_ci if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) { 47348c2ecf20Sopenharmony_ci r = check_gva_range(vcpu, mop->gaddr, mop->ar, 47358c2ecf20Sopenharmony_ci mop->size, GACC_STORE); 47368c2ecf20Sopenharmony_ci break; 47378c2ecf20Sopenharmony_ci } 47388c2ecf20Sopenharmony_ci if (copy_from_user(tmpbuf, uaddr, mop->size)) { 47398c2ecf20Sopenharmony_ci r = -EFAULT; 47408c2ecf20Sopenharmony_ci break; 47418c2ecf20Sopenharmony_ci } 47428c2ecf20Sopenharmony_ci r = write_guest(vcpu, mop->gaddr, mop->ar, tmpbuf, mop->size); 47438c2ecf20Sopenharmony_ci break; 47448c2ecf20Sopenharmony_ci } 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci if (r > 0 && (mop->flags & KVM_S390_MEMOP_F_INJECT_EXCEPTION) != 0) 47478c2ecf20Sopenharmony_ci kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm); 47488c2ecf20Sopenharmony_ci 47498c2ecf20Sopenharmony_ci vfree(tmpbuf); 47508c2ecf20Sopenharmony_ci return r; 47518c2ecf20Sopenharmony_ci} 47528c2ecf20Sopenharmony_ci 47538c2ecf20Sopenharmony_cistatic long kvm_s390_guest_memsida_op(struct kvm_vcpu *vcpu, 47548c2ecf20Sopenharmony_ci struct kvm_s390_mem_op *mop) 47558c2ecf20Sopenharmony_ci{ 47568c2ecf20Sopenharmony_ci int r, srcu_idx; 47578c2ecf20Sopenharmony_ci 47588c2ecf20Sopenharmony_ci srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 47598c2ecf20Sopenharmony_ci 47608c2ecf20Sopenharmony_ci switch (mop->op) { 47618c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_LOGICAL_READ: 47628c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_LOGICAL_WRITE: 47638c2ecf20Sopenharmony_ci r = kvm_s390_guest_mem_op(vcpu, mop); 47648c2ecf20Sopenharmony_ci break; 47658c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_SIDA_READ: 47668c2ecf20Sopenharmony_ci case KVM_S390_MEMOP_SIDA_WRITE: 47678c2ecf20Sopenharmony_ci /* we are locked against sida going away by the vcpu->mutex */ 47688c2ecf20Sopenharmony_ci r = kvm_s390_guest_sida_op(vcpu, mop); 47698c2ecf20Sopenharmony_ci break; 47708c2ecf20Sopenharmony_ci default: 47718c2ecf20Sopenharmony_ci r = -EINVAL; 47728c2ecf20Sopenharmony_ci } 47738c2ecf20Sopenharmony_ci 47748c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); 47758c2ecf20Sopenharmony_ci return r; 47768c2ecf20Sopenharmony_ci} 47778c2ecf20Sopenharmony_ci 47788c2ecf20Sopenharmony_cilong kvm_arch_vcpu_async_ioctl(struct file *filp, 47798c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 47808c2ecf20Sopenharmony_ci{ 47818c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = filp->private_data; 47828c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 47838c2ecf20Sopenharmony_ci 47848c2ecf20Sopenharmony_ci switch (ioctl) { 47858c2ecf20Sopenharmony_ci case KVM_S390_IRQ: { 47868c2ecf20Sopenharmony_ci struct kvm_s390_irq s390irq; 47878c2ecf20Sopenharmony_ci 47888c2ecf20Sopenharmony_ci if (copy_from_user(&s390irq, argp, sizeof(s390irq))) 47898c2ecf20Sopenharmony_ci return -EFAULT; 47908c2ecf20Sopenharmony_ci return kvm_s390_inject_vcpu(vcpu, &s390irq); 47918c2ecf20Sopenharmony_ci } 47928c2ecf20Sopenharmony_ci case KVM_S390_INTERRUPT: { 47938c2ecf20Sopenharmony_ci struct kvm_s390_interrupt s390int; 47948c2ecf20Sopenharmony_ci struct kvm_s390_irq s390irq = {}; 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci if (copy_from_user(&s390int, argp, sizeof(s390int))) 47978c2ecf20Sopenharmony_ci return -EFAULT; 47988c2ecf20Sopenharmony_ci if (s390int_to_s390irq(&s390int, &s390irq)) 47998c2ecf20Sopenharmony_ci return -EINVAL; 48008c2ecf20Sopenharmony_ci return kvm_s390_inject_vcpu(vcpu, &s390irq); 48018c2ecf20Sopenharmony_ci } 48028c2ecf20Sopenharmony_ci } 48038c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 48048c2ecf20Sopenharmony_ci} 48058c2ecf20Sopenharmony_ci 48068c2ecf20Sopenharmony_cilong kvm_arch_vcpu_ioctl(struct file *filp, 48078c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 48088c2ecf20Sopenharmony_ci{ 48098c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = filp->private_data; 48108c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 48118c2ecf20Sopenharmony_ci int idx; 48128c2ecf20Sopenharmony_ci long r; 48138c2ecf20Sopenharmony_ci u16 rc, rrc; 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci vcpu_load(vcpu); 48168c2ecf20Sopenharmony_ci 48178c2ecf20Sopenharmony_ci switch (ioctl) { 48188c2ecf20Sopenharmony_ci case KVM_S390_STORE_STATUS: 48198c2ecf20Sopenharmony_ci idx = srcu_read_lock(&vcpu->kvm->srcu); 48208c2ecf20Sopenharmony_ci r = kvm_s390_store_status_unloaded(vcpu, arg); 48218c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, idx); 48228c2ecf20Sopenharmony_ci break; 48238c2ecf20Sopenharmony_ci case KVM_S390_SET_INITIAL_PSW: { 48248c2ecf20Sopenharmony_ci psw_t psw; 48258c2ecf20Sopenharmony_ci 48268c2ecf20Sopenharmony_ci r = -EFAULT; 48278c2ecf20Sopenharmony_ci if (copy_from_user(&psw, argp, sizeof(psw))) 48288c2ecf20Sopenharmony_ci break; 48298c2ecf20Sopenharmony_ci r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); 48308c2ecf20Sopenharmony_ci break; 48318c2ecf20Sopenharmony_ci } 48328c2ecf20Sopenharmony_ci case KVM_S390_CLEAR_RESET: 48338c2ecf20Sopenharmony_ci r = 0; 48348c2ecf20Sopenharmony_ci kvm_arch_vcpu_ioctl_clear_reset(vcpu); 48358c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 48368c2ecf20Sopenharmony_ci r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu), 48378c2ecf20Sopenharmony_ci UVC_CMD_CPU_RESET_CLEAR, &rc, &rrc); 48388c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "PROTVIRT RESET CLEAR VCPU: rc %x rrc %x", 48398c2ecf20Sopenharmony_ci rc, rrc); 48408c2ecf20Sopenharmony_ci } 48418c2ecf20Sopenharmony_ci break; 48428c2ecf20Sopenharmony_ci case KVM_S390_INITIAL_RESET: 48438c2ecf20Sopenharmony_ci r = 0; 48448c2ecf20Sopenharmony_ci kvm_arch_vcpu_ioctl_initial_reset(vcpu); 48458c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 48468c2ecf20Sopenharmony_ci r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu), 48478c2ecf20Sopenharmony_ci UVC_CMD_CPU_RESET_INITIAL, 48488c2ecf20Sopenharmony_ci &rc, &rrc); 48498c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "PROTVIRT RESET INITIAL VCPU: rc %x rrc %x", 48508c2ecf20Sopenharmony_ci rc, rrc); 48518c2ecf20Sopenharmony_ci } 48528c2ecf20Sopenharmony_ci break; 48538c2ecf20Sopenharmony_ci case KVM_S390_NORMAL_RESET: 48548c2ecf20Sopenharmony_ci r = 0; 48558c2ecf20Sopenharmony_ci kvm_arch_vcpu_ioctl_normal_reset(vcpu); 48568c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) { 48578c2ecf20Sopenharmony_ci r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu), 48588c2ecf20Sopenharmony_ci UVC_CMD_CPU_RESET, &rc, &rrc); 48598c2ecf20Sopenharmony_ci VCPU_EVENT(vcpu, 3, "PROTVIRT RESET NORMAL VCPU: rc %x rrc %x", 48608c2ecf20Sopenharmony_ci rc, rrc); 48618c2ecf20Sopenharmony_ci } 48628c2ecf20Sopenharmony_ci break; 48638c2ecf20Sopenharmony_ci case KVM_SET_ONE_REG: 48648c2ecf20Sopenharmony_ci case KVM_GET_ONE_REG: { 48658c2ecf20Sopenharmony_ci struct kvm_one_reg reg; 48668c2ecf20Sopenharmony_ci r = -EINVAL; 48678c2ecf20Sopenharmony_ci if (kvm_s390_pv_cpu_is_protected(vcpu)) 48688c2ecf20Sopenharmony_ci break; 48698c2ecf20Sopenharmony_ci r = -EFAULT; 48708c2ecf20Sopenharmony_ci if (copy_from_user(®, argp, sizeof(reg))) 48718c2ecf20Sopenharmony_ci break; 48728c2ecf20Sopenharmony_ci if (ioctl == KVM_SET_ONE_REG) 48738c2ecf20Sopenharmony_ci r = kvm_arch_vcpu_ioctl_set_one_reg(vcpu, ®); 48748c2ecf20Sopenharmony_ci else 48758c2ecf20Sopenharmony_ci r = kvm_arch_vcpu_ioctl_get_one_reg(vcpu, ®); 48768c2ecf20Sopenharmony_ci break; 48778c2ecf20Sopenharmony_ci } 48788c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_S390_UCONTROL 48798c2ecf20Sopenharmony_ci case KVM_S390_UCAS_MAP: { 48808c2ecf20Sopenharmony_ci struct kvm_s390_ucas_mapping ucasmap; 48818c2ecf20Sopenharmony_ci 48828c2ecf20Sopenharmony_ci if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) { 48838c2ecf20Sopenharmony_ci r = -EFAULT; 48848c2ecf20Sopenharmony_ci break; 48858c2ecf20Sopenharmony_ci } 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(vcpu->kvm)) { 48888c2ecf20Sopenharmony_ci r = -EINVAL; 48898c2ecf20Sopenharmony_ci break; 48908c2ecf20Sopenharmony_ci } 48918c2ecf20Sopenharmony_ci 48928c2ecf20Sopenharmony_ci r = gmap_map_segment(vcpu->arch.gmap, ucasmap.user_addr, 48938c2ecf20Sopenharmony_ci ucasmap.vcpu_addr, ucasmap.length); 48948c2ecf20Sopenharmony_ci break; 48958c2ecf20Sopenharmony_ci } 48968c2ecf20Sopenharmony_ci case KVM_S390_UCAS_UNMAP: { 48978c2ecf20Sopenharmony_ci struct kvm_s390_ucas_mapping ucasmap; 48988c2ecf20Sopenharmony_ci 48998c2ecf20Sopenharmony_ci if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) { 49008c2ecf20Sopenharmony_ci r = -EFAULT; 49018c2ecf20Sopenharmony_ci break; 49028c2ecf20Sopenharmony_ci } 49038c2ecf20Sopenharmony_ci 49048c2ecf20Sopenharmony_ci if (!kvm_is_ucontrol(vcpu->kvm)) { 49058c2ecf20Sopenharmony_ci r = -EINVAL; 49068c2ecf20Sopenharmony_ci break; 49078c2ecf20Sopenharmony_ci } 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ci r = gmap_unmap_segment(vcpu->arch.gmap, ucasmap.vcpu_addr, 49108c2ecf20Sopenharmony_ci ucasmap.length); 49118c2ecf20Sopenharmony_ci break; 49128c2ecf20Sopenharmony_ci } 49138c2ecf20Sopenharmony_ci#endif 49148c2ecf20Sopenharmony_ci case KVM_S390_VCPU_FAULT: { 49158c2ecf20Sopenharmony_ci r = gmap_fault(vcpu->arch.gmap, arg, 0); 49168c2ecf20Sopenharmony_ci break; 49178c2ecf20Sopenharmony_ci } 49188c2ecf20Sopenharmony_ci case KVM_ENABLE_CAP: 49198c2ecf20Sopenharmony_ci { 49208c2ecf20Sopenharmony_ci struct kvm_enable_cap cap; 49218c2ecf20Sopenharmony_ci r = -EFAULT; 49228c2ecf20Sopenharmony_ci if (copy_from_user(&cap, argp, sizeof(cap))) 49238c2ecf20Sopenharmony_ci break; 49248c2ecf20Sopenharmony_ci r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); 49258c2ecf20Sopenharmony_ci break; 49268c2ecf20Sopenharmony_ci } 49278c2ecf20Sopenharmony_ci case KVM_S390_MEM_OP: { 49288c2ecf20Sopenharmony_ci struct kvm_s390_mem_op mem_op; 49298c2ecf20Sopenharmony_ci 49308c2ecf20Sopenharmony_ci if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0) 49318c2ecf20Sopenharmony_ci r = kvm_s390_guest_memsida_op(vcpu, &mem_op); 49328c2ecf20Sopenharmony_ci else 49338c2ecf20Sopenharmony_ci r = -EFAULT; 49348c2ecf20Sopenharmony_ci break; 49358c2ecf20Sopenharmony_ci } 49368c2ecf20Sopenharmony_ci case KVM_S390_SET_IRQ_STATE: { 49378c2ecf20Sopenharmony_ci struct kvm_s390_irq_state irq_state; 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci r = -EFAULT; 49408c2ecf20Sopenharmony_ci if (copy_from_user(&irq_state, argp, sizeof(irq_state))) 49418c2ecf20Sopenharmony_ci break; 49428c2ecf20Sopenharmony_ci if (irq_state.len > VCPU_IRQS_MAX_BUF || 49438c2ecf20Sopenharmony_ci irq_state.len == 0 || 49448c2ecf20Sopenharmony_ci irq_state.len % sizeof(struct kvm_s390_irq) > 0) { 49458c2ecf20Sopenharmony_ci r = -EINVAL; 49468c2ecf20Sopenharmony_ci break; 49478c2ecf20Sopenharmony_ci } 49488c2ecf20Sopenharmony_ci /* do not use irq_state.flags, it will break old QEMUs */ 49498c2ecf20Sopenharmony_ci r = kvm_s390_set_irq_state(vcpu, 49508c2ecf20Sopenharmony_ci (void __user *) irq_state.buf, 49518c2ecf20Sopenharmony_ci irq_state.len); 49528c2ecf20Sopenharmony_ci break; 49538c2ecf20Sopenharmony_ci } 49548c2ecf20Sopenharmony_ci case KVM_S390_GET_IRQ_STATE: { 49558c2ecf20Sopenharmony_ci struct kvm_s390_irq_state irq_state; 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci r = -EFAULT; 49588c2ecf20Sopenharmony_ci if (copy_from_user(&irq_state, argp, sizeof(irq_state))) 49598c2ecf20Sopenharmony_ci break; 49608c2ecf20Sopenharmony_ci if (irq_state.len == 0) { 49618c2ecf20Sopenharmony_ci r = -EINVAL; 49628c2ecf20Sopenharmony_ci break; 49638c2ecf20Sopenharmony_ci } 49648c2ecf20Sopenharmony_ci /* do not use irq_state.flags, it will break old QEMUs */ 49658c2ecf20Sopenharmony_ci r = kvm_s390_get_irq_state(vcpu, 49668c2ecf20Sopenharmony_ci (__u8 __user *) irq_state.buf, 49678c2ecf20Sopenharmony_ci irq_state.len); 49688c2ecf20Sopenharmony_ci break; 49698c2ecf20Sopenharmony_ci } 49708c2ecf20Sopenharmony_ci default: 49718c2ecf20Sopenharmony_ci r = -ENOTTY; 49728c2ecf20Sopenharmony_ci } 49738c2ecf20Sopenharmony_ci 49748c2ecf20Sopenharmony_ci vcpu_put(vcpu); 49758c2ecf20Sopenharmony_ci return r; 49768c2ecf20Sopenharmony_ci} 49778c2ecf20Sopenharmony_ci 49788c2ecf20Sopenharmony_civm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) 49798c2ecf20Sopenharmony_ci{ 49808c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_S390_UCONTROL 49818c2ecf20Sopenharmony_ci if ((vmf->pgoff == KVM_S390_SIE_PAGE_OFFSET) 49828c2ecf20Sopenharmony_ci && (kvm_is_ucontrol(vcpu->kvm))) { 49838c2ecf20Sopenharmony_ci vmf->page = virt_to_page(vcpu->arch.sie_block); 49848c2ecf20Sopenharmony_ci get_page(vmf->page); 49858c2ecf20Sopenharmony_ci return 0; 49868c2ecf20Sopenharmony_ci } 49878c2ecf20Sopenharmony_ci#endif 49888c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 49898c2ecf20Sopenharmony_ci} 49908c2ecf20Sopenharmony_ci 49918c2ecf20Sopenharmony_ci/* Section: memory related */ 49928c2ecf20Sopenharmony_ciint kvm_arch_prepare_memory_region(struct kvm *kvm, 49938c2ecf20Sopenharmony_ci struct kvm_memory_slot *memslot, 49948c2ecf20Sopenharmony_ci const struct kvm_userspace_memory_region *mem, 49958c2ecf20Sopenharmony_ci enum kvm_mr_change change) 49968c2ecf20Sopenharmony_ci{ 49978c2ecf20Sopenharmony_ci /* A few sanity checks. We can have memory slots which have to be 49988c2ecf20Sopenharmony_ci located/ended at a segment boundary (1MB). The memory in userland is 49998c2ecf20Sopenharmony_ci ok to be fragmented into various different vmas. It is okay to mmap() 50008c2ecf20Sopenharmony_ci and munmap() stuff in this slot after doing this call at any time */ 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci if (mem->userspace_addr & 0xffffful) 50038c2ecf20Sopenharmony_ci return -EINVAL; 50048c2ecf20Sopenharmony_ci 50058c2ecf20Sopenharmony_ci if (mem->memory_size & 0xffffful) 50068c2ecf20Sopenharmony_ci return -EINVAL; 50078c2ecf20Sopenharmony_ci 50088c2ecf20Sopenharmony_ci if (mem->guest_phys_addr + mem->memory_size > kvm->arch.mem_limit) 50098c2ecf20Sopenharmony_ci return -EINVAL; 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci /* When we are protected, we should not change the memory slots */ 50128c2ecf20Sopenharmony_ci if (kvm_s390_pv_get_handle(kvm)) 50138c2ecf20Sopenharmony_ci return -EINVAL; 50148c2ecf20Sopenharmony_ci 50158c2ecf20Sopenharmony_ci if (!kvm->arch.migration_mode) 50168c2ecf20Sopenharmony_ci return 0; 50178c2ecf20Sopenharmony_ci 50188c2ecf20Sopenharmony_ci /* 50198c2ecf20Sopenharmony_ci * Turn off migration mode when: 50208c2ecf20Sopenharmony_ci * - userspace creates a new memslot with dirty logging off, 50218c2ecf20Sopenharmony_ci * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and 50228c2ecf20Sopenharmony_ci * dirty logging is turned off. 50238c2ecf20Sopenharmony_ci * Migration mode expects dirty page logging being enabled to store 50248c2ecf20Sopenharmony_ci * its dirty bitmap. 50258c2ecf20Sopenharmony_ci */ 50268c2ecf20Sopenharmony_ci if (change != KVM_MR_DELETE && 50278c2ecf20Sopenharmony_ci !(mem->flags & KVM_MEM_LOG_DIRTY_PAGES)) 50288c2ecf20Sopenharmony_ci WARN(kvm_s390_vm_stop_migration(kvm), 50298c2ecf20Sopenharmony_ci "Failed to stop migration mode"); 50308c2ecf20Sopenharmony_ci 50318c2ecf20Sopenharmony_ci return 0; 50328c2ecf20Sopenharmony_ci} 50338c2ecf20Sopenharmony_ci 50348c2ecf20Sopenharmony_civoid kvm_arch_commit_memory_region(struct kvm *kvm, 50358c2ecf20Sopenharmony_ci const struct kvm_userspace_memory_region *mem, 50368c2ecf20Sopenharmony_ci struct kvm_memory_slot *old, 50378c2ecf20Sopenharmony_ci const struct kvm_memory_slot *new, 50388c2ecf20Sopenharmony_ci enum kvm_mr_change change) 50398c2ecf20Sopenharmony_ci{ 50408c2ecf20Sopenharmony_ci int rc = 0; 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_ci switch (change) { 50438c2ecf20Sopenharmony_ci case KVM_MR_DELETE: 50448c2ecf20Sopenharmony_ci rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE, 50458c2ecf20Sopenharmony_ci old->npages * PAGE_SIZE); 50468c2ecf20Sopenharmony_ci break; 50478c2ecf20Sopenharmony_ci case KVM_MR_MOVE: 50488c2ecf20Sopenharmony_ci rc = gmap_unmap_segment(kvm->arch.gmap, old->base_gfn * PAGE_SIZE, 50498c2ecf20Sopenharmony_ci old->npages * PAGE_SIZE); 50508c2ecf20Sopenharmony_ci if (rc) 50518c2ecf20Sopenharmony_ci break; 50528c2ecf20Sopenharmony_ci fallthrough; 50538c2ecf20Sopenharmony_ci case KVM_MR_CREATE: 50548c2ecf20Sopenharmony_ci rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr, 50558c2ecf20Sopenharmony_ci mem->guest_phys_addr, mem->memory_size); 50568c2ecf20Sopenharmony_ci break; 50578c2ecf20Sopenharmony_ci case KVM_MR_FLAGS_ONLY: 50588c2ecf20Sopenharmony_ci break; 50598c2ecf20Sopenharmony_ci default: 50608c2ecf20Sopenharmony_ci WARN(1, "Unknown KVM MR CHANGE: %d\n", change); 50618c2ecf20Sopenharmony_ci } 50628c2ecf20Sopenharmony_ci if (rc) 50638c2ecf20Sopenharmony_ci pr_warn("failed to commit memory region\n"); 50648c2ecf20Sopenharmony_ci return; 50658c2ecf20Sopenharmony_ci} 50668c2ecf20Sopenharmony_ci 50678c2ecf20Sopenharmony_cistatic inline unsigned long nonhyp_mask(int i) 50688c2ecf20Sopenharmony_ci{ 50698c2ecf20Sopenharmony_ci unsigned int nonhyp_fai = (sclp.hmfai << i * 2) >> 30; 50708c2ecf20Sopenharmony_ci 50718c2ecf20Sopenharmony_ci return 0x0000ffffffffffffUL >> (nonhyp_fai << 4); 50728c2ecf20Sopenharmony_ci} 50738c2ecf20Sopenharmony_ci 50748c2ecf20Sopenharmony_civoid kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) 50758c2ecf20Sopenharmony_ci{ 50768c2ecf20Sopenharmony_ci vcpu->valid_wakeup = false; 50778c2ecf20Sopenharmony_ci} 50788c2ecf20Sopenharmony_ci 50798c2ecf20Sopenharmony_cistatic int __init kvm_s390_init(void) 50808c2ecf20Sopenharmony_ci{ 50818c2ecf20Sopenharmony_ci int i; 50828c2ecf20Sopenharmony_ci 50838c2ecf20Sopenharmony_ci if (!sclp.has_sief2) { 50848c2ecf20Sopenharmony_ci pr_info("SIE is not available\n"); 50858c2ecf20Sopenharmony_ci return -ENODEV; 50868c2ecf20Sopenharmony_ci } 50878c2ecf20Sopenharmony_ci 50888c2ecf20Sopenharmony_ci if (nested && hpage) { 50898c2ecf20Sopenharmony_ci pr_info("A KVM host that supports nesting cannot back its KVM guests with huge pages\n"); 50908c2ecf20Sopenharmony_ci return -EINVAL; 50918c2ecf20Sopenharmony_ci } 50928c2ecf20Sopenharmony_ci 50938c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 50948c2ecf20Sopenharmony_ci kvm_s390_fac_base[i] |= 50958c2ecf20Sopenharmony_ci S390_lowcore.stfle_fac_list[i] & nonhyp_mask(i); 50968c2ecf20Sopenharmony_ci 50978c2ecf20Sopenharmony_ci return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); 50988c2ecf20Sopenharmony_ci} 50998c2ecf20Sopenharmony_ci 51008c2ecf20Sopenharmony_cistatic void __exit kvm_s390_exit(void) 51018c2ecf20Sopenharmony_ci{ 51028c2ecf20Sopenharmony_ci kvm_exit(); 51038c2ecf20Sopenharmony_ci} 51048c2ecf20Sopenharmony_ci 51058c2ecf20Sopenharmony_cimodule_init(kvm_s390_init); 51068c2ecf20Sopenharmony_cimodule_exit(kvm_s390_exit); 51078c2ecf20Sopenharmony_ci 51088c2ecf20Sopenharmony_ci/* 51098c2ecf20Sopenharmony_ci * Enable autoloading of the kvm module. 51108c2ecf20Sopenharmony_ci * Note that we add the module alias here instead of virt/kvm/kvm_main.c 51118c2ecf20Sopenharmony_ci * since x86 takes a different approach. 51128c2ecf20Sopenharmony_ci */ 51138c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 51148c2ecf20Sopenharmony_ciMODULE_ALIAS_MISCDEV(KVM_MINOR); 51158c2ecf20Sopenharmony_ciMODULE_ALIAS("devname:kvm"); 5116