Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/s390/kvm/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 168 kB image not shown  

Quelle  kvm-s390.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * hosting IBM Z kernel virtual machines (s390x)
 *
 * Copyright IBM Corp. 2008, 2020
 *
 *    Author(s): Carsten Otte <cotte@de.ibm.com>
 *               Christian Borntraeger <borntraeger@de.ibm.com>
 *               Christian Ehrhardt <ehrhardt@de.ibm.com>
 *               Jason J. Herne <jjherne@us.ibm.com>
 */


#define KMSG_COMPONENT "kvm-s390"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/compiler.h>
#include <linux/export.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/mman.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cpufeature.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/vmalloc.h>
#include <linux/bitmap.h>
#include <linux/sched/signal.h>
#include <linux/string.h>
#include <linux/pgtable.h>
#include <linux/mmu_notifier.h>

#include <asm/access-regs.h>
#include <asm/asm-offsets.h>
#include <asm/lowcore.h>
#include <asm/machine.h>
#include <asm/stp.h>
#include <asm/gmap.h>
#include <asm/gmap_helpers.h>
#include <asm/nmi.h>
#include <asm/isc.h>
#include <asm/sclp.h>
#include <asm/cpacf.h>
#include <asm/timex.h>
#include <asm/asm.h>
#include <asm/fpu.h>
#include <asm/ap.h>
#include <asm/uv.h>
#include "kvm-s390.h"
#include "gaccess.h"
#include "pci.h"

#define CREATE_TRACE_POINTS
#include "trace.h"
#include "trace-s390.h"

#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */
#define LOCAL_IRQS 32
#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
      (KVM_MAX_VCPUS + LOCAL_IRQS))

const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
 KVM_GENERIC_VM_STATS(),
 STATS_DESC_COUNTER(VM, inject_io),
 STATS_DESC_COUNTER(VM, inject_float_mchk),
 STATS_DESC_COUNTER(VM, inject_pfault_done),
 STATS_DESC_COUNTER(VM, inject_service_signal),
 STATS_DESC_COUNTER(VM, inject_virtio),
 STATS_DESC_COUNTER(VM, aen_forward),
 STATS_DESC_COUNTER(VM, gmap_shadow_reuse),
 STATS_DESC_COUNTER(VM, gmap_shadow_create),
 STATS_DESC_COUNTER(VM, gmap_shadow_r1_entry),
 STATS_DESC_COUNTER(VM, gmap_shadow_r2_entry),
 STATS_DESC_COUNTER(VM, gmap_shadow_r3_entry),
 STATS_DESC_COUNTER(VM, gmap_shadow_sg_entry),
 STATS_DESC_COUNTER(VM, gmap_shadow_pg_entry),
};

const struct kvm_stats_header kvm_vm_stats_header = {
 .name_size = KVM_STATS_NAME_SIZE,
 .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
 .id_offset = sizeof(struct kvm_stats_header),
 .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
 .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
         sizeof(kvm_vm_stats_desc),
};

const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
 KVM_GENERIC_VCPU_STATS(),
 STATS_DESC_COUNTER(VCPU, exit_userspace),
 STATS_DESC_COUNTER(VCPU, exit_null),
 STATS_DESC_COUNTER(VCPU, exit_external_request),
 STATS_DESC_COUNTER(VCPU, exit_io_request),
 STATS_DESC_COUNTER(VCPU, exit_external_interrupt),
 STATS_DESC_COUNTER(VCPU, exit_stop_request),
 STATS_DESC_COUNTER(VCPU, exit_validity),
 STATS_DESC_COUNTER(VCPU, exit_instruction),
 STATS_DESC_COUNTER(VCPU, exit_pei),
 STATS_DESC_COUNTER(VCPU, halt_no_poll_steal),
 STATS_DESC_COUNTER(VCPU, instruction_lctl),
 STATS_DESC_COUNTER(VCPU, instruction_lctlg),
 STATS_DESC_COUNTER(VCPU, instruction_stctl),
 STATS_DESC_COUNTER(VCPU, instruction_stctg),
 STATS_DESC_COUNTER(VCPU, exit_program_interruption),
 STATS_DESC_COUNTER(VCPU, exit_instr_and_program),
 STATS_DESC_COUNTER(VCPU, exit_operation_exception),
 STATS_DESC_COUNTER(VCPU, deliver_ckc),
 STATS_DESC_COUNTER(VCPU, deliver_cputm),
 STATS_DESC_COUNTER(VCPU, deliver_external_call),
 STATS_DESC_COUNTER(VCPU, deliver_emergency_signal),
 STATS_DESC_COUNTER(VCPU, deliver_service_signal),
 STATS_DESC_COUNTER(VCPU, deliver_virtio),
 STATS_DESC_COUNTER(VCPU, deliver_stop_signal),
 STATS_DESC_COUNTER(VCPU, deliver_prefix_signal),
 STATS_DESC_COUNTER(VCPU, deliver_restart_signal),
 STATS_DESC_COUNTER(VCPU, deliver_program),
 STATS_DESC_COUNTER(VCPU, deliver_io),
 STATS_DESC_COUNTER(VCPU, deliver_machine_check),
 STATS_DESC_COUNTER(VCPU, exit_wait_state),
 STATS_DESC_COUNTER(VCPU, inject_ckc),
 STATS_DESC_COUNTER(VCPU, inject_cputm),
 STATS_DESC_COUNTER(VCPU, inject_external_call),
 STATS_DESC_COUNTER(VCPU, inject_emergency_signal),
 STATS_DESC_COUNTER(VCPU, inject_mchk),
 STATS_DESC_COUNTER(VCPU, inject_pfault_init),
 STATS_DESC_COUNTER(VCPU, inject_program),
 STATS_DESC_COUNTER(VCPU, inject_restart),
 STATS_DESC_COUNTER(VCPU, inject_set_prefix),
 STATS_DESC_COUNTER(VCPU, inject_stop_signal),
 STATS_DESC_COUNTER(VCPU, instruction_epsw),
 STATS_DESC_COUNTER(VCPU, instruction_gs),
 STATS_DESC_COUNTER(VCPU, instruction_io_other),
 STATS_DESC_COUNTER(VCPU, instruction_lpsw),
 STATS_DESC_COUNTER(VCPU, instruction_lpswe),
 STATS_DESC_COUNTER(VCPU, instruction_lpswey),
 STATS_DESC_COUNTER(VCPU, instruction_pfmf),
 STATS_DESC_COUNTER(VCPU, instruction_ptff),
 STATS_DESC_COUNTER(VCPU, instruction_sck),
 STATS_DESC_COUNTER(VCPU, instruction_sckpf),
 STATS_DESC_COUNTER(VCPU, instruction_stidp),
 STATS_DESC_COUNTER(VCPU, instruction_spx),
 STATS_DESC_COUNTER(VCPU, instruction_stpx),
 STATS_DESC_COUNTER(VCPU, instruction_stap),
 STATS_DESC_COUNTER(VCPU, instruction_iske),
 STATS_DESC_COUNTER(VCPU, instruction_ri),
 STATS_DESC_COUNTER(VCPU, instruction_rrbe),
 STATS_DESC_COUNTER(VCPU, instruction_sske),
 STATS_DESC_COUNTER(VCPU, instruction_ipte_interlock),
 STATS_DESC_COUNTER(VCPU, instruction_stsi),
 STATS_DESC_COUNTER(VCPU, instruction_stfl),
 STATS_DESC_COUNTER(VCPU, instruction_tb),
 STATS_DESC_COUNTER(VCPU, instruction_tpi),
 STATS_DESC_COUNTER(VCPU, instruction_tprot),
 STATS_DESC_COUNTER(VCPU, instruction_tsch),
 STATS_DESC_COUNTER(VCPU, instruction_sie),
 STATS_DESC_COUNTER(VCPU, instruction_essa),
 STATS_DESC_COUNTER(VCPU, instruction_sthyi),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_sense),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_sense_running),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_external_call),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_emergency),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_cond_emergency),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_start),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_stop),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_stop_store_status),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_store_status),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_store_adtl_status),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_arch),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_prefix),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_restart),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_init_cpu_reset),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_cpu_reset),
 STATS_DESC_COUNTER(VCPU, instruction_sigp_unknown),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_10),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_44),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_9c),
 STATS_DESC_COUNTER(VCPU, diag_9c_ignored),
 STATS_DESC_COUNTER(VCPU, diag_9c_forward),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_258),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_308),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_500),
 STATS_DESC_COUNTER(VCPU, instruction_diagnose_other),
 STATS_DESC_COUNTER(VCPU, pfault_sync)
};

const struct kvm_stats_header kvm_vcpu_stats_header = {
 .name_size = KVM_STATS_NAME_SIZE,
 .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
 .id_offset = sizeof(struct kvm_stats_header),
 .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
 .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
         sizeof(kvm_vcpu_stats_desc),
};

/* allow nested virtualization in KVM (if enabled by user space) */
static int nested;
module_param(nested, int, S_IRUGO);
MODULE_PARM_DESC(nested, "Nested virtualization support");

/* allow 1m huge page guest backing, if !nested */
static int hpage;
module_param(hpage, int, 0444);
MODULE_PARM_DESC(hpage, "1m huge page backing support");

/* maximum percentage of steal time for polling.  >100 is treated like 100 */
static u8 halt_poll_max_steal = 10;
module_param(halt_poll_max_steal, byte, 0644);
MODULE_PARM_DESC(halt_poll_max_steal, "Maximum percentage of steal time to allow polling");

/* if set to true, the GISA will be initialized and used if available */
static bool use_gisa  = true;
module_param(use_gisa, bool, 0644);
MODULE_PARM_DESC(use_gisa, "Use the GISA if the host supports it.");

/* maximum diag9c forwarding per second */
unsigned int diag9c_forwarding_hz;
module_param(diag9c_forwarding_hz, uint, 0644);
MODULE_PARM_DESC(diag9c_forwarding_hz, "Maximum diag9c forwarding per second, 0 to turn off");

/*
 * allow asynchronous deinit for protected guests; enable by default since
 * the feature is opt-in anyway
 */

static int async_destroy = 1;
module_param(async_destroy, int, 0444);
MODULE_PARM_DESC(async_destroy, "Asynchronous destroy for protected guests");

/*
 * For now we handle at most 16 double words as this is what the s390 base
 * kernel handles and stores in the prefix page. If we ever need to go beyond
 * this, this requires changes to code, but the external uapi can stay.
 */

#define SIZE_INTERNAL 16

/*
 * Base feature mask that defines default mask for facilities. Consists of the
 * defines in FACILITIES_KVM and the non-hypervisor managed bits.
 */

static unsigned long kvm_s390_fac_base[SIZE_INTERNAL] = { FACILITIES_KVM };
/*
 * Extended feature mask. Consists of the defines in FACILITIES_KVM_CPUMODEL
 * and defines the facilities that can be enabled via a cpu model.
 */

static unsigned long kvm_s390_fac_ext[SIZE_INTERNAL] = { FACILITIES_KVM_CPUMODEL };

static unsigned long kvm_s390_fac_size(void)
{
 BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_MASK_SIZE_U64);
 BUILD_BUG_ON(SIZE_INTERNAL > S390_ARCH_FAC_LIST_SIZE_U64);
 BUILD_BUG_ON(SIZE_INTERNAL * sizeof(unsigned long) >
  sizeof(stfle_fac_list));

 return SIZE_INTERNAL;
}

/* available cpu features supported by kvm */
static DECLARE_BITMAP(kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
/* available subfunctions indicated via query / "test bit" */
static struct kvm_s390_vm_cpu_subfunc kvm_s390_available_subfunc;

static struct gmap_notifier gmap_notifier;
static struct gmap_notifier vsie_gmap_notifier;
debug_info_t *kvm_s390_dbf;
debug_info_t *kvm_s390_dbf_uv;

/* Section: not file related */
/* forward declarations */
static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
         unsigned long end);
static int sca_switch_to_extended(struct kvm *kvm);

static void kvm_clock_sync_scb(struct kvm_s390_sie_block *scb, u64 delta)
{
 u8 delta_idx = 0;

 /*
 * The TOD jumps by delta, we have to compensate this by adding
 * -delta to the epoch.
 */

 delta = -delta;

 /* sign-extension - we're adding to signed values below */
 if ((s64)delta < 0)
  delta_idx = -1;

 scb->epoch += delta;
 if (scb->ecd & ECD_MEF) {
  scb->epdx += delta_idx;
  if (scb->epoch < delta)
   scb->epdx += 1;
 }
}

/*
 * This callback is executed during stop_machine(). All CPUs are therefore
 * temporarily stopped. In order not to change guest behavior, we have to
 * disable preemption whenever we touch the epoch of kvm and the VCPUs,
 * so a CPU won't be stopped while calculating with the epoch.
 */

static int kvm_clock_sync(struct notifier_block *notifier, unsigned long val,
     void *v)
{
 struct kvm *kvm;
 struct kvm_vcpu *vcpu;
 unsigned long i;
 unsigned long long *delta = v;

 list_for_each_entry(kvm, &vm_list, vm_list) {
  kvm_for_each_vcpu(i, vcpu, kvm) {
   kvm_clock_sync_scb(vcpu->arch.sie_block, *delta);
   if (i == 0) {
    kvm->arch.epoch = vcpu->arch.sie_block->epoch;
    kvm->arch.epdx = vcpu->arch.sie_block->epdx;
   }
   if (vcpu->arch.cputm_enabled)
    vcpu->arch.cputm_start += *delta;
   if (vcpu->arch.vsie_block)
    kvm_clock_sync_scb(vcpu->arch.vsie_block,
         *delta);
  }
 }
 return NOTIFY_OK;
}

static struct notifier_block kvm_clock_notifier = {
 .notifier_call = kvm_clock_sync,
};

static void allow_cpu_feat(unsigned long nr)
{
 set_bit_inv(nr, kvm_s390_available_cpu_feat);
}

static inline int plo_test_bit(unsigned char nr)
{
 unsigned long function = (unsigned long)nr | 0x100;
 int cc;

 asm volatile(
  " lgr 0,%[function]\n"
  /* Parameter registers are ignored for "test bit" */
  " plo 0,0,0,0(0)\n"
  CC_IPM(cc)
  : CC_OUT(cc, cc)
  : [function] "d" (function)
  : CC_CLOBBER_LIST("0"));
 return CC_TRANSFORM(cc) == 0;
}

static __always_inline void pfcr_query(u8 (*query)[16])
{
 asm volatile(
  " lghi 0,0\n"
  " .insn rsy,0xeb0000000016,0,0,%[query]\n"
  : [query] "=QS" (*query)
  :
  : "cc""0");
}

static __always_inline void __sortl_query(u8 (*query)[32])
{
 asm volatile(
  " lghi 0,0\n"
  " la 1,%[query]\n"
  /* Parameter registers are ignored */
  " .insn rre,0xb9380000,2,4\n"
  : [query] "=R" (*query)
  :
  : "cc""0""1");
}

static __always_inline void __dfltcc_query(u8 (*query)[32])
{
 asm volatile(
  " lghi 0,0\n"
  " la 1,%[query]\n"
  /* Parameter registers are ignored */
  " .insn rrf,0xb9390000,2,4,6,0\n"
  : [query] "=R" (*query)
  :
  : "cc""0""1");
}

static void __init kvm_s390_cpu_feat_init(void)
{
 int i;

 for (i = 0; i < 256; ++i) {
  if (plo_test_bit(i))
   kvm_s390_available_subfunc.plo[i >> 3] |= 0x80 >> (i & 7);
 }

 if (test_facility(28)) /* TOD-clock steering */
  ptff(kvm_s390_available_subfunc.ptff,
       sizeof(kvm_s390_available_subfunc.ptff),
       PTFF_QAF);

 if (test_facility(17)) { /* MSA */
  __cpacf_query(CPACF_KMAC, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kmac);
  __cpacf_query(CPACF_KMC, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kmc);
  __cpacf_query(CPACF_KM, (cpacf_mask_t *)
         kvm_s390_available_subfunc.km);
  __cpacf_query(CPACF_KIMD, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kimd);
  __cpacf_query(CPACF_KLMD, (cpacf_mask_t *)
         kvm_s390_available_subfunc.klmd);
 }
 if (test_facility(76)) /* MSA3 */
  __cpacf_query(CPACF_PCKMO, (cpacf_mask_t *)
         kvm_s390_available_subfunc.pckmo);
 if (test_facility(77)) { /* MSA4 */
  __cpacf_query(CPACF_KMCTR, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kmctr);
  __cpacf_query(CPACF_KMF, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kmf);
  __cpacf_query(CPACF_KMO, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kmo);
  __cpacf_query(CPACF_PCC, (cpacf_mask_t *)
         kvm_s390_available_subfunc.pcc);
 }
 if (test_facility(57)) /* MSA5 */
  __cpacf_query(CPACF_PRNO, (cpacf_mask_t *)
         kvm_s390_available_subfunc.ppno);

 if (test_facility(146)) /* MSA8 */
  __cpacf_query(CPACF_KMA, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kma);

 if (test_facility(155)) /* MSA9 */
  __cpacf_query(CPACF_KDSA, (cpacf_mask_t *)
         kvm_s390_available_subfunc.kdsa);

 if (test_facility(150)) /* SORTL */
  __sortl_query(&kvm_s390_available_subfunc.sortl);

 if (test_facility(151)) /* DFLTCC */
  __dfltcc_query(&kvm_s390_available_subfunc.dfltcc);

 if (test_facility(201)) /* PFCR */
  pfcr_query(&kvm_s390_available_subfunc.pfcr);

 if (machine_has_esop())
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_ESOP);
 /*
 * We need SIE support, ESOP (PROT_READ protection for gmap_shadow),
 * 64bit SCAO (SCA passthrough) and IDTE (for gmap_shadow unshadowing).
 */

 if (!sclp.has_sief2 || !machine_has_esop() || !sclp.has_64bscao ||
     !test_facility(3) || !nested)
  return;
 allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2);
 if (sclp.has_64bscao)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
 if (sclp.has_siif)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF);
 if (sclp.has_gpere)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_GPERE);
 if (sclp.has_gsls)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_GSLS);
 if (sclp.has_ib)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IB);
 if (sclp.has_cei)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_CEI);
 if (sclp.has_ibs)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IBS);
 if (sclp.has_kss)
  allow_cpu_feat(KVM_S390_VM_CPU_FEAT_KSS);
 /*
 * KVM_S390_VM_CPU_FEAT_SKEY: Wrong shadow of PTE.I bits will make
 * all skey handling functions read/set the skey from the PGSTE
 * instead of the real storage key.
 *
 * KVM_S390_VM_CPU_FEAT_CMMA: Wrong shadow of PTE.I bits will make
 * pages being detected as preserved although they are resident.
 *
 * KVM_S390_VM_CPU_FEAT_PFMFI: Wrong shadow of PTE.I bits will
 * have the same effect as for KVM_S390_VM_CPU_FEAT_SKEY.
 *
 * For KVM_S390_VM_CPU_FEAT_SKEY, KVM_S390_VM_CPU_FEAT_CMMA and
 * KVM_S390_VM_CPU_FEAT_PFMFI, all PTE.I and PGSTE bits have to be
 * correctly shadowed. We can do that for the PGSTE but not for PTE.I.
 *
 * KVM_S390_VM_CPU_FEAT_SIGPIF: Wrong SCB addresses in the SCA. We
 * cannot easily shadow the SCA because of the ipte lock.
 */

}

static int __init __kvm_s390_init(void)
{
 int rc = -ENOMEM;

 kvm_s390_dbf = debug_register("kvm-trace", 32, 1, 7 * sizeof(long));
 if (!kvm_s390_dbf)
  return -ENOMEM;

 kvm_s390_dbf_uv = debug_register("kvm-uv", 32, 1, 7 * sizeof(long));
 if (!kvm_s390_dbf_uv)
  goto err_kvm_uv;

 if (debug_register_view(kvm_s390_dbf, &debug_sprintf_view) ||
     debug_register_view(kvm_s390_dbf_uv, &debug_sprintf_view))
  goto err_debug_view;

 kvm_s390_cpu_feat_init();

 /* Register floating interrupt controller interface. */
 rc = kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC);
 if (rc) {
  pr_err("A FLIC registration call failed with rc=%d\n", rc);
  goto err_flic;
 }

 if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) {
  rc = kvm_s390_pci_init();
  if (rc) {
   pr_err("Unable to allocate AIFT for PCI\n");
   goto err_pci;
  }
 }

 rc = kvm_s390_gib_init(GAL_ISC);
 if (rc)
  goto err_gib;

 gmap_notifier.notifier_call = kvm_gmap_notifier;
 gmap_register_pte_notifier(&gmap_notifier);
 vsie_gmap_notifier.notifier_call = kvm_s390_vsie_gmap_notifier;
 gmap_register_pte_notifier(&vsie_gmap_notifier);
 atomic_notifier_chain_register(&s390_epoch_delta_notifier,
           &kvm_clock_notifier);

 return 0;

err_gib:
 if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM))
  kvm_s390_pci_exit();
err_pci:
err_flic:
err_debug_view:
 debug_unregister(kvm_s390_dbf_uv);
err_kvm_uv:
 debug_unregister(kvm_s390_dbf);
 return rc;
}

static void __kvm_s390_exit(void)
{
 gmap_unregister_pte_notifier(&gmap_notifier);
 gmap_unregister_pte_notifier(&vsie_gmap_notifier);
 atomic_notifier_chain_unregister(&s390_epoch_delta_notifier,
      &kvm_clock_notifier);

 kvm_s390_gib_destroy();
 if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM))
  kvm_s390_pci_exit();
 debug_unregister(kvm_s390_dbf);
 debug_unregister(kvm_s390_dbf_uv);
}

/* Section: device related */
long kvm_arch_dev_ioctl(struct file *filp,
   unsigned int ioctl, unsigned long arg)
{
 if (ioctl == KVM_S390_ENABLE_SIE)
  return s390_enable_sie();
 return -EINVAL;
}

int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
 int r;

 switch (ext) {
 case KVM_CAP_S390_PSW:
 case KVM_CAP_S390_GMAP:
 case KVM_CAP_SYNC_MMU:
#ifdef CONFIG_KVM_S390_UCONTROL
 case KVM_CAP_S390_UCONTROL:
#endif
 case KVM_CAP_ASYNC_PF:
 case KVM_CAP_SYNC_REGS:
 case KVM_CAP_ONE_REG:
 case KVM_CAP_ENABLE_CAP:
 case KVM_CAP_S390_CSS_SUPPORT:
 case KVM_CAP_IOEVENTFD:
 case KVM_CAP_S390_IRQCHIP:
 case KVM_CAP_VM_ATTRIBUTES:
 case KVM_CAP_MP_STATE:
 case KVM_CAP_IMMEDIATE_EXIT:
 case KVM_CAP_S390_INJECT_IRQ:
 case KVM_CAP_S390_USER_SIGP:
 case KVM_CAP_S390_USER_STSI:
 case KVM_CAP_S390_SKEYS:
 case KVM_CAP_S390_IRQ_STATE:
 case KVM_CAP_S390_USER_INSTR0:
 case KVM_CAP_S390_CMMA_MIGRATION:
 case KVM_CAP_S390_AIS:
 case KVM_CAP_S390_AIS_MIGRATION:
 case KVM_CAP_S390_VCPU_RESETS:
 case KVM_CAP_SET_GUEST_DEBUG:
 case KVM_CAP_S390_DIAG318:
 case KVM_CAP_IRQFD_RESAMPLE:
  r = 1;
  break;
 case KVM_CAP_SET_GUEST_DEBUG2:
  r = KVM_GUESTDBG_VALID_MASK;
  break;
 case KVM_CAP_S390_HPAGE_1M:
  r = 0;
  if (hpage && !(kvm && kvm_is_ucontrol(kvm)))
   r = 1;
  break;
 case KVM_CAP_S390_MEM_OP:
  r = MEM_OP_MAX_SIZE;
  break;
 case KVM_CAP_S390_MEM_OP_EXTENSION:
  /*
 * Flag bits indicating which extensions are supported.
 * If r > 0, the base extension must also be supported/indicated,
 * in order to maintain backwards compatibility.
 */

  r = KVM_S390_MEMOP_EXTENSION_CAP_BASE |
      KVM_S390_MEMOP_EXTENSION_CAP_CMPXCHG;
  break;
 case KVM_CAP_NR_VCPUS:
 case KVM_CAP_MAX_VCPUS:
 case KVM_CAP_MAX_VCPU_ID:
  r = KVM_S390_BSCA_CPU_SLOTS;
  if (!kvm_s390_use_sca_entries())
   r = KVM_MAX_VCPUS;
  else if (sclp.has_esca && sclp.has_64bscao)
   r = KVM_S390_ESCA_CPU_SLOTS;
  if (ext == KVM_CAP_NR_VCPUS)
   r = min_t(unsigned int, num_online_cpus(), r);
  break;
 case KVM_CAP_S390_COW:
  r = machine_has_esop();
  break;
 case KVM_CAP_S390_VECTOR_REGISTERS:
  r = test_facility(129);
  break;
 case KVM_CAP_S390_RI:
  r = test_facility(64);
  break;
 case KVM_CAP_S390_GS:
  r = test_facility(133);
  break;
 case KVM_CAP_S390_BPB:
  r = test_facility(82);
  break;
 case KVM_CAP_S390_PROTECTED_ASYNC_DISABLE:
  r = async_destroy && is_prot_virt_host();
  break;
 case KVM_CAP_S390_PROTECTED:
  r = is_prot_virt_host();
  break;
 case KVM_CAP_S390_PROTECTED_DUMP: {
  u64 pv_cmds_dump[] = {
   BIT_UVC_CMD_DUMP_INIT,
   BIT_UVC_CMD_DUMP_CONFIG_STOR_STATE,
   BIT_UVC_CMD_DUMP_CPU,
   BIT_UVC_CMD_DUMP_COMPLETE,
  };
  int i;

  r = is_prot_virt_host();

  for (i = 0; i < ARRAY_SIZE(pv_cmds_dump); i++) {
   if (!test_bit_inv(pv_cmds_dump[i],
       (unsigned long *)&uv_info.inst_calls_list)) {
    r = 0;
    break;
   }
  }
  break;
 }
 case KVM_CAP_S390_ZPCI_OP:
  r = kvm_s390_pci_interp_allowed();
  break;
 case KVM_CAP_S390_CPU_TOPOLOGY:
  r = test_facility(11);
  break;
 default:
  r = 0;
 }
 return r;
}

void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
{
 int i;
 gfn_t cur_gfn, last_gfn;
 unsigned long gaddr, vmaddr;
 struct gmap *gmap = kvm->arch.gmap;
 DECLARE_BITMAP(bitmap, _PAGE_ENTRIES);

 /* Loop over all guest segments */
 cur_gfn = memslot->base_gfn;
 last_gfn = memslot->base_gfn + memslot->npages;
 for (; cur_gfn <= last_gfn; cur_gfn += _PAGE_ENTRIES) {
  gaddr = gfn_to_gpa(cur_gfn);
  vmaddr = gfn_to_hva_memslot(memslot, cur_gfn);
  if (kvm_is_error_hva(vmaddr))
   continue;

  bitmap_zero(bitmap, _PAGE_ENTRIES);
  gmap_sync_dirty_log_pmd(gmap, bitmap, gaddr, vmaddr);
  for (i = 0; i < _PAGE_ENTRIES; i++) {
   if (test_bit(i, bitmap))
    mark_page_dirty(kvm, cur_gfn + i);
  }

  if (fatal_signal_pending(current))
   return;
  cond_resched();
 }
}

/* Section: vm related */
static void sca_del_vcpu(struct kvm_vcpu *vcpu);

/*
 * Get (and clear) the dirty memory log for a memory slot.
 */

int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
          struct kvm_dirty_log *log)
{
 int r;
 unsigned long n;
 struct kvm_memory_slot *memslot;
 int is_dirty;

 if (kvm_is_ucontrol(kvm))
  return -EINVAL;

 mutex_lock(&kvm->slots_lock);

 r = -EINVAL;
 if (log->slot >= KVM_USER_MEM_SLOTS)
  goto out;

 r = kvm_get_dirty_log(kvm, log, &is_dirty, &memslot);
 if (r)
  goto out;

 /* Clear the dirty log */
 if (is_dirty) {
  n = kvm_dirty_bitmap_bytes(memslot);
  memset(memslot->dirty_bitmap, 0, n);
 }
 r = 0;
out:
 mutex_unlock(&kvm->slots_lock);
 return r;
}

static void icpt_operexc_on_all_vcpus(struct kvm *kvm)
{
 unsigned long i;
 struct kvm_vcpu *vcpu;

 kvm_for_each_vcpu(i, vcpu, kvm) {
  kvm_s390_sync_request(KVM_REQ_ICPT_OPEREXC, vcpu);
 }
}

int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
{
 int r;

 if (cap->flags)
  return -EINVAL;

 switch (cap->cap) {
 case KVM_CAP_S390_IRQCHIP:
  VM_EVENT(kvm, 3, "%s""ENABLE: CAP_S390_IRQCHIP");
  kvm->arch.use_irqchip = 1;
  r = 0;
  break;
 case KVM_CAP_S390_USER_SIGP:
  VM_EVENT(kvm, 3, "%s""ENABLE: CAP_S390_USER_SIGP");
  kvm->arch.user_sigp = 1;
  r = 0;
  break;
 case KVM_CAP_S390_VECTOR_REGISTERS:
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus) {
   r = -EBUSY;
  } else if (cpu_has_vx()) {
   set_kvm_facility(kvm->arch.model.fac_mask, 129);
   set_kvm_facility(kvm->arch.model.fac_list, 129);
   if (test_facility(134)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 134);
    set_kvm_facility(kvm->arch.model.fac_list, 134);
   }
   if (test_facility(135)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 135);
    set_kvm_facility(kvm->arch.model.fac_list, 135);
   }
   if (test_facility(148)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 148);
    set_kvm_facility(kvm->arch.model.fac_list, 148);
   }
   if (test_facility(152)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 152);
    set_kvm_facility(kvm->arch.model.fac_list, 152);
   }
   if (test_facility(192)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 192);
    set_kvm_facility(kvm->arch.model.fac_list, 192);
   }
   if (test_facility(198)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 198);
    set_kvm_facility(kvm->arch.model.fac_list, 198);
   }
   if (test_facility(199)) {
    set_kvm_facility(kvm->arch.model.fac_mask, 199);
    set_kvm_facility(kvm->arch.model.fac_list, 199);
   }
   r = 0;
  } else
   r = -EINVAL;
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s",
    r ? "(not available)" : "(success)");
  break;
 case KVM_CAP_S390_RI:
  r = -EINVAL;
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus) {
   r = -EBUSY;
  } else if (test_facility(64)) {
   set_kvm_facility(kvm->arch.model.fac_mask, 64);
   set_kvm_facility(kvm->arch.model.fac_list, 64);
   r = 0;
  }
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s",
    r ? "(not available)" : "(success)");
  break;
 case KVM_CAP_S390_AIS:
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus) {
   r = -EBUSY;
  } else {
   set_kvm_facility(kvm->arch.model.fac_mask, 72);
   set_kvm_facility(kvm->arch.model.fac_list, 72);
   r = 0;
  }
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "ENABLE: AIS %s",
    r ? "(not available)" : "(success)");
  break;
 case KVM_CAP_S390_GS:
  r = -EINVAL;
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus) {
   r = -EBUSY;
  } else if (test_facility(133)) {
   set_kvm_facility(kvm->arch.model.fac_mask, 133);
   set_kvm_facility(kvm->arch.model.fac_list, 133);
   r = 0;
  }
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "ENABLE: CAP_S390_GS %s",
    r ? "(not available)" : "(success)");
  break;
 case KVM_CAP_S390_HPAGE_1M:
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus)
   r = -EBUSY;
  else if (!hpage || kvm->arch.use_cmma || kvm_is_ucontrol(kvm))
   r = -EINVAL;
  else {
   r = 0;
   mmap_write_lock(kvm->mm);
   kvm->mm->context.allow_gmap_hpage_1m = 1;
   mmap_write_unlock(kvm->mm);
   /*
 * We might have to create fake 4k page
 * tables. To avoid that the hardware works on
 * stale PGSTEs, we emulate these instructions.
 */

   kvm->arch.use_skf = 0;
   kvm->arch.use_pfmfi = 0;
  }
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "ENABLE: CAP_S390_HPAGE %s",
    r ? "(not available)" : "(success)");
  break;
 case KVM_CAP_S390_USER_STSI:
  VM_EVENT(kvm, 3, "%s""ENABLE: CAP_S390_USER_STSI");
  kvm->arch.user_stsi = 1;
  r = 0;
  break;
 case KVM_CAP_S390_USER_INSTR0:
  VM_EVENT(kvm, 3, "%s""ENABLE: CAP_S390_USER_INSTR0");
  kvm->arch.user_instr0 = 1;
  icpt_operexc_on_all_vcpus(kvm);
  r = 0;
  break;
 case KVM_CAP_S390_CPU_TOPOLOGY:
  r = -EINVAL;
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus) {
   r = -EBUSY;
  } else if (test_facility(11)) {
   set_kvm_facility(kvm->arch.model.fac_mask, 11);
   set_kvm_facility(kvm->arch.model.fac_list, 11);
   r = 0;
  }
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "ENABLE: CAP_S390_CPU_TOPOLOGY %s",
    r ? "(not available)" : "(success)");
  break;
 default:
  r = -EINVAL;
  break;
 }
 return r;
}

static int kvm_s390_get_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;

 switch (attr->attr) {
 case KVM_S390_VM_MEM_LIMIT_SIZE:
  ret = 0;
  VM_EVENT(kvm, 3, "QUERY: max guest memory: %lu bytes",
    kvm->arch.mem_limit);
  if (put_user(kvm->arch.mem_limit, (u64 __user *)attr->addr))
   ret = -EFAULT;
  break;
 default:
  ret = -ENXIO;
  break;
 }
 return ret;
}

static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;
 unsigned int idx;
 switch (attr->attr) {
 case KVM_S390_VM_MEM_ENABLE_CMMA:
  ret = -ENXIO;
  if (!sclp.has_cmma)
   break;

  VM_EVENT(kvm, 3, "%s""ENABLE: CMMA support");
  mutex_lock(&kvm->lock);
  if (kvm->created_vcpus)
   ret = -EBUSY;
  else if (kvm->mm->context.allow_gmap_hpage_1m)
   ret = -EINVAL;
  else {
   kvm->arch.use_cmma = 1;
   /* Not compatible with cmma. */
   kvm->arch.use_pfmfi = 0;
   ret = 0;
  }
  mutex_unlock(&kvm->lock);
  break;
 case KVM_S390_VM_MEM_CLR_CMMA:
  ret = -ENXIO;
  if (!sclp.has_cmma)
   break;
  ret = -EINVAL;
  if (!kvm->arch.use_cmma)
   break;

  VM_EVENT(kvm, 3, "%s""RESET: CMMA states");
  mutex_lock(&kvm->lock);
  idx = srcu_read_lock(&kvm->srcu);
  s390_reset_cmma(kvm->arch.gmap->mm);
  srcu_read_unlock(&kvm->srcu, idx);
  mutex_unlock(&kvm->lock);
  ret = 0;
  break;
 case KVM_S390_VM_MEM_LIMIT_SIZE: {
  unsigned long new_limit;

  if (kvm_is_ucontrol(kvm))
   return -EINVAL;

  if (get_user(new_limit, (u64 __user *)attr->addr))
   return -EFAULT;

  if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT &&
      new_limit > kvm->arch.mem_limit)
   return -E2BIG;

  if (!new_limit)
   return -EINVAL;

  /* gmap_create takes last usable address */
  if (new_limit != KVM_S390_NO_MEM_LIMIT)
   new_limit -= 1;

  ret = -EBUSY;
  mutex_lock(&kvm->lock);
  if (!kvm->created_vcpus) {
   /* gmap_create will round the limit up */
   struct gmap *new = gmap_create(current->mm, new_limit);

   if (!new) {
    ret = -ENOMEM;
   } else {
    gmap_remove(kvm->arch.gmap);
    new->private = kvm;
    kvm->arch.gmap = new;
    ret = 0;
   }
  }
  mutex_unlock(&kvm->lock);
  VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit);
  VM_EVENT(kvm, 3, "New guest asce: 0x%p",
    (void *) kvm->arch.gmap->asce);
  break;
 }
 default:
  ret = -ENXIO;
  break;
 }
 return ret;
}

static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu);

void kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm)
{
 struct kvm_vcpu *vcpu;
 unsigned long i;

 kvm_s390_vcpu_block_all(kvm);

 kvm_for_each_vcpu(i, vcpu, kvm) {
  kvm_s390_vcpu_crypto_setup(vcpu);
  /* recreate the shadow crycb by leaving the VSIE handler */
  kvm_s390_sync_request(KVM_REQ_VSIE_RESTART, vcpu);
 }

 kvm_s390_vcpu_unblock_all(kvm);
}

static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr)
{
 mutex_lock(&kvm->lock);
 switch (attr->attr) {
 case KVM_S390_VM_CRYPTO_ENABLE_AES_KW:
  if (!test_kvm_facility(kvm, 76)) {
   mutex_unlock(&kvm->lock);
   return -EINVAL;
  }
  get_random_bytes(
   kvm->arch.crypto.crycb->aes_wrapping_key_mask,
   sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
  kvm->arch.crypto.aes_kw = 1;
  VM_EVENT(kvm, 3, "%s""ENABLE: AES keywrapping support");
  break;
 case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW:
  if (!test_kvm_facility(kvm, 76)) {
   mutex_unlock(&kvm->lock);
   return -EINVAL;
  }
  get_random_bytes(
   kvm->arch.crypto.crycb->dea_wrapping_key_mask,
   sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
  kvm->arch.crypto.dea_kw = 1;
  VM_EVENT(kvm, 3, "%s""ENABLE: DEA keywrapping support");
  break;
 case KVM_S390_VM_CRYPTO_DISABLE_AES_KW:
  if (!test_kvm_facility(kvm, 76)) {
   mutex_unlock(&kvm->lock);
   return -EINVAL;
  }
  kvm->arch.crypto.aes_kw = 0;
  memset(kvm->arch.crypto.crycb->aes_wrapping_key_mask, 0,
   sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
  VM_EVENT(kvm, 3, "%s""DISABLE: AES keywrapping support");
  break;
 case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW:
  if (!test_kvm_facility(kvm, 76)) {
   mutex_unlock(&kvm->lock);
   return -EINVAL;
  }
  kvm->arch.crypto.dea_kw = 0;
  memset(kvm->arch.crypto.crycb->dea_wrapping_key_mask, 0,
   sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
  VM_EVENT(kvm, 3, "%s""DISABLE: DEA keywrapping support");
  break;
 case KVM_S390_VM_CRYPTO_ENABLE_APIE:
  if (!ap_instructions_available()) {
   mutex_unlock(&kvm->lock);
   return -EOPNOTSUPP;
  }
  kvm->arch.crypto.apie = 1;
  break;
 case KVM_S390_VM_CRYPTO_DISABLE_APIE:
  if (!ap_instructions_available()) {
   mutex_unlock(&kvm->lock);
   return -EOPNOTSUPP;
  }
  kvm->arch.crypto.apie = 0;
  break;
 default:
  mutex_unlock(&kvm->lock);
  return -ENXIO;
 }

 kvm_s390_vcpu_crypto_reset_all(kvm);
 mutex_unlock(&kvm->lock);
 return 0;
}

static void kvm_s390_vcpu_pci_setup(struct kvm_vcpu *vcpu)
{
 /* Only set the ECB bits after guest requests zPCI interpretation */
 if (!vcpu->kvm->arch.use_zpci_interp)
  return;

 vcpu->arch.sie_block->ecb2 |= ECB2_ZPCI_LSI;
 vcpu->arch.sie_block->ecb3 |= ECB3_AISII + ECB3_AISI;
}

void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm)
{
 struct kvm_vcpu *vcpu;
 unsigned long i;

 lockdep_assert_held(&kvm->lock);

 if (!kvm_s390_pci_interp_allowed())
  return;

 /*
 * If host is configured for PCI and the necessary facilities are
 * available, turn on interpretation for the life of this guest
 */

 kvm->arch.use_zpci_interp = 1;

 kvm_s390_vcpu_block_all(kvm);

 kvm_for_each_vcpu(i, vcpu, kvm) {
  kvm_s390_vcpu_pci_setup(vcpu);
  kvm_s390_sync_request(KVM_REQ_VSIE_RESTART, vcpu);
 }

 kvm_s390_vcpu_unblock_all(kvm);
}

static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
{
 unsigned long cx;
 struct kvm_vcpu *vcpu;

 kvm_for_each_vcpu(cx, vcpu, kvm)
  kvm_s390_sync_request(req, vcpu);
}

/*
 * Must be called with kvm->srcu held to avoid races on memslots, and with
 * kvm->slots_lock to avoid races with ourselves and kvm_s390_vm_stop_migration.
 */

static int kvm_s390_vm_start_migration(struct kvm *kvm)
{
 struct kvm_memory_slot *ms;
 struct kvm_memslots *slots;
 unsigned long ram_pages = 0;
 int bkt;

 /* migration mode already enabled */
 if (kvm->arch.migration_mode)
  return 0;
 slots = kvm_memslots(kvm);
 if (!slots || kvm_memslots_empty(slots))
  return -EINVAL;

 if (!kvm->arch.use_cmma) {
  kvm->arch.migration_mode = 1;
  return 0;
 }
 /* mark all the pages in active slots as dirty */
 kvm_for_each_memslot(ms, bkt, slots) {
  if (!ms->dirty_bitmap)
   return -EINVAL;
  /*
 * The second half of the bitmap is only used on x86,
 * and would be wasted otherwise, so we put it to good
 * use here to keep track of the state of the storage
 * attributes.
 */

  memset(kvm_second_dirty_bitmap(ms), 0xff, kvm_dirty_bitmap_bytes(ms));
  ram_pages += ms->npages;
 }
 atomic64_set(&kvm->arch.cmma_dirty_pages, ram_pages);
 kvm->arch.migration_mode = 1;
 kvm_s390_sync_request_broadcast(kvm, KVM_REQ_START_MIGRATION);
 return 0;
}

/*
 * Must be called with kvm->slots_lock to avoid races with ourselves and
 * kvm_s390_vm_start_migration.
 */

static int kvm_s390_vm_stop_migration(struct kvm *kvm)
{
 /* migration mode already disabled */
 if (!kvm->arch.migration_mode)
  return 0;
 kvm->arch.migration_mode = 0;
 if (kvm->arch.use_cmma)
  kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
 return 0;
}

static int kvm_s390_vm_set_migration(struct kvm *kvm,
         struct kvm_device_attr *attr)
{
 int res = -ENXIO;

 mutex_lock(&kvm->slots_lock);
 switch (attr->attr) {
 case KVM_S390_VM_MIGRATION_START:
  res = kvm_s390_vm_start_migration(kvm);
  break;
 case KVM_S390_VM_MIGRATION_STOP:
  res = kvm_s390_vm_stop_migration(kvm);
  break;
 default:
  break;
 }
 mutex_unlock(&kvm->slots_lock);

 return res;
}

static int kvm_s390_vm_get_migration(struct kvm *kvm,
         struct kvm_device_attr *attr)
{
 u64 mig = kvm->arch.migration_mode;

 if (attr->attr != KVM_S390_VM_MIGRATION_STATUS)
  return -ENXIO;

 if (copy_to_user((void __user *)attr->addr, &mig, sizeof(mig)))
  return -EFAULT;
 return 0;
}

static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);

static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_tod_clock gtod;

 if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod)))
  return -EFAULT;

 if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
  return -EINVAL;
 __kvm_s390_set_tod_clock(kvm, >od);

 VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
  gtod.epoch_idx, gtod.tod);

 return 0;
}

static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
{
 u8 gtod_high;

 if (copy_from_user(>od_high, (void __user *)attr->addr,
        sizeof(gtod_high)))
  return -EFAULT;

 if (gtod_high != 0)
  return -EINVAL;
 VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x", gtod_high);

 return 0;
}

static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_tod_clock gtod = { 0 };

 if (copy_from_user(>od.tod, (void __user *)attr->addr,
      sizeof(gtod.tod)))
  return -EFAULT;

 __kvm_s390_set_tod_clock(kvm, >od);
 VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
 return 0;
}

static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;

 if (attr->flags)
  return -EINVAL;

 mutex_lock(&kvm->lock);
 /*
 * For protected guests, the TOD is managed by the ultravisor, so trying
 * to change it will never bring the expected results.
 */

 if (kvm_s390_pv_is_protected(kvm)) {
  ret = -EOPNOTSUPP;
  goto out_unlock;
 }

 switch (attr->attr) {
 case KVM_S390_VM_TOD_EXT:
  ret = kvm_s390_set_tod_ext(kvm, attr);
  break;
 case KVM_S390_VM_TOD_HIGH:
  ret = kvm_s390_set_tod_high(kvm, attr);
  break;
 case KVM_S390_VM_TOD_LOW:
  ret = kvm_s390_set_tod_low(kvm, attr);
  break;
 default:
  ret = -ENXIO;
  break;
 }

out_unlock:
 mutex_unlock(&kvm->lock);
 return ret;
}

static void kvm_s390_get_tod_clock(struct kvm *kvm,
       struct kvm_s390_vm_tod_clock *gtod)
{
 union tod_clock clk;

 preempt_disable();

 store_tod_clock_ext(&clk);

 gtod->tod = clk.tod + kvm->arch.epoch;
 gtod->epoch_idx = 0;
 if (test_kvm_facility(kvm, 139)) {
  gtod->epoch_idx = clk.ei + kvm->arch.epdx;
  if (gtod->tod < clk.tod)
   gtod->epoch_idx += 1;
 }

 preempt_enable();
}

static int kvm_s390_get_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_tod_clock gtod;

 memset(>od, 0, sizeof(gtod));
 kvm_s390_get_tod_clock(kvm, >od);
 if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod)))
  return -EFAULT;

 VM_EVENT(kvm, 3, "QUERY: TOD extension: 0x%x, TOD base: 0x%llx",
  gtod.epoch_idx, gtod.tod);
 return 0;
}

static int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
{
 u8 gtod_high = 0;

 if (copy_to_user((void __user *)attr->addr, >od_high,
      sizeof(gtod_high)))
  return -EFAULT;
 VM_EVENT(kvm, 3, "QUERY: TOD extension: 0x%x", gtod_high);

 return 0;
}

static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
{
 u64 gtod;

 gtod = kvm_s390_get_tod_clock_fast(kvm);
 if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod)))
  return -EFAULT;
 VM_EVENT(kvm, 3, "QUERY: TOD base: 0x%llx", gtod);

 return 0;
}

static int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;

 if (attr->flags)
  return -EINVAL;

 switch (attr->attr) {
 case KVM_S390_VM_TOD_EXT:
  ret = kvm_s390_get_tod_ext(kvm, attr);
  break;
 case KVM_S390_VM_TOD_HIGH:
  ret = kvm_s390_get_tod_high(kvm, attr);
  break;
 case KVM_S390_VM_TOD_LOW:
  ret = kvm_s390_get_tod_low(kvm, attr);
  break;
 default:
  ret = -ENXIO;
  break;
 }
 return ret;
}

static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_processor *proc;
 u16 lowest_ibc, unblocked_ibc;
 int ret = 0;

 mutex_lock(&kvm->lock);
 if (kvm->created_vcpus) {
  ret = -EBUSY;
  goto out;
 }
 proc = kzalloc(sizeof(*proc), GFP_KERNEL_ACCOUNT);
 if (!proc) {
  ret = -ENOMEM;
  goto out;
 }
 if (!copy_from_user(proc, (void __user *)attr->addr,
       sizeof(*proc))) {
  kvm->arch.model.cpuid = proc->cpuid;
  lowest_ibc = sclp.ibc >> 16 & 0xfff;
  unblocked_ibc = sclp.ibc & 0xfff;
  if (lowest_ibc && proc->ibc) {
   if (proc->ibc > unblocked_ibc)
    kvm->arch.model.ibc = unblocked_ibc;
   else if (proc->ibc < lowest_ibc)
    kvm->arch.model.ibc = lowest_ibc;
   else
    kvm->arch.model.ibc = proc->ibc;
  }
  memcpy(kvm->arch.model.fac_list, proc->fac_list,
         S390_ARCH_FAC_LIST_SIZE_BYTE);
  VM_EVENT(kvm, 3, "SET: guest ibc: 0x%4.4x, guest cpuid: 0x%16.16llx",
    kvm->arch.model.ibc,
    kvm->arch.model.cpuid);
  VM_EVENT(kvm, 3, "SET: guest faclist: 0x%16.16llx.%16.16llx.%16.16llx",
    kvm->arch.model.fac_list[0],
    kvm->arch.model.fac_list[1],
    kvm->arch.model.fac_list[2]);
 } else
  ret = -EFAULT;
 kfree(proc);
out:
 mutex_unlock(&kvm->lock);
 return ret;
}

static int kvm_s390_set_processor_feat(struct kvm *kvm,
           struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_feat data;

 if (copy_from_user(&data, (void __user *)attr->addr, sizeof(data)))
  return -EFAULT;
 if (!bitmap_subset((unsigned long *) data.feat,
      kvm_s390_available_cpu_feat,
      KVM_S390_VM_CPU_FEAT_NR_BITS))
  return -EINVAL;

 mutex_lock(&kvm->lock);
 if (kvm->created_vcpus) {
  mutex_unlock(&kvm->lock);
  return -EBUSY;
 }
 bitmap_from_arr64(kvm->arch.cpu_feat, data.feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
 mutex_unlock(&kvm->lock);
 VM_EVENT(kvm, 3, "SET: guest feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx",
    data.feat[0],
    data.feat[1],
    data.feat[2]);
 return 0;
}

static int kvm_s390_set_processor_subfunc(struct kvm *kvm,
       struct kvm_device_attr *attr)
{
 mutex_lock(&kvm->lock);
 if (kvm->created_vcpus) {
  mutex_unlock(&kvm->lock);
  return -EBUSY;
 }

 if (copy_from_user(&kvm->arch.model.subfuncs, (void __user *)attr->addr,
      sizeof(struct kvm_s390_vm_cpu_subfunc))) {
  mutex_unlock(&kvm->lock);
  return -EFAULT;
 }
 mutex_unlock(&kvm->lock);

 VM_EVENT(kvm, 3, "SET: guest PLO subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[1],
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[2],
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[3]);
 VM_EVENT(kvm, 3, "SET: guest PTFF subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[1]);
 VM_EVENT(kvm, 3, "SET: guest KMAC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[1]);
 VM_EVENT(kvm, 3, "SET: guest KMC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[1]);
 VM_EVENT(kvm, 3, "SET: guest KM subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.km)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.km)[1]);
 VM_EVENT(kvm, 3, "SET: guest KIMD subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[1]);
 VM_EVENT(kvm, 3, "SET: guest KLMD subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[1]);
 VM_EVENT(kvm, 3, "SET: guest PCKMO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[1]);
 VM_EVENT(kvm, 3, "SET: guest KMCTR subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[1]);
 VM_EVENT(kvm, 3, "SET: guest KMF subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[1]);
 VM_EVENT(kvm, 3, "SET: guest KMO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[1]);
 VM_EVENT(kvm, 3, "SET: guest PCC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[1]);
 VM_EVENT(kvm, 3, "SET: guest PPNO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[1]);
 VM_EVENT(kvm, 3, "SET: guest KMA subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kma)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kma)[1]);
 VM_EVENT(kvm, 3, "SET: guest KDSA subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[1]);
 VM_EVENT(kvm, 3, "SET: guest SORTL subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[1],
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[2],
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[3]);
 VM_EVENT(kvm, 3, "SET: guest DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1],
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2],
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]);
 VM_EVENT(kvm, 3, "GET: guest PFCR subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[1]);

 return 0;
}

#define KVM_S390_VM_CPU_UV_FEAT_GUEST_MASK \
(      \
 ((struct kvm_s390_vm_cpu_uv_feat){ \
  .ap = 1,   \
  .ap_intr = 1,   \
 })     \
 .feat     \
)

static int kvm_s390_set_uv_feat(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_uv_feat __user *ptr = (void __user *)attr->addr;
 unsigned long data, filter;

 filter = uv_info.uv_feature_indications & KVM_S390_VM_CPU_UV_FEAT_GUEST_MASK;
 if (get_user(data, &ptr->feat))
  return -EFAULT;
 if (!bitmap_subset(&data, &filter, KVM_S390_VM_CPU_UV_FEAT_NR_BITS))
  return -EINVAL;

 mutex_lock(&kvm->lock);
 if (kvm->created_vcpus) {
  mutex_unlock(&kvm->lock);
  return -EBUSY;
 }
 kvm->arch.model.uv_feat_guest.feat = data;
 mutex_unlock(&kvm->lock);

 VM_EVENT(kvm, 3, "SET: guest UV-feat: 0x%16.16lx", data);

 return 0;
}

static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret = -ENXIO;

 switch (attr->attr) {
 case KVM_S390_VM_CPU_PROCESSOR:
  ret = kvm_s390_set_processor(kvm, attr);
  break;
 case KVM_S390_VM_CPU_PROCESSOR_FEAT:
  ret = kvm_s390_set_processor_feat(kvm, attr);
  break;
 case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC:
  ret = kvm_s390_set_processor_subfunc(kvm, attr);
  break;
 case KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST:
  ret = kvm_s390_set_uv_feat(kvm, attr);
  break;
 }
 return ret;
}

static int kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_processor *proc;
 int ret = 0;

 proc = kzalloc(sizeof(*proc), GFP_KERNEL_ACCOUNT);
 if (!proc) {
  ret = -ENOMEM;
  goto out;
 }
 proc->cpuid = kvm->arch.model.cpuid;
 proc->ibc = kvm->arch.model.ibc;
 memcpy(&proc->fac_list, kvm->arch.model.fac_list,
        S390_ARCH_FAC_LIST_SIZE_BYTE);
 VM_EVENT(kvm, 3, "GET: guest ibc: 0x%4.4x, guest cpuid: 0x%16.16llx",
   kvm->arch.model.ibc,
   kvm->arch.model.cpuid);
 VM_EVENT(kvm, 3, "GET: guest faclist: 0x%16.16llx.%16.16llx.%16.16llx",
   kvm->arch.model.fac_list[0],
   kvm->arch.model.fac_list[1],
   kvm->arch.model.fac_list[2]);
 if (copy_to_user((void __user *)attr->addr, proc, sizeof(*proc)))
  ret = -EFAULT;
 kfree(proc);
out:
 return ret;
}

static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_machine *mach;
 int ret = 0;

 mach = kzalloc(sizeof(*mach), GFP_KERNEL_ACCOUNT);
 if (!mach) {
  ret = -ENOMEM;
  goto out;
 }
 get_cpu_id((struct cpuid *) &mach->cpuid);
 mach->ibc = sclp.ibc;
 memcpy(&mach->fac_mask, kvm->arch.model.fac_mask,
        S390_ARCH_FAC_LIST_SIZE_BYTE);
 memcpy((unsigned long *)&mach->fac_list, stfle_fac_list,
        sizeof(stfle_fac_list));
 VM_EVENT(kvm, 3, "GET: host ibc: 0x%4.4x, host cpuid: 0x%16.16llx",
   kvm->arch.model.ibc,
   kvm->arch.model.cpuid);
 VM_EVENT(kvm, 3, "GET: host facmask: 0x%16.16llx.%16.16llx.%16.16llx",
   mach->fac_mask[0],
   mach->fac_mask[1],
   mach->fac_mask[2]);
 VM_EVENT(kvm, 3, "GET: host faclist: 0x%16.16llx.%16.16llx.%16.16llx",
   mach->fac_list[0],
   mach->fac_list[1],
   mach->fac_list[2]);
 if (copy_to_user((void __user *)attr->addr, mach, sizeof(*mach)))
  ret = -EFAULT;
 kfree(mach);
out:
 return ret;
}

static int kvm_s390_get_processor_feat(struct kvm *kvm,
           struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_feat data;

 bitmap_to_arr64(data.feat, kvm->arch.cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
 if (copy_to_user((void __user *)attr->addr, &data, sizeof(data)))
  return -EFAULT;
 VM_EVENT(kvm, 3, "GET: guest feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx",
    data.feat[0],
    data.feat[1],
    data.feat[2]);
 return 0;
}

static int kvm_s390_get_machine_feat(struct kvm *kvm,
         struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_feat data;

 bitmap_to_arr64(data.feat, kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
 if (copy_to_user((void __user *)attr->addr, &data, sizeof(data)))
  return -EFAULT;
 VM_EVENT(kvm, 3, "GET: host feat: 0x%16.16llx.0x%16.16llx.0x%16.16llx",
    data.feat[0],
    data.feat[1],
    data.feat[2]);
 return 0;
}

static int kvm_s390_get_processor_subfunc(struct kvm *kvm,
       struct kvm_device_attr *attr)
{
 if (copy_to_user((void __user *)attr->addr, &kvm->arch.model.subfuncs,
     sizeof(struct kvm_s390_vm_cpu_subfunc)))
  return -EFAULT;

 VM_EVENT(kvm, 3, "GET: guest PLO subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[1],
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[2],
   ((unsigned long *) &kvm->arch.model.subfuncs.plo)[3]);
 VM_EVENT(kvm, 3, "GET: guest PTFF subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.ptff)[1]);
 VM_EVENT(kvm, 3, "GET: guest KMAC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmac)[1]);
 VM_EVENT(kvm, 3, "GET: guest KMC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmc)[1]);
 VM_EVENT(kvm, 3, "GET: guest KM subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.km)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.km)[1]);
 VM_EVENT(kvm, 3, "GET: guest KIMD subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kimd)[1]);
 VM_EVENT(kvm, 3, "GET: guest KLMD subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.klmd)[1]);
 VM_EVENT(kvm, 3, "GET: guest PCKMO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.pckmo)[1]);
 VM_EVENT(kvm, 3, "GET: guest KMCTR subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmctr)[1]);
 VM_EVENT(kvm, 3, "GET: guest KMF subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmf)[1]);
 VM_EVENT(kvm, 3, "GET: guest KMO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kmo)[1]);
 VM_EVENT(kvm, 3, "GET: guest PCC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.pcc)[1]);
 VM_EVENT(kvm, 3, "GET: guest PPNO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.ppno)[1]);
 VM_EVENT(kvm, 3, "GET: guest KMA subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kma)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kma)[1]);
 VM_EVENT(kvm, 3, "GET: guest KDSA subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.kdsa)[1]);
 VM_EVENT(kvm, 3, "GET: guest SORTL subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[1],
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[2],
   ((unsigned long *) &kvm->arch.model.subfuncs.sortl)[3]);
 VM_EVENT(kvm, 3, "GET: guest DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[0],
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1],
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2],
   ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]);
 VM_EVENT(kvm, 3, "GET: guest PFCR subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[1]);

 return 0;
}

static int kvm_s390_get_machine_subfunc(struct kvm *kvm,
     struct kvm_device_attr *attr)
{
 if (copy_to_user((void __user *)attr->addr, &kvm_s390_available_subfunc,
     sizeof(struct kvm_s390_vm_cpu_subfunc)))
  return -EFAULT;

 VM_EVENT(kvm, 3, "GET: host PLO subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.plo)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.plo)[1],
   ((unsigned long *) &kvm_s390_available_subfunc.plo)[2],
   ((unsigned long *) &kvm_s390_available_subfunc.plo)[3]);
 VM_EVENT(kvm, 3, "GET: host PTFF subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.ptff)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.ptff)[1]);
 VM_EVENT(kvm, 3, "GET: host KMAC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kmac)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kmac)[1]);
 VM_EVENT(kvm, 3, "GET: host KMC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kmc)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kmc)[1]);
 VM_EVENT(kvm, 3, "GET: host KM subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.km)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.km)[1]);
 VM_EVENT(kvm, 3, "GET: host KIMD subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kimd)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kimd)[1]);
 VM_EVENT(kvm, 3, "GET: host KLMD subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.klmd)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.klmd)[1]);
 VM_EVENT(kvm, 3, "GET: host PCKMO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.pckmo)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.pckmo)[1]);
 VM_EVENT(kvm, 3, "GET: host KMCTR subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kmctr)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kmctr)[1]);
 VM_EVENT(kvm, 3, "GET: host KMF subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kmf)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kmf)[1]);
 VM_EVENT(kvm, 3, "GET: host KMO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kmo)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kmo)[1]);
 VM_EVENT(kvm, 3, "GET: host PCC subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.pcc)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.pcc)[1]);
 VM_EVENT(kvm, 3, "GET: host PPNO subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.ppno)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.ppno)[1]);
 VM_EVENT(kvm, 3, "GET: host KMA subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kma)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kma)[1]);
 VM_EVENT(kvm, 3, "GET: host KDSA subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.kdsa)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.kdsa)[1]);
 VM_EVENT(kvm, 3, "GET: host SORTL subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.sortl)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.sortl)[1],
   ((unsigned long *) &kvm_s390_available_subfunc.sortl)[2],
   ((unsigned long *) &kvm_s390_available_subfunc.sortl)[3]);
 VM_EVENT(kvm, 3, "GET: host DFLTCC subfunc 0x%16.16lx.%16.16lx.%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[1],
   ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[2],
   ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[3]);
 VM_EVENT(kvm, 3, "GET: host PFCR subfunc 0x%16.16lx.%16.16lx",
   ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[0],
   ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[1]);

 return 0;
}

static int kvm_s390_get_processor_uv_feat(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_uv_feat __user *dst = (void __user *)attr->addr;
 unsigned long feat = kvm->arch.model.uv_feat_guest.feat;

 if (put_user(feat, &dst->feat))
  return -EFAULT;
 VM_EVENT(kvm, 3, "GET: guest UV-feat: 0x%16.16lx", feat);

 return 0;
}

static int kvm_s390_get_machine_uv_feat(struct kvm *kvm, struct kvm_device_attr *attr)
{
 struct kvm_s390_vm_cpu_uv_feat __user *dst = (void __user *)attr->addr;
 unsigned long feat;

 BUILD_BUG_ON(sizeof(*dst) != sizeof(uv_info.uv_feature_indications));

 feat = uv_info.uv_feature_indications & KVM_S390_VM_CPU_UV_FEAT_GUEST_MASK;
 if (put_user(feat, &dst->feat))
  return -EFAULT;
 VM_EVENT(kvm, 3, "GET: guest UV-feat: 0x%16.16lx", feat);

 return 0;
}

static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret = -ENXIO;

 switch (attr->attr) {
 case KVM_S390_VM_CPU_PROCESSOR:
  ret = kvm_s390_get_processor(kvm, attr);
  break;
 case KVM_S390_VM_CPU_MACHINE:
  ret = kvm_s390_get_machine(kvm, attr);
  break;
 case KVM_S390_VM_CPU_PROCESSOR_FEAT:
  ret = kvm_s390_get_processor_feat(kvm, attr);
  break;
 case KVM_S390_VM_CPU_MACHINE_FEAT:
  ret = kvm_s390_get_machine_feat(kvm, attr);
  break;
 case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC:
  ret = kvm_s390_get_processor_subfunc(kvm, attr);
  break;
 case KVM_S390_VM_CPU_MACHINE_SUBFUNC:
  ret = kvm_s390_get_machine_subfunc(kvm, attr);
  break;
 case KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST:
  ret = kvm_s390_get_processor_uv_feat(kvm, attr);
  break;
 case KVM_S390_VM_CPU_MACHINE_UV_FEAT_GUEST:
  ret = kvm_s390_get_machine_uv_feat(kvm, attr);
  break;
 }
 return ret;
}

/**
 * kvm_s390_update_topology_change_report - update CPU topology change report
 * @kvm: guest KVM description
 * @val: set or clear the MTCR bit
 *
 * Updates the Multiprocessor Topology-Change-Report bit to signal
 * the guest with a topology change.
 * This is only relevant if the topology facility is present.
 *
 * The SCA version, bsca or esca, doesn't matter as offset is the same.
 */

static void kvm_s390_update_topology_change_report(struct kvm *kvm, bool val)
{
 union sca_utility new, old;
 struct bsca_block *sca;

 read_lock(&kvm->arch.sca_lock);
 sca = kvm->arch.sca;
 old = READ_ONCE(sca->utility);
 do {
  new = old;
  new.mtcr = val;
 } while (!try_cmpxchg(&sca->utility.val, &old.val, new.val));
 read_unlock(&kvm->arch.sca_lock);
}

static int kvm_s390_set_topo_change_indication(struct kvm *kvm,
            struct kvm_device_attr *attr)
{
 if (!test_kvm_facility(kvm, 11))
  return -ENXIO;

 kvm_s390_update_topology_change_report(kvm, !!attr->attr);
 return 0;
}

static int kvm_s390_get_topo_change_indication(struct kvm *kvm,
            struct kvm_device_attr *attr)
{
 u8 topo;

 if (!test_kvm_facility(kvm, 11))
  return -ENXIO;

 read_lock(&kvm->arch.sca_lock);
 topo = ((struct bsca_block *)kvm->arch.sca)->utility.mtcr;
 read_unlock(&kvm->arch.sca_lock);

 return put_user(topo, (u8 __user *)attr->addr);
}

static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;

 switch (attr->group) {
 case KVM_S390_VM_MEM_CTRL:
  ret = kvm_s390_set_mem_control(kvm, attr);
  break;
 case KVM_S390_VM_TOD:
  ret = kvm_s390_set_tod(kvm, attr);
  break;
 case KVM_S390_VM_CPU_MODEL:
  ret = kvm_s390_set_cpu_model(kvm, attr);
  break;
 case KVM_S390_VM_CRYPTO:
  ret = kvm_s390_vm_set_crypto(kvm, attr);
  break;
 case KVM_S390_VM_MIGRATION:
  ret = kvm_s390_vm_set_migration(kvm, attr);
  break;
 case KVM_S390_VM_CPU_TOPOLOGY:
  ret = kvm_s390_set_topo_change_indication(kvm, attr);
  break;
 default:
  ret = -ENXIO;
  break;
 }

 return ret;
}

static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;

 switch (attr->group) {
 case KVM_S390_VM_MEM_CTRL:
  ret = kvm_s390_get_mem_control(kvm, attr);
  break;
 case KVM_S390_VM_TOD:
  ret = kvm_s390_get_tod(kvm, attr);
  break;
 case KVM_S390_VM_CPU_MODEL:
  ret = kvm_s390_get_cpu_model(kvm, attr);
  break;
 case KVM_S390_VM_MIGRATION:
  ret = kvm_s390_vm_get_migration(kvm, attr);
  break;
 case KVM_S390_VM_CPU_TOPOLOGY:
  ret = kvm_s390_get_topo_change_indication(kvm, attr);
  break;
 default:
  ret = -ENXIO;
  break;
 }

 return ret;
}

static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
{
 int ret;

 switch (attr->group) {
 case KVM_S390_VM_MEM_CTRL:
  switch (attr->attr) {
  case KVM_S390_VM_MEM_ENABLE_CMMA:
  case KVM_S390_VM_MEM_CLR_CMMA:
   ret = sclp.has_cmma ? 0 : -ENXIO;
   break;
  case KVM_S390_VM_MEM_LIMIT_SIZE:
   ret = 0;
   break;
  default:
   ret = -ENXIO;
   break;
  }
  break;
 case KVM_S390_VM_TOD:
  switch (attr->attr) {
  case KVM_S390_VM_TOD_LOW:
  case KVM_S390_VM_TOD_HIGH:
   ret = 0;
   break;
  default:
   ret = -ENXIO;
   break;
  }
  break;
 case KVM_S390_VM_CPU_MODEL:
  switch (attr->attr) {
  case KVM_S390_VM_CPU_PROCESSOR:
  case KVM_S390_VM_CPU_MACHINE:
  case KVM_S390_VM_CPU_PROCESSOR_FEAT:
  case KVM_S390_VM_CPU_MACHINE_FEAT:
  case KVM_S390_VM_CPU_MACHINE_SUBFUNC:
  case KVM_S390_VM_CPU_PROCESSOR_SUBFUNC:
  case KVM_S390_VM_CPU_MACHINE_UV_FEAT_GUEST:
  case KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST:
   ret = 0;
   break;
  default:
   ret = -ENXIO;
   break;
  }
  break;
 case KVM_S390_VM_CRYPTO:
  switch (attr->attr) {
  case KVM_S390_VM_CRYPTO_ENABLE_AES_KW:
  case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW:
  case KVM_S390_VM_CRYPTO_DISABLE_AES_KW:
  case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW:
   ret = 0;
   break;
  case KVM_S390_VM_CRYPTO_ENABLE_APIE:
  case KVM_S390_VM_CRYPTO_DISABLE_APIE:
   ret = ap_instructions_available() ? 0 : -ENXIO;
   break;
  default:
   ret = -ENXIO;
   break;
  }
  break;
 case KVM_S390_VM_MIGRATION:
  ret = 0;
  break;
 case KVM_S390_VM_CPU_TOPOLOGY:
  ret = test_kvm_facility(kvm, 11) ? 0 : -ENXIO;
  break;
 default:
  ret = -ENXIO;
  break;
 }

 return ret;
}

static int kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
{
 uint8_t *keys;
 uint64_t hva;
 int srcu_idx, i, r = 0;

 if (args->flags != 0)
  return -EINVAL;

 /* Is this guest using storage keys? */
 if (!mm_uses_skeys(current->mm))
  return KVM_S390_GET_SKEYS_NONE;

 /* Enforce sane limit on memory allocation */
 if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX)
  return -EINVAL;

 keys = kvmalloc_array(args->count, sizeof(uint8_t), GFP_KERNEL_ACCOUNT);
 if (!keys)
  return -ENOMEM;

 mmap_read_lock(current->mm);
 srcu_idx = srcu_read_lock(&kvm->srcu);
 for (i = 0; i < args->count; i++) {
  hva = gfn_to_hva(kvm, args->start_gfn + i);
  if (kvm_is_error_hva(hva)) {
   r = -EFAULT;
   break;
  }

  r = get_guest_storage_key(current->mm, hva, &keys[i]);
  if (r)
   break;
 }
 srcu_read_unlock(&kvm->srcu, srcu_idx);
 mmap_read_unlock(current->mm);

 if (!r) {
  r = copy_to_user((uint8_t __user *)args->skeydata_addr, keys,
     sizeof(uint8_t) * args->count);
  if (r)
   r = -EFAULT;
 }

 kvfree(keys);
 return r;
}

static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
{
 uint8_t *keys;
 uint64_t hva;
 int srcu_idx, i, r = 0;
 bool unlocked;

 if (args->flags != 0)
  return -EINVAL;

 /* Enforce sane limit on memory allocation */
 if (args->count < 1 || args->count > KVM_S390_SKEYS_MAX)
  return -EINVAL;

 keys = kvmalloc_array(args->count, sizeof(uint8_t), GFP_KERNEL_ACCOUNT);
 if (!keys)
  return -ENOMEM;

 r = copy_from_user(keys, (uint8_t __user *)args->skeydata_addr,
      sizeof(uint8_t) * args->count);
 if (r) {
  r = -EFAULT;
  goto out;
 }

 /* Enable storage key handling for the guest */
 r = s390_enable_skey();
 if (r)
  goto out;

 i = 0;
 mmap_read_lock(current->mm);
 srcu_idx = srcu_read_lock(&kvm->srcu);
        while (i < args->count) {
  unlocked = false;
  hva = gfn_to_hva(kvm, args->start_gfn + i);
  if (kvm_is_error_hva(hva)) {
   r = -EFAULT;
   break;
  }

  /* Lowest order bit is reserved */
  if (keys[i] & 0x01) {
   r = -EINVAL;
   break;
  }

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=93 G=94

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Normalansicht

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.