1 /* 2 * sigp.c - handlinge interprocessor communication 3 * 4 * Copyright IBM Corp. 2008 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License (version 2 only) 8 * as published by the Free Software Foundation. 9 * 10 * Author(s): Carsten Otte <cotte@de.ibm.com> 11 * Christian Borntraeger <borntraeger@de.ibm.com> 12 */ 13 14 #include <linux/kvm.h> 15 #include <linux/kvm_host.h> 16 #include "gaccess.h" 17 #include "kvm-s390.h" 18 19 /* sigp order codes */ 20 #define SIGP_SENSE 0x01 21 #define SIGP_EXTERNAL_CALL 0x02 22 #define SIGP_EMERGENCY 0x03 23 #define SIGP_START 0x04 24 #define SIGP_STOP 0x05 25 #define SIGP_RESTART 0x06 26 #define SIGP_STOP_STORE_STATUS 0x09 27 #define SIGP_INITIAL_CPU_RESET 0x0b 28 #define SIGP_CPU_RESET 0x0c 29 #define SIGP_SET_PREFIX 0x0d 30 #define SIGP_STORE_STATUS_ADDR 0x0e 31 #define SIGP_SET_ARCH 0x12 32 33 /* cpu status bits */ 34 #define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL 35 #define SIGP_STAT_INCORRECT_STATE 0x00000200UL 36 #define SIGP_STAT_INVALID_PARAMETER 0x00000100UL 37 #define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL 38 #define SIGP_STAT_STOPPED 0x00000040UL 39 #define SIGP_STAT_OPERATOR_INTERV 0x00000020UL 40 #define SIGP_STAT_CHECK_STOP 0x00000010UL 41 #define SIGP_STAT_INOPERATIVE 0x00000004UL 42 #define SIGP_STAT_INVALID_ORDER 0x00000002UL 43 #define SIGP_STAT_RECEIVER_CHECK 0x00000001UL 44 45 46 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, 47 unsigned long *reg) 48 { 49 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 50 int rc; 51 52 if (cpu_addr >= KVM_MAX_VCPUS) 53 return 3; /* not operational */ 54 55 spin_lock_bh(&fi->lock); 56 if (fi->local_int[cpu_addr] == NULL) 57 rc = 3; /* not operational */ 58 else if (atomic_read(fi->local_int[cpu_addr]->cpuflags) 59 & CPUSTAT_RUNNING) { 60 *reg &= 0xffffffff00000000UL; 61 rc = 1; /* status stored */ 62 } else { 63 *reg &= 0xffffffff00000000UL; 64 *reg |= SIGP_STAT_STOPPED; 65 rc = 1; /* status stored */ 66 } 67 spin_unlock_bh(&fi->lock); 68 69 VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc); 70 return rc; 71 } 72 73 static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) 74 { 75 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 76 struct kvm_s390_local_interrupt *li; 77 struct kvm_s390_interrupt_info *inti; 78 int rc; 79 80 if (cpu_addr >= KVM_MAX_VCPUS) 81 return 3; /* not operational */ 82 83 inti = kzalloc(sizeof(*inti), GFP_KERNEL); 84 if (!inti) 85 return -ENOMEM; 86 87 inti->type = KVM_S390_INT_EMERGENCY; 88 89 spin_lock_bh(&fi->lock); 90 li = fi->local_int[cpu_addr]; 91 if (li == NULL) { 92 rc = 3; /* not operational */ 93 kfree(inti); 94 goto unlock; 95 } 96 spin_lock_bh(&li->lock); 97 list_add_tail(&inti->list, &li->list); 98 atomic_set(&li->active, 1); 99 atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); 100 if (waitqueue_active(&li->wq)) 101 wake_up_interruptible(&li->wq); 102 spin_unlock_bh(&li->lock); 103 rc = 0; /* order accepted */ 104 unlock: 105 spin_unlock_bh(&fi->lock); 106 VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); 107 return rc; 108 } 109 110 static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int store) 111 { 112 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 113 struct kvm_s390_local_interrupt *li; 114 struct kvm_s390_interrupt_info *inti; 115 int rc; 116 117 if (cpu_addr >= KVM_MAX_VCPUS) 118 return 3; /* not operational */ 119 120 inti = kzalloc(sizeof(*inti), GFP_KERNEL); 121 if (!inti) 122 return -ENOMEM; 123 124 inti->type = KVM_S390_SIGP_STOP; 125 126 spin_lock_bh(&fi->lock); 127 li = fi->local_int[cpu_addr]; 128 if (li == NULL) { 129 rc = 3; /* not operational */ 130 kfree(inti); 131 goto unlock; 132 } 133 spin_lock_bh(&li->lock); 134 list_add_tail(&inti->list, &li->list); 135 atomic_set(&li->active, 1); 136 atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); 137 if (store) 138 li->action_bits |= ACTION_STORE_ON_STOP; 139 li->action_bits |= ACTION_STOP_ON_STOP; 140 if (waitqueue_active(&li->wq)) 141 wake_up_interruptible(&li->wq); 142 spin_unlock_bh(&li->lock); 143 rc = 0; /* order accepted */ 144 unlock: 145 spin_unlock_bh(&fi->lock); 146 VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr); 147 return rc; 148 } 149 150 static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) 151 { 152 int rc; 153 154 switch (parameter & 0xff) { 155 case 0: 156 rc = 3; /* not operational */ 157 break; 158 case 1: 159 case 2: 160 rc = 0; /* order accepted */ 161 break; 162 default: 163 rc = -ENOTSUPP; 164 } 165 return rc; 166 } 167 168 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, 169 unsigned long *reg) 170 { 171 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 172 struct kvm_s390_local_interrupt *li; 173 struct kvm_s390_interrupt_info *inti; 174 int rc; 175 u8 tmp; 176 177 /* make sure that the new value is valid memory */ 178 address = address & 0x7fffe000u; 179 if ((copy_from_guest(vcpu, &tmp, 180 (u64) (address + vcpu->kvm->arch.guest_origin) , 1)) || 181 (copy_from_guest(vcpu, &tmp, (u64) (address + 182 vcpu->kvm->arch.guest_origin + PAGE_SIZE), 1))) { 183 *reg |= SIGP_STAT_INVALID_PARAMETER; 184 return 1; /* invalid parameter */ 185 } 186 187 inti = kzalloc(sizeof(*inti), GFP_KERNEL); 188 if (!inti) 189 return 2; /* busy */ 190 191 spin_lock_bh(&fi->lock); 192 li = fi->local_int[cpu_addr]; 193 194 if ((cpu_addr >= KVM_MAX_VCPUS) || (li == NULL)) { 195 rc = 1; /* incorrect state */ 196 *reg &= SIGP_STAT_INCORRECT_STATE; 197 kfree(inti); 198 goto out_fi; 199 } 200 201 spin_lock_bh(&li->lock); 202 /* cpu must be in stopped state */ 203 if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) { 204 rc = 1; /* incorrect state */ 205 *reg &= SIGP_STAT_INCORRECT_STATE; 206 kfree(inti); 207 goto out_li; 208 } 209 210 inti->type = KVM_S390_SIGP_SET_PREFIX; 211 inti->prefix.address = address; 212 213 list_add_tail(&inti->list, &li->list); 214 atomic_set(&li->active, 1); 215 if (waitqueue_active(&li->wq)) 216 wake_up_interruptible(&li->wq); 217 rc = 0; /* order accepted */ 218 219 VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); 220 out_li: 221 spin_unlock_bh(&li->lock); 222 out_fi: 223 spin_unlock_bh(&fi->lock); 224 return rc; 225 } 226 227 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) 228 { 229 int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; 230 int r3 = vcpu->arch.sie_block->ipa & 0x000f; 231 int base2 = vcpu->arch.sie_block->ipb >> 28; 232 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 233 u32 parameter; 234 u16 cpu_addr = vcpu->arch.guest_gprs[r3]; 235 u8 order_code; 236 int rc; 237 238 /* sigp in userspace can exit */ 239 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 240 return kvm_s390_inject_program_int(vcpu, 241 PGM_PRIVILEGED_OPERATION); 242 243 order_code = disp2; 244 if (base2) 245 order_code += vcpu->arch.guest_gprs[base2]; 246 247 if (r1 % 2) 248 parameter = vcpu->arch.guest_gprs[r1]; 249 else 250 parameter = vcpu->arch.guest_gprs[r1 + 1]; 251 252 switch (order_code) { 253 case SIGP_SENSE: 254 vcpu->stat.instruction_sigp_sense++; 255 rc = __sigp_sense(vcpu, cpu_addr, 256 &vcpu->arch.guest_gprs[r1]); 257 break; 258 case SIGP_EMERGENCY: 259 vcpu->stat.instruction_sigp_emergency++; 260 rc = __sigp_emergency(vcpu, cpu_addr); 261 break; 262 case SIGP_STOP: 263 vcpu->stat.instruction_sigp_stop++; 264 rc = __sigp_stop(vcpu, cpu_addr, 0); 265 break; 266 case SIGP_STOP_STORE_STATUS: 267 vcpu->stat.instruction_sigp_stop++; 268 rc = __sigp_stop(vcpu, cpu_addr, 1); 269 break; 270 case SIGP_SET_ARCH: 271 vcpu->stat.instruction_sigp_arch++; 272 rc = __sigp_set_arch(vcpu, parameter); 273 break; 274 case SIGP_SET_PREFIX: 275 vcpu->stat.instruction_sigp_prefix++; 276 rc = __sigp_set_prefix(vcpu, cpu_addr, parameter, 277 &vcpu->arch.guest_gprs[r1]); 278 break; 279 case SIGP_RESTART: 280 vcpu->stat.instruction_sigp_restart++; 281 /* user space must know about restart */ 282 default: 283 return -ENOTSUPP; 284 } 285 286 if (rc < 0) 287 return rc; 288 289 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 290 vcpu->arch.sie_block->gpsw.mask |= (rc & 3ul) << 44; 291 return 0; 292 } 293