1e28acfeaSChristian Borntraeger /* 2e28acfeaSChristian Borntraeger * diag.c - 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> 16e28acfeaSChristian Borntraeger #include "kvm-s390.h" 17e28acfeaSChristian Borntraeger 18388186bcSChristian Borntraeger static int diag_release_pages(struct kvm_vcpu *vcpu) 19388186bcSChristian Borntraeger { 20388186bcSChristian Borntraeger unsigned long start, end; 21388186bcSChristian Borntraeger unsigned long prefix = vcpu->arch.sie_block->prefix; 22388186bcSChristian Borntraeger 235a32c1afSChristian Borntraeger start = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; 245a32c1afSChristian Borntraeger end = vcpu->run->s.regs.gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096; 25388186bcSChristian Borntraeger 26388186bcSChristian Borntraeger if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end 27388186bcSChristian Borntraeger || start < 2 * PAGE_SIZE) 28388186bcSChristian Borntraeger return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 29388186bcSChristian Borntraeger 30388186bcSChristian Borntraeger VCPU_EVENT(vcpu, 5, "diag release pages %lX %lX", start, end); 31388186bcSChristian Borntraeger vcpu->stat.diagnose_10++; 32388186bcSChristian Borntraeger 33388186bcSChristian Borntraeger /* we checked for start > end above */ 34388186bcSChristian Borntraeger if (end < prefix || start >= prefix + 2 * PAGE_SIZE) { 35388186bcSChristian Borntraeger gmap_discard(start, end, vcpu->arch.gmap); 36388186bcSChristian Borntraeger } else { 37388186bcSChristian Borntraeger if (start < prefix) 38388186bcSChristian Borntraeger gmap_discard(start, prefix, vcpu->arch.gmap); 39388186bcSChristian Borntraeger if (end >= prefix) 40388186bcSChristian Borntraeger gmap_discard(prefix + 2 * PAGE_SIZE, 41388186bcSChristian Borntraeger end, vcpu->arch.gmap); 42388186bcSChristian Borntraeger } 43388186bcSChristian Borntraeger return 0; 44388186bcSChristian Borntraeger } 45388186bcSChristian Borntraeger 46e28acfeaSChristian Borntraeger static int __diag_time_slice_end(struct kvm_vcpu *vcpu) 47e28acfeaSChristian Borntraeger { 48e28acfeaSChristian Borntraeger VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); 49e28acfeaSChristian Borntraeger vcpu->stat.diagnose_44++; 50e28acfeaSChristian Borntraeger vcpu_put(vcpu); 51b8cee18cSChristian Borntraeger yield(); 52e28acfeaSChristian Borntraeger vcpu_load(vcpu); 53e28acfeaSChristian Borntraeger return 0; 54e28acfeaSChristian Borntraeger } 55e28acfeaSChristian Borntraeger 56*41628d33SKonstantin Weitz static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu) 57*41628d33SKonstantin Weitz { 58*41628d33SKonstantin Weitz struct kvm *kvm = vcpu->kvm; 59*41628d33SKonstantin Weitz struct kvm_vcpu *tcpu; 60*41628d33SKonstantin Weitz int tid; 61*41628d33SKonstantin Weitz int i; 62*41628d33SKonstantin Weitz 63*41628d33SKonstantin Weitz tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4]; 64*41628d33SKonstantin Weitz vcpu->stat.diagnose_9c++; 65*41628d33SKonstantin Weitz VCPU_EVENT(vcpu, 5, "diag time slice end directed to %d", tid); 66*41628d33SKonstantin Weitz 67*41628d33SKonstantin Weitz if (tid == vcpu->vcpu_id) 68*41628d33SKonstantin Weitz return 0; 69*41628d33SKonstantin Weitz 70*41628d33SKonstantin Weitz kvm_for_each_vcpu(i, tcpu, kvm) 71*41628d33SKonstantin Weitz if (tcpu->vcpu_id == tid) { 72*41628d33SKonstantin Weitz kvm_vcpu_yield_to(tcpu); 73*41628d33SKonstantin Weitz break; 74*41628d33SKonstantin Weitz } 75*41628d33SKonstantin Weitz 76*41628d33SKonstantin Weitz return 0; 77*41628d33SKonstantin Weitz } 78*41628d33SKonstantin Weitz 79e28acfeaSChristian Borntraeger static int __diag_ipl_functions(struct kvm_vcpu *vcpu) 80e28acfeaSChristian Borntraeger { 81e28acfeaSChristian Borntraeger unsigned int reg = vcpu->arch.sie_block->ipa & 0xf; 825a32c1afSChristian Borntraeger unsigned long subcode = vcpu->run->s.regs.gprs[reg] & 0xffff; 83e28acfeaSChristian Borntraeger 84e28acfeaSChristian Borntraeger VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode); 85e28acfeaSChristian Borntraeger switch (subcode) { 86e28acfeaSChristian Borntraeger case 3: 87e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; 88e28acfeaSChristian Borntraeger break; 89e28acfeaSChristian Borntraeger case 4: 90e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags = 0; 91e28acfeaSChristian Borntraeger break; 92e28acfeaSChristian Borntraeger default: 93b8e660b8SHeiko Carstens return -EOPNOTSUPP; 94e28acfeaSChristian Borntraeger } 95e28acfeaSChristian Borntraeger 969e6dabefSCornelia Huck atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); 97e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; 98e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; 99e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; 100e28acfeaSChristian Borntraeger vcpu->run->exit_reason = KVM_EXIT_S390_RESET; 10133e19115SHeiko Carstens VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx", 102e28acfeaSChristian Borntraeger vcpu->run->s390_reset_flags); 103e28acfeaSChristian Borntraeger return -EREMOTE; 104e28acfeaSChristian Borntraeger } 105e28acfeaSChristian Borntraeger 106e28acfeaSChristian Borntraeger int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) 107e28acfeaSChristian Borntraeger { 108e28acfeaSChristian Borntraeger int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; 109e28acfeaSChristian Borntraeger 110e28acfeaSChristian Borntraeger switch (code) { 111388186bcSChristian Borntraeger case 0x10: 112388186bcSChristian Borntraeger return diag_release_pages(vcpu); 113e28acfeaSChristian Borntraeger case 0x44: 114e28acfeaSChristian Borntraeger return __diag_time_slice_end(vcpu); 115*41628d33SKonstantin Weitz case 0x9c: 116*41628d33SKonstantin Weitz return __diag_time_slice_end_directed(vcpu); 117e28acfeaSChristian Borntraeger case 0x308: 118e28acfeaSChristian Borntraeger return __diag_ipl_functions(vcpu); 119e28acfeaSChristian Borntraeger default: 120b8e660b8SHeiko Carstens return -EOPNOTSUPP; 121e28acfeaSChristian Borntraeger } 122e28acfeaSChristian Borntraeger } 123