1 /* 2 * priv.c - handling privileged instructions 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/errno.h> 16 #include <asm/current.h> 17 #include <asm/debug.h> 18 #include <asm/ebcdic.h> 19 #include <asm/sysinfo.h> 20 #include "gaccess.h" 21 #include "kvm-s390.h" 22 23 static int handle_set_prefix(struct kvm_vcpu *vcpu) 24 { 25 int base2 = vcpu->arch.sie_block->ipb >> 28; 26 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 27 u64 operand2; 28 u32 address = 0; 29 u8 tmp; 30 31 vcpu->stat.instruction_spx++; 32 33 operand2 = disp2; 34 if (base2) 35 operand2 += vcpu->arch.guest_gprs[base2]; 36 37 /* must be word boundary */ 38 if (operand2 & 3) { 39 kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 40 goto out; 41 } 42 43 /* get the value */ 44 if (get_guest_u32(vcpu, operand2, &address)) { 45 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 46 goto out; 47 } 48 49 address = address & 0x7fffe000u; 50 51 /* make sure that the new value is valid memory */ 52 if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || 53 (copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1))) { 54 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 55 goto out; 56 } 57 58 vcpu->arch.sie_block->prefix = address; 59 vcpu->arch.sie_block->ihcpu = 0xffff; 60 61 VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); 62 out: 63 return 0; 64 } 65 66 static int handle_store_prefix(struct kvm_vcpu *vcpu) 67 { 68 int base2 = vcpu->arch.sie_block->ipb >> 28; 69 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 70 u64 operand2; 71 u32 address; 72 73 vcpu->stat.instruction_stpx++; 74 operand2 = disp2; 75 if (base2) 76 operand2 += vcpu->arch.guest_gprs[base2]; 77 78 /* must be word boundary */ 79 if (operand2 & 3) { 80 kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 81 goto out; 82 } 83 84 address = vcpu->arch.sie_block->prefix; 85 address = address & 0x7fffe000u; 86 87 /* get the value */ 88 if (put_guest_u32(vcpu, operand2, address)) { 89 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 90 goto out; 91 } 92 93 VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); 94 out: 95 return 0; 96 } 97 98 static int handle_store_cpu_address(struct kvm_vcpu *vcpu) 99 { 100 int base2 = vcpu->arch.sie_block->ipb >> 28; 101 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 102 u64 useraddr; 103 int rc; 104 105 vcpu->stat.instruction_stap++; 106 useraddr = disp2; 107 if (base2) 108 useraddr += vcpu->arch.guest_gprs[base2]; 109 110 if (useraddr & 1) { 111 kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 112 goto out; 113 } 114 115 rc = put_guest_u16(vcpu, useraddr, vcpu->vcpu_id); 116 if (rc == -EFAULT) { 117 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 118 goto out; 119 } 120 121 VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); 122 out: 123 return 0; 124 } 125 126 static int handle_skey(struct kvm_vcpu *vcpu) 127 { 128 vcpu->stat.instruction_storage_key++; 129 vcpu->arch.sie_block->gpsw.addr -= 4; 130 VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation"); 131 return 0; 132 } 133 134 static int handle_stsch(struct kvm_vcpu *vcpu) 135 { 136 vcpu->stat.instruction_stsch++; 137 VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3"); 138 /* condition code 3 */ 139 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 140 vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; 141 return 0; 142 } 143 144 static int handle_chsc(struct kvm_vcpu *vcpu) 145 { 146 vcpu->stat.instruction_chsc++; 147 VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3"); 148 /* condition code 3 */ 149 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 150 vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; 151 return 0; 152 } 153 154 static int handle_stfl(struct kvm_vcpu *vcpu) 155 { 156 unsigned int facility_list = stfl(); 157 int rc; 158 159 vcpu->stat.instruction_stfl++; 160 /* only pass the facility bits, which we can handle */ 161 facility_list &= 0xff00fff3; 162 163 rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), 164 &facility_list, sizeof(facility_list)); 165 if (rc == -EFAULT) 166 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 167 else 168 VCPU_EVENT(vcpu, 5, "store facility list value %x", 169 facility_list); 170 return 0; 171 } 172 173 static int handle_stidp(struct kvm_vcpu *vcpu) 174 { 175 int base2 = vcpu->arch.sie_block->ipb >> 28; 176 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 177 u64 operand2; 178 int rc; 179 180 vcpu->stat.instruction_stidp++; 181 operand2 = disp2; 182 if (base2) 183 operand2 += vcpu->arch.guest_gprs[base2]; 184 185 if (operand2 & 7) { 186 kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 187 goto out; 188 } 189 190 rc = put_guest_u64(vcpu, operand2, vcpu->arch.stidp_data); 191 if (rc == -EFAULT) { 192 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 193 goto out; 194 } 195 196 VCPU_EVENT(vcpu, 5, "%s", "store cpu id"); 197 out: 198 return 0; 199 } 200 201 static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem) 202 { 203 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; 204 int cpus = 0; 205 int n; 206 207 spin_lock(&fi->lock); 208 for (n = 0; n < KVM_MAX_VCPUS; n++) 209 if (fi->local_int[n]) 210 cpus++; 211 spin_unlock(&fi->lock); 212 213 /* deal with other level 3 hypervisors */ 214 if (stsi(mem, 3, 2, 2) == -ENOSYS) 215 mem->count = 0; 216 if (mem->count < 8) 217 mem->count++; 218 for (n = mem->count - 1; n > 0 ; n--) 219 memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0])); 220 221 mem->vm[0].cpus_total = cpus; 222 mem->vm[0].cpus_configured = cpus; 223 mem->vm[0].cpus_standby = 0; 224 mem->vm[0].cpus_reserved = 0; 225 mem->vm[0].caf = 1000; 226 memcpy(mem->vm[0].name, "KVMguest", 8); 227 ASCEBC(mem->vm[0].name, 8); 228 memcpy(mem->vm[0].cpi, "KVM/Linux ", 16); 229 ASCEBC(mem->vm[0].cpi, 16); 230 } 231 232 static int handle_stsi(struct kvm_vcpu *vcpu) 233 { 234 int fc = (vcpu->arch.guest_gprs[0] & 0xf0000000) >> 28; 235 int sel1 = vcpu->arch.guest_gprs[0] & 0xff; 236 int sel2 = vcpu->arch.guest_gprs[1] & 0xffff; 237 int base2 = vcpu->arch.sie_block->ipb >> 28; 238 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 239 u64 operand2; 240 unsigned long mem; 241 242 vcpu->stat.instruction_stsi++; 243 VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2); 244 245 operand2 = disp2; 246 if (base2) 247 operand2 += vcpu->arch.guest_gprs[base2]; 248 249 if (operand2 & 0xfff && fc > 0) 250 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); 251 252 switch (fc) { 253 case 0: 254 vcpu->arch.guest_gprs[0] = 3 << 28; 255 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 256 return 0; 257 case 1: /* same handling for 1 and 2 */ 258 case 2: 259 mem = get_zeroed_page(GFP_KERNEL); 260 if (!mem) 261 goto out_fail; 262 if (stsi((void *) mem, fc, sel1, sel2) == -ENOSYS) 263 goto out_mem; 264 break; 265 case 3: 266 if (sel1 != 2 || sel2 != 2) 267 goto out_fail; 268 mem = get_zeroed_page(GFP_KERNEL); 269 if (!mem) 270 goto out_fail; 271 handle_stsi_3_2_2(vcpu, (void *) mem); 272 break; 273 default: 274 goto out_fail; 275 } 276 277 if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) { 278 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 279 goto out_mem; 280 } 281 free_page(mem); 282 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 283 vcpu->arch.guest_gprs[0] = 0; 284 return 0; 285 out_mem: 286 free_page(mem); 287 out_fail: 288 /* condition code 3 */ 289 vcpu->arch.sie_block->gpsw.mask |= 3ul << 44; 290 return 0; 291 } 292 293 static intercept_handler_t priv_handlers[256] = { 294 [0x02] = handle_stidp, 295 [0x10] = handle_set_prefix, 296 [0x11] = handle_store_prefix, 297 [0x12] = handle_store_cpu_address, 298 [0x29] = handle_skey, 299 [0x2a] = handle_skey, 300 [0x2b] = handle_skey, 301 [0x34] = handle_stsch, 302 [0x5f] = handle_chsc, 303 [0x7d] = handle_stsi, 304 [0xb1] = handle_stfl, 305 }; 306 307 int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) 308 { 309 intercept_handler_t handler; 310 311 /* 312 * a lot of B2 instructions are priviledged. We first check for 313 * the priviledges ones, that we can handle in the kernel. If the 314 * kernel can handle this instruction, we check for the problem 315 * state bit and (a) handle the instruction or (b) send a code 2 316 * program check. 317 * Anything else goes to userspace.*/ 318 handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; 319 if (handler) { 320 if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) 321 return kvm_s390_inject_program_int(vcpu, 322 PGM_PRIVILEGED_OPERATION); 323 else 324 return handler(vcpu); 325 } 326 return -ENOTSUPP; 327 } 328