1e28acfeaSChristian Borntraeger /* 2a53c8fabSHeiko Carstens * handling diagnose instructions 3e28acfeaSChristian Borntraeger * 4388186bcSChristian Borntraeger * Copyright IBM Corp. 2008, 2011 5e28acfeaSChristian Borntraeger * 6e28acfeaSChristian Borntraeger * This program is free software; you can redistribute it and/or modify 7e28acfeaSChristian Borntraeger * it under the terms of the GNU General Public License (version 2 only) 8e28acfeaSChristian Borntraeger * as published by the Free Software Foundation. 9e28acfeaSChristian Borntraeger * 10e28acfeaSChristian Borntraeger * Author(s): Carsten Otte <cotte@de.ibm.com> 11e28acfeaSChristian Borntraeger * Christian Borntraeger <borntraeger@de.ibm.com> 12e28acfeaSChristian Borntraeger */ 13e28acfeaSChristian Borntraeger 14e28acfeaSChristian Borntraeger #include <linux/kvm.h> 15e28acfeaSChristian Borntraeger #include <linux/kvm_host.h> 1610ccaa1eSCornelia Huck #include <asm/virtio-ccw.h> 17e28acfeaSChristian Borntraeger #include "kvm-s390.h" 185786fffaSCornelia Huck #include "trace.h" 19ade38c31SCornelia Huck #include "trace-s390.h" 20e28acfeaSChristian Borntraeger 21388186bcSChristian Borntraeger static int diag_release_pages(struct kvm_vcpu *vcpu) 22388186bcSChristian Borntraeger { 23388186bcSChristian Borntraeger unsigned long start, end; 24388186bcSChristian Borntraeger unsigned long prefix = vcpu->arch.sie_block->prefix; 25388186bcSChristian Borntraeger 265a32c1afSChristian Borntraeger start = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; 275a32c1afSChristian Borntraeger end = vcpu->run->s.regs.gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096; 28388186bcSChristian Borntraeger 29388186bcSChristian Borntraeger if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end 30388186bcSChristian Borntraeger || start < 2 * PAGE_SIZE) 31388186bcSChristian Borntraeger return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 32388186bcSChristian Borntraeger 33388186bcSChristian Borntraeger VCPU_EVENT(vcpu, 5, "diag release pages %lX %lX", start, end); 34388186bcSChristian Borntraeger vcpu->stat.diagnose_10++; 35388186bcSChristian Borntraeger 36388186bcSChristian Borntraeger /* we checked for start > end above */ 37388186bcSChristian Borntraeger if (end < prefix || start >= prefix + 2 * PAGE_SIZE) { 38388186bcSChristian Borntraeger gmap_discard(start, end, vcpu->arch.gmap); 39388186bcSChristian Borntraeger } else { 40388186bcSChristian Borntraeger if (start < prefix) 41388186bcSChristian Borntraeger gmap_discard(start, prefix, vcpu->arch.gmap); 42388186bcSChristian Borntraeger if (end >= prefix) 43388186bcSChristian Borntraeger gmap_discard(prefix + 2 * PAGE_SIZE, 44388186bcSChristian Borntraeger end, vcpu->arch.gmap); 45388186bcSChristian Borntraeger } 46388186bcSChristian Borntraeger return 0; 47388186bcSChristian Borntraeger } 48388186bcSChristian Borntraeger 49e28acfeaSChristian Borntraeger static int __diag_time_slice_end(struct kvm_vcpu *vcpu) 50e28acfeaSChristian Borntraeger { 51e28acfeaSChristian Borntraeger VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); 52e28acfeaSChristian Borntraeger vcpu->stat.diagnose_44++; 538733ac36SChristian Borntraeger kvm_vcpu_on_spin(vcpu); 54e28acfeaSChristian Borntraeger return 0; 55e28acfeaSChristian Borntraeger } 56e28acfeaSChristian Borntraeger 5741628d33SKonstantin Weitz static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu) 5841628d33SKonstantin Weitz { 5941628d33SKonstantin Weitz struct kvm *kvm = vcpu->kvm; 6041628d33SKonstantin Weitz struct kvm_vcpu *tcpu; 6141628d33SKonstantin Weitz int tid; 6241628d33SKonstantin Weitz int i; 6341628d33SKonstantin Weitz 6441628d33SKonstantin Weitz tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; 6541628d33SKonstantin Weitz vcpu->stat.diagnose_9c++; 6641628d33SKonstantin Weitz VCPU_EVENT(vcpu, 5, "diag time slice end directed to %d", tid); 6741628d33SKonstantin Weitz 6841628d33SKonstantin Weitz if (tid == vcpu->vcpu_id) 6941628d33SKonstantin Weitz return 0; 7041628d33SKonstantin Weitz 7141628d33SKonstantin Weitz kvm_for_each_vcpu(i, tcpu, kvm) 7241628d33SKonstantin Weitz if (tcpu->vcpu_id == tid) { 7341628d33SKonstantin Weitz kvm_vcpu_yield_to(tcpu); 7441628d33SKonstantin Weitz break; 7541628d33SKonstantin Weitz } 7641628d33SKonstantin Weitz 7741628d33SKonstantin Weitz return 0; 7841628d33SKonstantin Weitz } 7941628d33SKonstantin Weitz 80e28acfeaSChristian Borntraeger static int __diag_ipl_functions(struct kvm_vcpu *vcpu) 81e28acfeaSChristian Borntraeger { 82e28acfeaSChristian Borntraeger unsigned int reg = vcpu->arch.sie_block->ipa & 0xf; 835a32c1afSChristian Borntraeger unsigned long subcode = vcpu->run->s.regs.gprs[reg] & 0xffff; 84e28acfeaSChristian Borntraeger 85e28acfeaSChristian Borntraeger VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); 86e28acfeaSChristian Borntraeger switch (subcode) { 87e28acfeaSChristian Borntraeger case 3: 88e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; 89e28acfeaSChristian Borntraeger break; 90e28acfeaSChristian Borntraeger case 4: 91e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags = 0; 92e28acfeaSChristian Borntraeger break; 93e28acfeaSChristian Borntraeger default: 94b8e660b8SHeiko Carstens return -EOPNOTSUPP; 95e28acfeaSChristian Borntraeger } 96e28acfeaSChristian Borntraeger 979e6dabefSCornelia Huck atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); 98e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; 99e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; 100e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; 101e28acfeaSChristian Borntraeger vcpu->run->exit_reason = KVM_EXIT_S390_RESET; 10233e19115SHeiko Carstens VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx", 103e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags); 104ade38c31SCornelia Huck trace_kvm_s390_request_resets(vcpu->run->s390_reset_flags); 105e28acfeaSChristian Borntraeger return -EREMOTE; 106e28acfeaSChristian Borntraeger } 107e28acfeaSChristian Borntraeger 10810ccaa1eSCornelia Huck static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu) 10910ccaa1eSCornelia Huck { 11010ccaa1eSCornelia Huck int ret, idx; 11110ccaa1eSCornelia Huck 11210ccaa1eSCornelia Huck /* No virtio-ccw notification? Get out quickly. */ 11310ccaa1eSCornelia Huck if (!vcpu->kvm->arch.css_support || 11410ccaa1eSCornelia Huck (vcpu->run->s.regs.gprs[1] != KVM_S390_VIRTIO_CCW_NOTIFY)) 11510ccaa1eSCornelia Huck return -EOPNOTSUPP; 11610ccaa1eSCornelia Huck 11710ccaa1eSCornelia Huck idx = srcu_read_lock(&vcpu->kvm->srcu); 11810ccaa1eSCornelia Huck /* 11910ccaa1eSCornelia Huck * The layout is as follows: 12010ccaa1eSCornelia Huck * - gpr 2 contains the subchannel id (passed as addr) 12110ccaa1eSCornelia Huck * - gpr 3 contains the virtqueue index (passed as datamatch) 12210ccaa1eSCornelia Huck */ 12310ccaa1eSCornelia Huck ret = kvm_io_bus_write(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS, 12410ccaa1eSCornelia Huck vcpu->run->s.regs.gprs[2], 12510ccaa1eSCornelia Huck 8, &vcpu->run->s.regs.gprs[3]); 12610ccaa1eSCornelia Huck srcu_read_unlock(&vcpu->kvm->srcu, idx); 12710ccaa1eSCornelia Huck /* kvm_io_bus_write returns -EOPNOTSUPP if it found no match. */ 12810ccaa1eSCornelia Huck return ret < 0 ? ret : 0; 12910ccaa1eSCornelia Huck } 13010ccaa1eSCornelia Huck 131e28acfeaSChristian Borntraeger int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) 132e28acfeaSChristian Borntraeger { 133e28acfeaSChristian Borntraeger int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; 134e28acfeaSChristian Borntraeger 135*93e1750fSThomas Huth if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 136*93e1750fSThomas Huth return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); 137*93e1750fSThomas Huth 1385786fffaSCornelia Huck trace_kvm_s390_handle_diag(vcpu, code); 139e28acfeaSChristian Borntraeger switch (code) { 140388186bcSChristian Borntraeger case 0x10: 141388186bcSChristian Borntraeger return diag_release_pages(vcpu); 142e28acfeaSChristian Borntraeger case 0x44: 143e28acfeaSChristian Borntraeger return __diag_time_slice_end(vcpu); 14441628d33SKonstantin Weitz case 0x9c: 14541628d33SKonstantin Weitz return __diag_time_slice_end_directed(vcpu); 146e28acfeaSChristian Borntraeger case 0x308: 147e28acfeaSChristian Borntraeger return __diag_ipl_functions(vcpu); 14810ccaa1eSCornelia Huck case 0x500: 14910ccaa1eSCornelia Huck return __diag_virtio_hypercall(vcpu); 150e28acfeaSChristian Borntraeger default: 151b8e660b8SHeiko Carstens return -EOPNOTSUPP; 152e28acfeaSChristian Borntraeger } 153e28acfeaSChristian Borntraeger } 154