1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright IBM Corp. 2007 5 * Copyright 2011 Freescale Semiconductor, Inc. 6 * 7 * Authors: Hollis Blanchard <hollisb@us.ibm.com> 8 */ 9 10 #include <linux/jiffies.h> 11 #include <linux/hrtimer.h> 12 #include <linux/types.h> 13 #include <linux/string.h> 14 #include <linux/kvm_host.h> 15 #include <linux/clockchips.h> 16 17 #include <asm/reg.h> 18 #include <asm/time.h> 19 #include <asm/byteorder.h> 20 #include <asm/kvm_ppc.h> 21 #include <asm/disassemble.h> 22 #include <asm/ppc-opcode.h> 23 #include <asm/sstep.h> 24 #include "timing.h" 25 #include "trace.h" 26 27 #ifdef CONFIG_PPC_FPU 28 static bool kvmppc_check_fp_disabled(struct kvm_vcpu *vcpu) 29 { 30 if (!(kvmppc_get_msr(vcpu) & MSR_FP)) { 31 kvmppc_core_queue_fpunavail(vcpu); 32 return true; 33 } 34 35 return false; 36 } 37 #endif /* CONFIG_PPC_FPU */ 38 39 #ifdef CONFIG_VSX 40 static bool kvmppc_check_vsx_disabled(struct kvm_vcpu *vcpu) 41 { 42 if (!(kvmppc_get_msr(vcpu) & MSR_VSX)) { 43 kvmppc_core_queue_vsx_unavail(vcpu); 44 return true; 45 } 46 47 return false; 48 } 49 #endif /* CONFIG_VSX */ 50 51 #ifdef CONFIG_ALTIVEC 52 static bool kvmppc_check_altivec_disabled(struct kvm_vcpu *vcpu) 53 { 54 if (!(kvmppc_get_msr(vcpu) & MSR_VEC)) { 55 kvmppc_core_queue_vec_unavail(vcpu); 56 return true; 57 } 58 59 return false; 60 } 61 #endif /* CONFIG_ALTIVEC */ 62 63 /* 64 * XXX to do: 65 * lfiwax, lfiwzx 66 * vector loads and stores 67 * 68 * Instructions that trap when used on cache-inhibited mappings 69 * are not emulated here: multiple and string instructions, 70 * lq/stq, and the load-reserve/store-conditional instructions. 71 */ 72 int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) 73 { 74 u32 inst; 75 enum emulation_result emulated = EMULATE_FAIL; 76 int advance = 1; 77 struct instruction_op op; 78 79 /* this default type might be overwritten by subcategories */ 80 kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); 81 82 emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst); 83 if (emulated != EMULATE_DONE) 84 return emulated; 85 86 vcpu->arch.mmio_vsx_copy_nums = 0; 87 vcpu->arch.mmio_vsx_offset = 0; 88 vcpu->arch.mmio_copy_type = KVMPPC_VSX_COPY_NONE; 89 vcpu->arch.mmio_sp64_extend = 0; 90 vcpu->arch.mmio_sign_extend = 0; 91 vcpu->arch.mmio_vmx_copy_nums = 0; 92 vcpu->arch.mmio_vmx_offset = 0; 93 vcpu->arch.mmio_host_swabbed = 0; 94 95 emulated = EMULATE_FAIL; 96 vcpu->arch.regs.msr = vcpu->arch.shared->msr; 97 if (analyse_instr(&op, &vcpu->arch.regs, ppc_inst(inst)) == 0) { 98 int type = op.type & INSTR_TYPE_MASK; 99 int size = GETSIZE(op.type); 100 101 switch (type) { 102 case LOAD: { 103 int instr_byte_swap = op.type & BYTEREV; 104 105 if (op.type & SIGNEXT) 106 emulated = kvmppc_handle_loads(vcpu, 107 op.reg, size, !instr_byte_swap); 108 else 109 emulated = kvmppc_handle_load(vcpu, 110 op.reg, size, !instr_byte_swap); 111 112 if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) 113 kvmppc_set_gpr(vcpu, op.update_reg, op.ea); 114 115 break; 116 } 117 #ifdef CONFIG_PPC_FPU 118 case LOAD_FP: 119 if (kvmppc_check_fp_disabled(vcpu)) 120 return EMULATE_DONE; 121 122 if (op.type & FPCONV) 123 vcpu->arch.mmio_sp64_extend = 1; 124 125 if (op.type & SIGNEXT) 126 emulated = kvmppc_handle_loads(vcpu, 127 KVM_MMIO_REG_FPR|op.reg, size, 1); 128 else 129 emulated = kvmppc_handle_load(vcpu, 130 KVM_MMIO_REG_FPR|op.reg, size, 1); 131 132 if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) 133 kvmppc_set_gpr(vcpu, op.update_reg, op.ea); 134 135 break; 136 #endif 137 #ifdef CONFIG_ALTIVEC 138 case LOAD_VMX: 139 if (kvmppc_check_altivec_disabled(vcpu)) 140 return EMULATE_DONE; 141 142 /* Hardware enforces alignment of VMX accesses */ 143 vcpu->arch.vaddr_accessed &= ~((unsigned long)size - 1); 144 vcpu->arch.paddr_accessed &= ~((unsigned long)size - 1); 145 146 if (size == 16) { /* lvx */ 147 vcpu->arch.mmio_copy_type = 148 KVMPPC_VMX_COPY_DWORD; 149 } else if (size == 4) { /* lvewx */ 150 vcpu->arch.mmio_copy_type = 151 KVMPPC_VMX_COPY_WORD; 152 } else if (size == 2) { /* lvehx */ 153 vcpu->arch.mmio_copy_type = 154 KVMPPC_VMX_COPY_HWORD; 155 } else if (size == 1) { /* lvebx */ 156 vcpu->arch.mmio_copy_type = 157 KVMPPC_VMX_COPY_BYTE; 158 } else 159 break; 160 161 vcpu->arch.mmio_vmx_offset = 162 (vcpu->arch.vaddr_accessed & 0xf)/size; 163 164 if (size == 16) { 165 vcpu->arch.mmio_vmx_copy_nums = 2; 166 emulated = kvmppc_handle_vmx_load(vcpu, 167 KVM_MMIO_REG_VMX|op.reg, 168 8, 1); 169 } else { 170 vcpu->arch.mmio_vmx_copy_nums = 1; 171 emulated = kvmppc_handle_vmx_load(vcpu, 172 KVM_MMIO_REG_VMX|op.reg, 173 size, 1); 174 } 175 break; 176 #endif 177 #ifdef CONFIG_VSX 178 case LOAD_VSX: { 179 int io_size_each; 180 181 if (op.vsx_flags & VSX_CHECK_VEC) { 182 if (kvmppc_check_altivec_disabled(vcpu)) 183 return EMULATE_DONE; 184 } else { 185 if (kvmppc_check_vsx_disabled(vcpu)) 186 return EMULATE_DONE; 187 } 188 189 if (op.vsx_flags & VSX_FPCONV) 190 vcpu->arch.mmio_sp64_extend = 1; 191 192 if (op.element_size == 8) { 193 if (op.vsx_flags & VSX_SPLAT) 194 vcpu->arch.mmio_copy_type = 195 KVMPPC_VSX_COPY_DWORD_LOAD_DUMP; 196 else 197 vcpu->arch.mmio_copy_type = 198 KVMPPC_VSX_COPY_DWORD; 199 } else if (op.element_size == 4) { 200 if (op.vsx_flags & VSX_SPLAT) 201 vcpu->arch.mmio_copy_type = 202 KVMPPC_VSX_COPY_WORD_LOAD_DUMP; 203 else 204 vcpu->arch.mmio_copy_type = 205 KVMPPC_VSX_COPY_WORD; 206 } else 207 break; 208 209 if (size < op.element_size) { 210 /* precision convert case: lxsspx, etc */ 211 vcpu->arch.mmio_vsx_copy_nums = 1; 212 io_size_each = size; 213 } else { /* lxvw4x, lxvd2x, etc */ 214 vcpu->arch.mmio_vsx_copy_nums = 215 size/op.element_size; 216 io_size_each = op.element_size; 217 } 218 219 emulated = kvmppc_handle_vsx_load(vcpu, 220 KVM_MMIO_REG_VSX|op.reg, io_size_each, 221 1, op.type & SIGNEXT); 222 break; 223 } 224 #endif 225 case STORE: 226 /* if need byte reverse, op.val has been reversed by 227 * analyse_instr(). 228 */ 229 emulated = kvmppc_handle_store(vcpu, op.val, size, 1); 230 231 if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) 232 kvmppc_set_gpr(vcpu, op.update_reg, op.ea); 233 234 break; 235 #ifdef CONFIG_PPC_FPU 236 case STORE_FP: 237 if (kvmppc_check_fp_disabled(vcpu)) 238 return EMULATE_DONE; 239 240 /* The FP registers need to be flushed so that 241 * kvmppc_handle_store() can read actual FP vals 242 * from vcpu->arch. 243 */ 244 if (vcpu->kvm->arch.kvm_ops->giveup_ext) 245 vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, 246 MSR_FP); 247 248 if (op.type & FPCONV) 249 vcpu->arch.mmio_sp64_extend = 1; 250 251 emulated = kvmppc_handle_store(vcpu, 252 VCPU_FPR(vcpu, op.reg), size, 1); 253 254 if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) 255 kvmppc_set_gpr(vcpu, op.update_reg, op.ea); 256 257 break; 258 #endif 259 #ifdef CONFIG_ALTIVEC 260 case STORE_VMX: 261 if (kvmppc_check_altivec_disabled(vcpu)) 262 return EMULATE_DONE; 263 264 /* Hardware enforces alignment of VMX accesses. */ 265 vcpu->arch.vaddr_accessed &= ~((unsigned long)size - 1); 266 vcpu->arch.paddr_accessed &= ~((unsigned long)size - 1); 267 268 if (vcpu->kvm->arch.kvm_ops->giveup_ext) 269 vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, 270 MSR_VEC); 271 if (size == 16) { /* stvx */ 272 vcpu->arch.mmio_copy_type = 273 KVMPPC_VMX_COPY_DWORD; 274 } else if (size == 4) { /* stvewx */ 275 vcpu->arch.mmio_copy_type = 276 KVMPPC_VMX_COPY_WORD; 277 } else if (size == 2) { /* stvehx */ 278 vcpu->arch.mmio_copy_type = 279 KVMPPC_VMX_COPY_HWORD; 280 } else if (size == 1) { /* stvebx */ 281 vcpu->arch.mmio_copy_type = 282 KVMPPC_VMX_COPY_BYTE; 283 } else 284 break; 285 286 vcpu->arch.mmio_vmx_offset = 287 (vcpu->arch.vaddr_accessed & 0xf)/size; 288 289 if (size == 16) { 290 vcpu->arch.mmio_vmx_copy_nums = 2; 291 emulated = kvmppc_handle_vmx_store(vcpu, 292 op.reg, 8, 1); 293 } else { 294 vcpu->arch.mmio_vmx_copy_nums = 1; 295 emulated = kvmppc_handle_vmx_store(vcpu, 296 op.reg, size, 1); 297 } 298 299 break; 300 #endif 301 #ifdef CONFIG_VSX 302 case STORE_VSX: { 303 int io_size_each; 304 305 if (op.vsx_flags & VSX_CHECK_VEC) { 306 if (kvmppc_check_altivec_disabled(vcpu)) 307 return EMULATE_DONE; 308 } else { 309 if (kvmppc_check_vsx_disabled(vcpu)) 310 return EMULATE_DONE; 311 } 312 313 if (vcpu->kvm->arch.kvm_ops->giveup_ext) 314 vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, 315 MSR_VSX); 316 317 if (op.vsx_flags & VSX_FPCONV) 318 vcpu->arch.mmio_sp64_extend = 1; 319 320 if (op.element_size == 8) 321 vcpu->arch.mmio_copy_type = 322 KVMPPC_VSX_COPY_DWORD; 323 else if (op.element_size == 4) 324 vcpu->arch.mmio_copy_type = 325 KVMPPC_VSX_COPY_WORD; 326 else 327 break; 328 329 if (size < op.element_size) { 330 /* precise conversion case, like stxsspx */ 331 vcpu->arch.mmio_vsx_copy_nums = 1; 332 io_size_each = size; 333 } else { /* stxvw4x, stxvd2x, etc */ 334 vcpu->arch.mmio_vsx_copy_nums = 335 size/op.element_size; 336 io_size_each = op.element_size; 337 } 338 339 emulated = kvmppc_handle_vsx_store(vcpu, 340 op.reg, io_size_each, 1); 341 break; 342 } 343 #endif 344 case CACHEOP: 345 /* Do nothing. The guest is performing dcbi because 346 * hardware DMA is not snooped by the dcache, but 347 * emulated DMA either goes through the dcache as 348 * normal writes, or the host kernel has handled dcache 349 * coherence. 350 */ 351 emulated = EMULATE_DONE; 352 break; 353 default: 354 break; 355 } 356 } 357 358 if (emulated == EMULATE_FAIL) { 359 advance = 0; 360 kvmppc_core_queue_program(vcpu, 0); 361 } 362 363 trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); 364 365 /* Advance past emulated instruction. */ 366 if (advance) 367 kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); 368 369 return emulated; 370 } 371