/* 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 */ staticbool 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 */ unsignedint 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");
/* 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" */ staticstruct kvm_s390_vm_cpu_subfunc kvm_s390_available_subfunc;
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, unsignedint ioctl, unsignedlong 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: /* *Flagbitsindicatingwhichextensionsaresupported. *Ifr>0,thebaseextensionmustalsobesupported/indicated, *inordertomaintainbackwardscompatibility.
*/
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; elseif (sclp.has_esca && sclp.has_64bscao)
r = KVM_S390_ESCA_CPU_SLOTS; if (ext == KVM_CAP_NR_VCPUS)
r = min_t(unsignedint, 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],
(unsignedlong *)&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;
}
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;
} elseif (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;
} elseif (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;
} elseif (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; elseif (!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); /* *Wemighthavetocreatefake4kpage *tables.Toavoidthatthehardwareworkson *stalePGSTEs,weemulatetheseinstructions.
*/
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;
} elseif (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;
}
staticint 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;
}
staticint kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
{ int ret; unsignedint 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; elseif (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;
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;
}
staticvoid 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;
staticint 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);
staticint kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
{ int ret;
if (attr->flags) return -EINVAL;
mutex_lock(&kvm->lock); /* *Forprotectedguests,theTODismanagedbytheultravisor,sotrying *tochangeitwillneverbringtheexpectedresults.
*/ 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;
}
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);
return0;
}
staticint 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;
}
staticint 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;
staticint 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;
}
staticint kvm_s390_get_processor(struct kvm *kvm, struct kvm_device_attr *attr)
{ struct kvm_s390_vm_cpu_processor *proc; int ret = 0;
staticint 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;
}
staticint 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;
}
staticint 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;
}
staticint 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;
}
staticint 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;
}
staticint 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;
}
r = set_guest_storage_key(current->mm, hva, keys[i], 0); if (r) {
r = fixup_user_fault(current->mm, hva,
FAULT_FLAG_WRITE, &unlocked); if (r) break;
} if (!r)
i++;
}
srcu_read_unlock(&kvm->srcu, srcu_idx);
mmap_read_unlock(current->mm);
out:
kvfree(keys); return r;
}
if (ms->base_gfn + ms->npages <= cur_gfn) {
mnode = rb_next(mnode); /* If we are above the highest slot, wrap around */ if (!mnode)
mnode = rb_first(&slots->gfn_tree);
ms = container_of(mnode, struct kvm_memory_slot, gfn_node[slots->node_idx]);
ofs = 0;
}
while (args->count < bufsize) {
hva = gfn_to_hva(kvm, cur_gfn); if (kvm_is_error_hva(hva)) return0; /* Decrement only if we actually flipped the bit to 0 */ if (test_and_clear_bit(cur_gfn - ms->base_gfn, kvm_second_dirty_bitmap(ms)))
atomic64_dec(&kvm->arch.cmma_dirty_pages); if (get_pgste(kvm->mm, hva, &pgstev) < 0)
pgstev = 0; /* Save the value */
res[args->count++] = (pgstev >> 24) & 0x43; /* If the next bit is too far away, stop. */ if (next_gfn > cur_gfn + KVM_S390_MAX_BIT_DISTANCE) return0; /* If we reached the previous "next", find the next one */ if (cur_gfn == next_gfn)
next_gfn = kvm_s390_next_dirty_cmma(slots, cur_gfn + 1); /* Reached the end of memory or of the buffer, stop */ if ((next_gfn >= mem_end) ||
(next_gfn - args->start_gfn >= bufsize)) return0;
cur_gfn++; /* Reached the end of the current memslot, take the next one. */ if (cur_gfn - ms->base_gfn >= ms->npages) {
ms = gfn_to_memslot(kvm, cur_gfn); if (!ms) return0;
}
} return0;
}
if (!kvm->arch.use_cmma) return -ENXIO; /* Invalid/unsupported flags were specified */ if (args->flags & ~KVM_S390_CMMA_PEEK) return -EINVAL; /* Migration mode query, and we are not doing a migration */
peek = !!(args->flags & KVM_S390_CMMA_PEEK); if (!peek && !kvm->arch.migration_mode) return -EINVAL; /* CMMA is disabled or was not used, or the buffer has length zero */
bufsize = min(args->count, KVM_S390_CMMA_SIZE_MAX); if (!bufsize || !kvm->mm->context.uses_cmm) {
memset(args, 0, sizeof(*args)); return0;
} /* We are not peeking, and there are no dirty pages */ if (!peek && !atomic64_read(&kvm->arch.cmma_dirty_pages)) {
memset(args, 0, sizeof(*args)); return0;
}
values = vmalloc(bufsize); if (!values) return -ENOMEM;
mmap_read_lock(kvm->mm);
srcu_idx = srcu_read_lock(&kvm->srcu); if (peek)
ret = kvm_s390_peek_cmma(kvm, args, values, bufsize); else
ret = kvm_s390_get_cmma(kvm, args, values, bufsize);
srcu_read_unlock(&kvm->srcu, srcu_idx);
mmap_read_unlock(kvm->mm);
if (kvm->arch.migration_mode)
args->remaining = atomic64_read(&kvm->arch.cmma_dirty_pages); else
args->remaining = 0;
if (copy_to_user((void __user *)args->values, values, args->count))
ret = -EFAULT;
if (!kvm->arch.use_cmma) return -ENXIO; /* invalid/unsupported flags */ if (args->flags != 0) return -EINVAL; /* Enforce sane limit on memory allocation */ if (args->count > KVM_S390_CMMA_SIZE_MAX) return -EINVAL; /* Nothing to do */ if (args->count == 0) return0;
bits = vmalloc(array_size(sizeof(*bits), args->count)); if (!bits) return -ENOMEM;
r = copy_from_user(bits, (void __user *)args->values, args->count); if (r) {
r = -EFAULT; goto out;
}
mmap_read_lock(kvm->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;
}
/* *WeignorefailuresandtrytodestroyasmanyCPUsaspossible. *Atthesametimewemustnotfreetheassignedresourceswhen *thisfails,astheultravisorhasstillaccesstothatmemory. *Sokvm_s390_pv_destroy_cpucanleavea"wanted"memoryleak *behind. *Wewanttoreturnthefirstfailurercandrrc,though.
*/
kvm_for_each_vcpu(i, vcpu, kvm) {
mutex_lock(&vcpu->mutex); if (kvm_s390_pv_destroy_cpu(vcpu, &_rc, &_rrc) && !ret) {
*rc = _rc;
*rrc = _rrc;
ret = -EIO;
}
mutex_unlock(&vcpu->mutex);
} /* Ensure that we re-enable gisa if the non-PV guest used it but the PV guest did not. */ if (use_gisa)
kvm_s390_gisa_enable(kvm); return ret;
}
/* It's max cpuid not max cpus, so it's off by one */
info->vm.max_cpus = uv_info.max_guest_cpu_id + 1;
info->vm.max_guests = uv_info.max_num_sec_conf;
info->vm.max_guest_addr = uv_info.max_sec_stor_addr;
info->vm.feature_indication = uv_info.uv_feature_indications;
switch (cmd->cmd) { case KVM_PV_ENABLE: {
r = -EINVAL; if (kvm_s390_pv_is_protected(kvm)) break;
/* *FMT4SIEneedsesca.Asweneverswitchbacktobscafrom *esca,weneednocleanupintheerrorcasesbelow
*/
r = sca_switch_to_extended(kvm); if (r) break;
mmap_write_lock(kvm->mm);
r = gmap_helper_disable_cow_sharing();
mmap_write_unlock(kvm->mm); if (r) break;
r = kvm_s390_pv_init_vm(kvm, &cmd->rc, &cmd->rrc); if (r) break;
r = kvm_s390_cpus_to_pv(kvm, &cmd->rc, &cmd->rrc); if (r)
kvm_s390_pv_deinit_vm(kvm, &dummy, &dummy);
/* we need to block service interrupts from now on */
set_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs); break;
} case KVM_PV_ASYNC_CLEANUP_PREPARE:
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm) || !async_destroy) break;
r = kvm_s390_cpus_from_pv(kvm, &cmd->rc, &cmd->rrc); /* *IfaCPUcouldnotbedestroyed,destroyVMwillalsofail. *Thereisnopointintryingtodestroyit.Insteadreturn *thercandrrcfromthefirstCPUthatfaileddestroying.
*/ if (r) break;
r = kvm_s390_pv_set_aside(kvm, &cmd->rc, &cmd->rrc);
/* no need to block service interrupts any more */
clear_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs); break; case KVM_PV_ASYNC_CLEANUP_PERFORM:
r = -EINVAL; if (!async_destroy) break; /* kvm->lock must not be held; this is asserted inside the function. */
r = kvm_s390_pv_deinit_aside_vm(kvm, &cmd->rc, &cmd->rrc); break; case KVM_PV_DISABLE: {
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm)) break;
r = kvm_s390_cpus_from_pv(kvm, &cmd->rc, &cmd->rrc); /* *IfaCPUcouldnotbedestroyed,destroyVMwillalsofail. *Thereisnopointintryingtodestroyit.Insteadreturn *thercandrrcfromthefirstCPUthatfaileddestroying.
*/ if (r) break;
r = kvm_s390_pv_deinit_cleanup_all(kvm, &cmd->rc, &cmd->rrc);
/* no need to block service interrupts any more */
clear_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs); break;
} case KVM_PV_SET_SEC_PARMS: { struct kvm_s390_pv_sec_parm parms = {}; void *hdr;
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm)) break;
r = -EFAULT; if (copy_from_user(&parms, argp, sizeof(parms))) break;
/* Currently restricted to 8KB */
r = -EINVAL; if (parms.length > PAGE_SIZE * 2) break;
r = -ENOMEM;
hdr = vmalloc(parms.length); if (!hdr) break;
r = -EFAULT; if (!copy_from_user(hdr, (void __user *)parms.origin,
parms.length))
r = kvm_s390_pv_set_sec_parms(kvm, hdr, parms.length,
&cmd->rc, &cmd->rrc);
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm) || !mm_is_protected(kvm->mm)) break;
r = -EFAULT; if (copy_from_user(&unp, argp, sizeof(unp))) break;
r = kvm_s390_pv_unpack(kvm, unp.addr, unp.size, unp.tweak,
&cmd->rc, &cmd->rrc); break;
} case KVM_PV_VERIFY: {
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm)) break;
r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
UVC_CMD_VERIFY_IMG, &cmd->rc, &cmd->rrc);
KVM_UV_EVENT(kvm, 3, "PROTVIRT VERIFY: rc %x rrc %x", cmd->rc,
cmd->rrc); break;
} case KVM_PV_PREP_RESET: {
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm)) break;
r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
UVC_CMD_PREPARE_RESET, &cmd->rc, &cmd->rrc);
KVM_UV_EVENT(kvm, 3, "PROTVIRT PREP RESET: rc %x rrc %x",
cmd->rc, cmd->rrc); break;
} case KVM_PV_UNSHARE_ALL: {
r = -EINVAL; if (!kvm_s390_pv_is_protected(kvm)) break;
r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm),
UVC_CMD_SET_UNSHARE_ALL, &cmd->rc, &cmd->rrc);
KVM_UV_EVENT(kvm, 3, "PROTVIRT UNSHARE: rc %x rrc %x",
cmd->rc, cmd->rrc); break;
} case KVM_PV_INFO: { struct kvm_s390_pv_info info = {};
ssize_t data_len;
switch (ioctl) { case KVM_S390_INTERRUPT: { struct kvm_s390_interrupt s390int;
r = -EFAULT; if (copy_from_user(&s390int, argp, sizeof(s390int))) break;
r = kvm_s390_inject_vm(kvm, &s390int); break;
} case KVM_CREATE_IRQCHIP: {
r = -EINVAL; if (kvm->arch.use_irqchip)
r = 0; break;
} case KVM_SET_DEVICE_ATTR: {
r = -EFAULT; if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) break;
r = kvm_s390_vm_set_attr(kvm, &attr); break;
} case KVM_GET_DEVICE_ATTR: {
r = -EFAULT; if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) break;
r = kvm_s390_vm_get_attr(kvm, &attr); break;
} case KVM_HAS_DEVICE_ATTR: {
r = -EFAULT; if (copy_from_user(&attr, (void __user *)arg, sizeof(attr))) break;
r = kvm_s390_vm_has_attr(kvm, &attr); break;
} case KVM_S390_GET_SKEYS: { struct kvm_s390_skeys args;
r = -EFAULT; if (copy_from_user(&args, argp, sizeof(struct kvm_s390_skeys))) break;
r = kvm_s390_get_skeys(kvm, &args); break;
} case KVM_S390_SET_SKEYS: { struct kvm_s390_skeys args;
r = -EFAULT; if (copy_from_user(&args, argp, sizeof(struct kvm_s390_skeys))) break;
r = kvm_s390_set_skeys(kvm, &args); break;
} case KVM_S390_GET_CMMA_BITS: { struct kvm_s390_cmma_log args;
r = -EFAULT; if (copy_from_user(&args, argp, sizeof(args))) break;
mutex_lock(&kvm->slots_lock);
r = kvm_s390_get_cmma_bits(kvm, &args);
mutex_unlock(&kvm->slots_lock); if (!r) {
r = copy_to_user(argp, &args, sizeof(args)); if (r)
r = -EFAULT;
} break;
} case KVM_S390_SET_CMMA_BITS: { struct kvm_s390_cmma_log args;
r = -EFAULT; if (copy_from_user(&args, argp, sizeof(args))) break;
mutex_lock(&kvm->slots_lock);
r = kvm_s390_set_cmma_bits(kvm, &args);
mutex_unlock(&kvm->slots_lock); break;
} case KVM_S390_PV_COMMAND: { struct kvm_pv_cmd args;
/* protvirt means user cpu state */
kvm_s390_set_user_cpu_state_ctrl(kvm);
r = 0; if (!is_prot_virt_host()) {
r = -EINVAL; break;
} if (copy_from_user(&args, argp, sizeof(args))) {
r = -EFAULT; break;
} if (args.flags) {
r = -EINVAL; break;
} /* must be called without kvm->lock */
r = kvm_s390_handle_pv(kvm, &args); if (copy_to_user(argp, &args, sizeof(args))) {
r = -EFAULT; break;
} break;
} case KVM_S390_MEM_OP: { struct kvm_s390_mem_op mem_op;
if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0)
r = kvm_s390_vm_mem_op(kvm, &mem_op); else
r = -EFAULT; break;
} case KVM_S390_ZPCI_OP: { struct kvm_s390_zpci_op args;
r = -EINVAL; if (!IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) break; if (copy_from_user(&args, argp, sizeof(args))) {
r = -EFAULT; break;
}
r = kvm_s390_pci_zpci_op(kvm, &args); break;
} default:
r = -ENOTTY;
}
/* recreate the shadow crycb for each vcpu */
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_VSIE_RESTART);
kvm_s390_vcpu_unblock_all(kvm);
}
EXPORT_SYMBOL_GPL(kvm_arch_crypto_set_masks);
for (i = 0; i < kvm_s390_fac_size(); i++) {
kvm->arch.model.fac_mask[i] = stfle_fac_list[i] &
(kvm_s390_fac_base[i] |
kvm_s390_fac_ext[i]);
kvm->arch.model.fac_list[i] = stfle_fac_list[i] &
kvm_s390_fac_base[i];
}
kvm->arch.model.subfuncs = kvm_s390_available_subfunc;
/* we are always in czam mode - even on pre z14 machines */
set_kvm_facility(kvm->arch.model.fac_mask, 138);
set_kvm_facility(kvm->arch.model.fac_list, 138); /* we emulate STHYI in kvm */
set_kvm_facility(kvm->arch.model.fac_mask, 74);
set_kvm_facility(kvm->arch.model.fac_list, 74); if (machine_has_tlb_guest()) {
set_kvm_facility(kvm->arch.model.fac_mask, 147);
set_kvm_facility(kvm->arch.model.fac_list, 147);
}
if (css_general_characteristics.aiv && test_facility(65))
set_kvm_facility(kvm->arch.model.fac_mask, 65);
if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) {
mutex_lock(&kvm->lock);
kvm_s390_pci_init_list(kvm);
kvm_s390_vcpu_pci_enable_interp(kvm);
mutex_unlock(&kvm->lock);
}
mutex_init(&kvm->arch.float_int.ais_lock);
spin_lock_init(&kvm->arch.float_int.lock); for (i = 0; i < FIRQ_LIST_COUNT; i++)
INIT_LIST_HEAD(&kvm->arch.float_int.lists[i]);
init_waitqueue_head(&kvm->arch.ipte_wq);
mutex_init(&kvm->arch.ipte_mutex);
debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
VM_EVENT(kvm, 3, "vm created with type %lu", type);
if (kvm_is_ucontrol(vcpu->kvm))
gmap_remove(vcpu->arch.gmap);
if (vcpu->kvm->arch.use_cmma)
kvm_s390_vcpu_unsetup_cmma(vcpu); /* We can not hold the vcpu mutex here, we are already dying */ if (kvm_s390_pv_cpu_get_handle(vcpu))
kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc);
free_page((unsignedlong)(vcpu->arch.sie_block));
}
/* we still need the basic sca for the ipte control */
vcpu->arch.sie_block->scaoh = sca_phys >> 32;
vcpu->arch.sie_block->scaol = sca_phys; return;
}
read_lock(&vcpu->kvm->arch.sca_lock); if (vcpu->kvm->arch.use_esca) { struct esca_block *sca = vcpu->kvm->arch.sca;
phys_addr_t sca_phys = virt_to_phys(sca);
staticint sca_can_add_vcpu(struct kvm *kvm, unsignedint id)
{ int rc;
if (!kvm_s390_use_sca_entries()) { if (id < KVM_MAX_VCPUS) returntrue; returnfalse;
} if (id < KVM_S390_BSCA_CPU_SLOTS) returntrue; if (!sclp.has_esca || !sclp.has_64bscao) returnfalse;
/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ staticvoid __start_cpu_timer_accounting(struct kvm_vcpu *vcpu)
{
WARN_ON_ONCE(vcpu->arch.cputm_start != 0);
raw_write_seqcount_begin(&vcpu->arch.cputm_seqcount);
vcpu->arch.cputm_start = get_tod_clock_fast();
raw_write_seqcount_end(&vcpu->arch.cputm_seqcount);
}
/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ staticvoid __stop_cpu_timer_accounting(struct kvm_vcpu *vcpu)
{
WARN_ON_ONCE(vcpu->arch.cputm_start == 0);
raw_write_seqcount_begin(&vcpu->arch.cputm_seqcount);
vcpu->arch.sie_block->cputm -= get_tod_clock_fast() - vcpu->arch.cputm_start;
vcpu->arch.cputm_start = 0;
raw_write_seqcount_end(&vcpu->arch.cputm_seqcount);
}
/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ staticvoid __enable_cpu_timer_accounting(struct kvm_vcpu *vcpu)
{
WARN_ON_ONCE(vcpu->arch.cputm_enabled);
vcpu->arch.cputm_enabled = true;
__start_cpu_timer_accounting(vcpu);
}
/* needs disabled preemption to protect from TOD sync and vcpu_load/put */ staticvoid __disable_cpu_timer_accounting(struct kvm_vcpu *vcpu)
{
WARN_ON_ONCE(!vcpu->arch.cputm_enabled);
__stop_cpu_timer_accounting(vcpu);
vcpu->arch.cputm_enabled = false;
}
staticvoid enable_cpu_timer_accounting(struct kvm_vcpu *vcpu)
{
preempt_disable(); /* protect from TOD sync and vcpu_load/put */
__enable_cpu_timer_accounting(vcpu);
preempt_enable();
}
staticvoid disable_cpu_timer_accounting(struct kvm_vcpu *vcpu)
{
preempt_disable(); /* protect from TOD sync and vcpu_load/put */
__disable_cpu_timer_accounting(vcpu);
preempt_enable();
}
/* set the cpu timer - may only be called from the VCPU thread itself */ void kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm)
{
preempt_disable(); /* protect from TOD sync and vcpu_load/put */
raw_write_seqcount_begin(&vcpu->arch.cputm_seqcount); if (vcpu->arch.cputm_enabled)
vcpu->arch.cputm_start = get_tod_clock_fast();
vcpu->arch.sie_block->cputm = cputm;
raw_write_seqcount_end(&vcpu->arch.cputm_seqcount);
preempt_enable();
}
/* update and get the cpu timer - can also be called from other VCPU threads */
__u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu)
{ unsignedint seq;
__u64 value;
if (unlikely(!vcpu->arch.cputm_enabled)) return vcpu->arch.sie_block->cputm;
preempt_disable(); /* protect from TOD sync and vcpu_load/put */ do {
seq = raw_read_seqcount(&vcpu->arch.cputm_seqcount); /* *Ifthewriterwouldeverexecuteareadinthecritical *section,e.g.inirqcontext,wehaveadeadlock.
*/
WARN_ON_ONCE((seq & 1) && smp_processor_id() == vcpu->cpu);
value = vcpu->arch.sie_block->cputm; /* if cputm_start is 0, accounting is being started/stopped */ if (likely(vcpu->arch.cputm_start))
value -= get_tod_clock_fast() - vcpu->arch.cputm_start;
} while (read_seqcount_retry(&vcpu->arch.cputm_seqcount, seq & ~1));
preempt_enable(); return value;
}
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
staticbool kvm_has_pckmo_ecc(struct kvm *kvm)
{ /* At least one ECC subfunction must be present */ return kvm_has_pckmo_subfunc(kvm, 32) ||
kvm_has_pckmo_subfunc(kvm, 33) ||
kvm_has_pckmo_subfunc(kvm, 34) ||
kvm_has_pckmo_subfunc(kvm, 40) ||
kvm_has_pckmo_subfunc(kvm, 41);
}
staticbool kvm_has_pckmo_hmac(struct kvm *kvm)
{ /* At least one HMAC subfunction must be present */ return kvm_has_pckmo_subfunc(kvm, 118) ||
kvm_has_pckmo_subfunc(kvm, 122);
}
if (vcpu->kvm->arch.crypto.apie)
vcpu->arch.sie_block->eca |= ECA_APIE;
/* Set up protected key support */ if (vcpu->kvm->arch.crypto.aes_kw) {
vcpu->arch.sie_block->ecb3 |= ECB3_AES; /* ecc/hmac is also wrapped with AES key */ if (kvm_has_pckmo_ecc(vcpu->kvm))
vcpu->arch.sie_block->ecd |= ECD_ECC; if (kvm_has_pckmo_hmac(vcpu->kvm))
vcpu->arch.sie_block->ecd |= ECD_HMAC;
}
if (vcpu->kvm->arch.crypto.dea_kw)
vcpu->arch.sie_block->ecb3 |= ECB3_DEA;
}
if (test_kvm_facility(vcpu->kvm, 78))
kvm_s390_set_cpuflags(vcpu, CPUSTAT_GED2); elseif (test_kvm_facility(vcpu->kvm, 8))
kvm_s390_set_cpuflags(vcpu, CPUSTAT_GED);
kvm_s390_vcpu_setup_model(vcpu);
/* pgste_set_pte has special handling for !machine_has_esop() */ if (machine_has_esop())
vcpu->arch.sie_block->ecb |= ECB_HOSTPROTINT; if (test_kvm_facility(vcpu->kvm, 9))
vcpu->arch.sie_block->ecb |= ECB_SRSI; if (test_kvm_facility(vcpu->kvm, 11))
vcpu->arch.sie_block->ecb |= ECB_PTF; if (test_kvm_facility(vcpu->kvm, 73))
vcpu->arch.sie_block->ecb |= ECB_TE; if (!kvm_is_ucontrol(vcpu->kvm))
vcpu->arch.sie_block->ecb |= ECB_SPECI;
if (test_kvm_facility(vcpu->kvm, 8) && vcpu->kvm->arch.use_pfmfi)
vcpu->arch.sie_block->ecb2 |= ECB2_PFMFI; if (test_kvm_facility(vcpu->kvm, 130))
vcpu->arch.sie_block->ecb2 |= ECB2_IEP;
vcpu->arch.sie_block->eca = ECA_MVPGI | ECA_PROTEXCI; if (sclp.has_cei)
vcpu->arch.sie_block->eca |= ECA_CEI; if (sclp.has_ib)
vcpu->arch.sie_block->eca |= ECA_IB; if (sclp.has_siif)
vcpu->arch.sie_block->eca |= ECA_SII; if (sclp.has_sigpif)
vcpu->arch.sie_block->eca |= ECA_SIGPI; if (test_kvm_facility(vcpu->kvm, 129)) {
vcpu->arch.sie_block->eca |= ECA_VX;
vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
} if (test_kvm_facility(vcpu->kvm, 139))
vcpu->arch.sie_block->ecd |= ECD_MEF; if (test_kvm_facility(vcpu->kvm, 156))
vcpu->arch.sie_block->ecd |= ECD_ETOKENF; if (vcpu->arch.sie_block->gd) {
vcpu->arch.sie_block->eca |= ECA_AIV;
VCPU_EVENT(vcpu, 3, "AIV gisa format-%u enabled for cpu %03u",
vcpu->arch.sie_block->gd & 0x3, vcpu->vcpu_id);
}
vcpu->arch.sie_block->sdnxo = virt_to_phys(&vcpu->run->s.regs.sdnx) | SDNXC;
vcpu->arch.sie_block->riccbd = virt_to_phys(&vcpu->run->s.regs.riccb);
vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
kvm_clear_async_pf_completion_queue(vcpu);
vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX |
KVM_SYNC_GPRS |
KVM_SYNC_ACRS |
KVM_SYNC_CRS |
KVM_SYNC_ARCH0 |
KVM_SYNC_PFAULT |
KVM_SYNC_DIAG318;
vcpu->arch.acrs_loaded = false;
kvm_s390_set_prefix(vcpu, 0); if (test_kvm_facility(vcpu->kvm, 64))
vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB; if (test_kvm_facility(vcpu->kvm, 82))
vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC; if (test_kvm_facility(vcpu->kvm, 133))
vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB; if (test_kvm_facility(vcpu->kvm, 156))
vcpu->run->kvm_valid_regs |= KVM_SYNC_ETOKEN; /* fprs can be synchronized via vrs, even if the guest has no vx. With *cpu_has_vx(),(load|store)_fpu_regs()willworkwithvrsformat.
*/ if (cpu_has_vx())
vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS; else
vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS;
if (kvm_is_ucontrol(vcpu->kvm)) {
rc = __kvm_ucontrol_vcpu_init(vcpu); if (rc) goto out_free_sie_block;
}
VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sie block at 0x%p",
vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
rc = kvm_s390_vcpu_setup(vcpu); if (rc) goto out_ucontrol_uninit;
/* Kick a guest cpu out of SIE to process a request synchronously */ void kvm_s390_sync_request(int req, struct kvm_vcpu *vcpu)
{
__kvm_make_request(req, vcpu);
kvm_s390_vcpu_request(vcpu);
}
if (gmap_is_shadow(gmap)) return; if (start >= 1UL << 31) /* We are only interested in prefix pages */ return;
kvm_for_each_vcpu(i, vcpu, kvm) { /* match against both prefix pages */
prefix = kvm_s390_get_prefix(vcpu); if (prefix <= end && start <= prefix + 2*PAGE_SIZE - 1) {
VCPU_EVENT(vcpu, 2, "gmap notifier for %lx-%lx",
start, end);
kvm_s390_sync_request(KVM_REQ_REFRESH_GUEST_PREFIX, vcpu);
}
}
}
bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)
{ /* do not poll with more than halt_poll_max_steal percent of steal time */ if (get_lowcore()->avg_steal_timer * 100 / (TICK_USEC << 12) >=
READ_ONCE(halt_poll_max_steal)) {
vcpu->stat.halt_no_poll_steal++; returntrue;
} returnfalse;
}
int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
{ /* kvm common code refers to this, but never calls it */
BUG(); return0;
}
staticint kvm_arch_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
{ int r = -EINVAL;
switch (reg->id) { case KVM_REG_S390_TODPR:
r = put_user(vcpu->arch.sie_block->todpr,
(u32 __user *)reg->addr); break; case KVM_REG_S390_EPOCHDIFF:
r = put_user(vcpu->arch.sie_block->epoch,
(u64 __user *)reg->addr); break; case KVM_REG_S390_CPU_TIMER:
r = put_user(kvm_s390_get_cpu_timer(vcpu),
(u64 __user *)reg->addr); break; case KVM_REG_S390_CLOCK_COMP:
r = put_user(vcpu->arch.sie_block->ckc,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PFTOKEN:
r = put_user(vcpu->arch.pfault_token,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PFCOMPARE:
r = put_user(vcpu->arch.pfault_compare,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PFSELECT:
r = put_user(vcpu->arch.pfault_select,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PP:
r = put_user(vcpu->arch.sie_block->pp,
(u64 __user *)reg->addr); break; case KVM_REG_S390_GBEA:
r = put_user(vcpu->arch.sie_block->gbea,
(u64 __user *)reg->addr); break; default: break;
}
return r;
}
staticint kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
{ int r = -EINVAL;
__u64 val;
switch (reg->id) { case KVM_REG_S390_TODPR:
r = get_user(vcpu->arch.sie_block->todpr,
(u32 __user *)reg->addr); break; case KVM_REG_S390_EPOCHDIFF:
r = get_user(vcpu->arch.sie_block->epoch,
(u64 __user *)reg->addr); break; case KVM_REG_S390_CPU_TIMER:
r = get_user(val, (u64 __user *)reg->addr); if (!r)
kvm_s390_set_cpu_timer(vcpu, val); break; case KVM_REG_S390_CLOCK_COMP:
r = get_user(vcpu->arch.sie_block->ckc,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PFTOKEN:
r = get_user(vcpu->arch.pfault_token,
(u64 __user *)reg->addr); if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
kvm_clear_async_pf_completion_queue(vcpu); break; case KVM_REG_S390_PFCOMPARE:
r = get_user(vcpu->arch.pfault_compare,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PFSELECT:
r = get_user(vcpu->arch.pfault_select,
(u64 __user *)reg->addr); break; case KVM_REG_S390_PP:
r = get_user(vcpu->arch.sie_block->pp,
(u64 __user *)reg->addr); break; case KVM_REG_S390_GBEA:
r = get_user(vcpu->arch.sie_block->gbea,
(u64 __user *)reg->addr); break; default: break;
}
kvm_clear_async_pf_completion_queue(vcpu); if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
kvm_s390_vcpu_stop(vcpu);
kvm_s390_clear_local_irqs(vcpu);
}
staticvoid kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
{ /* Initial reset is a superset of the normal reset */
kvm_arch_vcpu_ioctl_normal_reset(vcpu);
if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID) returnfalse; if ((vcpu->arch.sie_block->gpsw.mask & vcpu->arch.pfault_select) !=
vcpu->arch.pfault_compare) returnfalse; if (psw_extint_disabled(vcpu)) returnfalse; if (kvm_s390_vcpu_has_irq(vcpu, 0)) returnfalse; if (!(vcpu->arch.sie_block->gcr[0] & CR0_SERVICE_SIGNAL_SUBMASK)) returnfalse; if (!vcpu->arch.gmap->pfault_enabled) returnfalse;
hva = gfn_to_hva(vcpu->kvm, current->thread.gmap_teid.addr); if (read_guest_real(vcpu, vcpu->arch.pfault_token, &arch.pfault_token, 8)) returnfalse;
/* Access outside memory, inject addressing exception */ if (is_noslot_pfn(pfn)) return vcpu_post_run_addressing_exception(vcpu); /* Signal pending: try again */ if (pfn == KVM_PFN_ERR_SIGPENDING) return -EAGAIN;
/* Needs I/O, try to setup async pfault (only possible with FOLL_NOWAIT) */ if (pfn == KVM_PFN_ERR_NEEDS_IO) {
trace_kvm_s390_major_guest_pfault(vcpu); if (kvm_arch_setup_async_pf(vcpu)) return0;
vcpu->stat.pfault_sync++; /* Could not setup async pfault, try again synchronously */
foll &= ~FOLL_NOWAIT; goto try_again;
} /* Any other error */ if (is_error_pfn(pfn)) return -EFAULT;
/* Success */
mmap_read_lock(vcpu->arch.gmap->mm); /* Mark the userspace PTEs as young and/or dirty, to avoid page fault loops */
rc = fixup_user_fault(vcpu->arch.gmap->mm, vmaddr, fault_flags, &unlocked); if (!rc)
rc = __gmap_link(vcpu->arch.gmap, gaddr, vmaddr);
scoped_guard(spinlock, &vcpu->kvm->mmu_lock) {
kvm_release_faultin_page(vcpu->kvm, page, false, writable);
}
mmap_read_unlock(vcpu->arch.gmap->mm); return rc;
}
int kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
{ int i, online_vcpus, r = 0, started_vcpus = 0;
if (!is_vcpu_stopped(vcpu)) return0;
trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1); /* Only one cpu at a time may enter/leave the STOPPED state. */
spin_lock(&vcpu->kvm->arch.start_stop_lock);
online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
/* Let's tell the UV that we want to change into the operating state */ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_OPR); if (r) {
spin_unlock(&vcpu->kvm->arch.start_stop_lock); return r;
}
}
for (i = 0; i < online_vcpus; i++) { if (!is_vcpu_stopped(kvm_get_vcpu(vcpu->kvm, i)))
started_vcpus++;
}
if (started_vcpus == 0) { /* we're the only active VCPU -> speed it up */
__enable_ibs_on_vcpu(vcpu);
} elseif (started_vcpus == 1) { /* *AswearestartingasecondVCPU,wehavetodisable *theIBSfacilityonallVCPUstoremovepotentially *outstandingENABLErequests.
*/
__disable_ibs_on_all_vcpus(vcpu->kvm);
}
int kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
{ int i, online_vcpus, r = 0, started_vcpus = 0; struct kvm_vcpu *started_vcpu = NULL;
if (is_vcpu_stopped(vcpu)) return0;
trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0); /* Only one cpu at a time may enter/leave the STOPPED state. */
spin_lock(&vcpu->kvm->arch.start_stop_lock);
online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
/* Let's tell the UV that we want to change into the stopped state */ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = kvm_s390_pv_set_cpu_state(vcpu, PV_CPU_STATE_STP); if (r) {
spin_unlock(&vcpu->kvm->arch.start_stop_lock); return r;
}
}
switch (mop->op) { case KVM_S390_MEMOP_LOGICAL_READ: case KVM_S390_MEMOP_LOGICAL_WRITE:
r = kvm_s390_vcpu_mem_op(vcpu, mop); break; case KVM_S390_MEMOP_SIDA_READ: case KVM_S390_MEMOP_SIDA_WRITE: /* we are locked against sida going away by the vcpu->mutex */
r = kvm_s390_vcpu_sida_op(vcpu, mop); break; default:
r = -EINVAL;
}
/* On success copy over the dump data */ if (!ret && copy_to_user((__u8 __user *)dmp.buff_addr, data, uv_info.guest_cpu_stor_len))
ret = -EFAULT;
kvfree(data); return ret;
}
long kvm_arch_vcpu_ioctl(struct file *filp, unsignedint ioctl, unsignedlong arg)
{ struct kvm_vcpu *vcpu = filp->private_data; void __user *argp = (void __user *)arg; int idx; long r;
u16 rc, rrc;
vcpu_load(vcpu);
switch (ioctl) { case KVM_S390_STORE_STATUS:
idx = srcu_read_lock(&vcpu->kvm->srcu);
r = kvm_s390_store_status_unloaded(vcpu, arg);
srcu_read_unlock(&vcpu->kvm->srcu, idx); break; case KVM_S390_SET_INITIAL_PSW: {
psw_t psw;
r = -EFAULT; if (copy_from_user(&psw, argp, sizeof(psw))) break;
r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); break;
} case KVM_S390_CLEAR_RESET:
r = 0;
kvm_arch_vcpu_ioctl_clear_reset(vcpu); if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
UVC_CMD_CPU_RESET_CLEAR, &rc, &rrc);
VCPU_EVENT(vcpu, 3, "PROTVIRT RESET CLEAR VCPU: rc %x rrc %x",
rc, rrc);
} break; case KVM_S390_INITIAL_RESET:
r = 0;
kvm_arch_vcpu_ioctl_initial_reset(vcpu); if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
UVC_CMD_CPU_RESET_INITIAL,
&rc, &rrc);
VCPU_EVENT(vcpu, 3, "PROTVIRT RESET INITIAL VCPU: rc %x rrc %x",
rc, rrc);
} break; case KVM_S390_NORMAL_RESET:
r = 0;
kvm_arch_vcpu_ioctl_normal_reset(vcpu); if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = uv_cmd_nodata(kvm_s390_pv_cpu_get_handle(vcpu),
UVC_CMD_CPU_RESET, &rc, &rrc);
VCPU_EVENT(vcpu, 3, "PROTVIRT RESET NORMAL VCPU: rc %x rrc %x",
rc, rrc);
} break; case KVM_SET_ONE_REG: case KVM_GET_ONE_REG: { struct kvm_one_reg reg;
r = -EINVAL; if (kvm_s390_pv_cpu_is_protected(vcpu)) break;
r = -EFAULT; if (copy_from_user(®, argp, sizeof(reg))) break; if (ioctl == KVM_SET_ONE_REG)
r = kvm_arch_vcpu_ioctl_set_one_reg(vcpu, ®); else
r = kvm_arch_vcpu_ioctl_get_one_reg(vcpu, ®); break;
} #ifdef CONFIG_KVM_S390_UCONTROL case KVM_S390_UCAS_MAP: { struct kvm_s390_ucas_mapping ucasmap;
if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
r = -EFAULT; break;
}
if (!kvm_is_ucontrol(vcpu->kvm)) {
r = -EINVAL; break;
}
r = gmap_map_segment(vcpu->arch.gmap, ucasmap.user_addr,
ucasmap.vcpu_addr, ucasmap.length); break;
} case KVM_S390_UCAS_UNMAP: { struct kvm_s390_ucas_mapping ucasmap;
if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
r = -EFAULT; break;
}
if (!kvm_is_ucontrol(vcpu->kvm)) {
r = -EINVAL; break;
}
r = gmap_unmap_segment(vcpu->arch.gmap, ucasmap.vcpu_addr,
ucasmap.length); break;
} #endif case KVM_S390_VCPU_FAULT: {
idx = srcu_read_lock(&vcpu->kvm->srcu);
r = vcpu_dat_fault_handler(vcpu, arg, 0);
srcu_read_unlock(&vcpu->kvm->srcu, idx); break;
} case KVM_ENABLE_CAP:
{ struct kvm_enable_cap cap;
r = -EFAULT; if (copy_from_user(&cap, argp, sizeof(cap))) break;
r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); break;
} case KVM_S390_MEM_OP: { struct kvm_s390_mem_op mem_op;
if (copy_from_user(&mem_op, argp, sizeof(mem_op)) == 0)
r = kvm_s390_vcpu_memsida_op(vcpu, &mem_op); else
r = -EFAULT; break;
} case KVM_S390_SET_IRQ_STATE: { struct kvm_s390_irq_state irq_state;
r = -EFAULT; if (copy_from_user(&irq_state, argp, sizeof(irq_state))) break; if (irq_state.len > VCPU_IRQS_MAX_BUF ||
irq_state.len == 0 ||
irq_state.len % sizeof(struct kvm_s390_irq) > 0) {
r = -EINVAL; break;
} /* do not use irq_state.flags, it will break old QEMUs */
r = kvm_s390_set_irq_state(vcpu,
(void __user *) irq_state.buf,
irq_state.len); break;
} case KVM_S390_GET_IRQ_STATE: { struct kvm_s390_irq_state irq_state;
r = -EFAULT; if (copy_from_user(&irq_state, argp, sizeof(irq_state))) break; if (irq_state.len == 0) {
r = -EINVAL; break;
} /* do not use irq_state.flags, it will break old QEMUs */
r = kvm_s390_get_irq_state(vcpu,
(__u8 __user *) irq_state.buf,
irq_state.len); break;
} case KVM_S390_PV_CPU_COMMAND: { struct kvm_pv_cmd cmd;
r = -EINVAL; if (!is_prot_virt_host()) break;
r = -EFAULT; if (copy_from_user(&cmd, argp, sizeof(cmd))) break;
r = -EINVAL; if (cmd.flags) break;
/* We only handle this cmd right now */ if (cmd.cmd != KVM_PV_DUMP) break;
r = kvm_s390_handle_pv_vcpu_dump(vcpu, &cmd);
/* Always copy over UV rc / rrc data */ if (copy_to_user((__u8 __user *)argp, &cmd.rc, sizeof(cmd.rc) + sizeof(cmd.rrc)))
r = -EFAULT; break;
} default:
r = -ENOTTY;
}
¤ 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.0.200Bemerkung:
(vorverarbeitet am 2026-09-29)
¤
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.