Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.10-rc2 686 lines 19 kB view raw
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * KVM/MIPS: Deliver/Emulate exceptions to the guest kernel 7 * 8 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. 9 * Authors: Sanjay Lal <sanjayl@kymasys.com> 10 */ 11 12#include <linux/errno.h> 13#include <linux/err.h> 14#include <linux/vmalloc.h> 15 16#include <linux/kvm_host.h> 17 18#include "interrupt.h" 19 20static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva) 21{ 22 gpa_t gpa; 23 gva_t kseg = KSEGX(gva); 24 25 if ((kseg == CKSEG0) || (kseg == CKSEG1)) 26 gpa = CPHYSADDR(gva); 27 else { 28 kvm_err("%s: cannot find GPA for GVA: %#lx\n", __func__, gva); 29 kvm_mips_dump_host_tlbs(); 30 gpa = KVM_INVALID_ADDR; 31 } 32 33 kvm_debug("%s: gva %#lx, gpa: %#llx\n", __func__, gva, gpa); 34 35 return gpa; 36} 37 38static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu) 39{ 40 struct mips_coproc *cop0 = vcpu->arch.cop0; 41 struct kvm_run *run = vcpu->run; 42 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 43 u32 cause = vcpu->arch.host_cp0_cause; 44 enum emulation_result er = EMULATE_DONE; 45 int ret = RESUME_GUEST; 46 47 if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1) { 48 /* FPU Unusable */ 49 if (!kvm_mips_guest_has_fpu(&vcpu->arch) || 50 (kvm_read_c0_guest_status(cop0) & ST0_CU1) == 0) { 51 /* 52 * Unusable/no FPU in guest: 53 * deliver guest COP1 Unusable Exception 54 */ 55 er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu); 56 } else { 57 /* Restore FPU state */ 58 kvm_own_fpu(vcpu); 59 er = EMULATE_DONE; 60 } 61 } else { 62 er = kvm_mips_emulate_inst(cause, opc, run, vcpu); 63 } 64 65 switch (er) { 66 case EMULATE_DONE: 67 ret = RESUME_GUEST; 68 break; 69 70 case EMULATE_FAIL: 71 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 72 ret = RESUME_HOST; 73 break; 74 75 case EMULATE_WAIT: 76 run->exit_reason = KVM_EXIT_INTR; 77 ret = RESUME_HOST; 78 break; 79 80 default: 81 BUG(); 82 } 83 return ret; 84} 85 86static int kvm_trap_emul_handle_tlb_mod(struct kvm_vcpu *vcpu) 87{ 88 struct kvm_run *run = vcpu->run; 89 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 90 unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr; 91 u32 cause = vcpu->arch.host_cp0_cause; 92 enum emulation_result er = EMULATE_DONE; 93 int ret = RESUME_GUEST; 94 95 if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0 96 || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) { 97 kvm_debug("USER/KSEG23 ADDR TLB MOD fault: cause %#x, PC: %p, BadVaddr: %#lx\n", 98 cause, opc, badvaddr); 99 er = kvm_mips_handle_tlbmod(cause, opc, run, vcpu); 100 101 if (er == EMULATE_DONE) 102 ret = RESUME_GUEST; 103 else { 104 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 105 ret = RESUME_HOST; 106 } 107 } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) { 108 /* 109 * XXXKYMA: The guest kernel does not expect to get this fault 110 * when we are not using HIGHMEM. Need to address this in a 111 * HIGHMEM kernel 112 */ 113 kvm_err("TLB MOD fault not handled, cause %#x, PC: %p, BadVaddr: %#lx\n", 114 cause, opc, badvaddr); 115 kvm_mips_dump_host_tlbs(); 116 kvm_arch_vcpu_dump_regs(vcpu); 117 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 118 ret = RESUME_HOST; 119 } else { 120 kvm_err("Illegal TLB Mod fault address , cause %#x, PC: %p, BadVaddr: %#lx\n", 121 cause, opc, badvaddr); 122 kvm_mips_dump_host_tlbs(); 123 kvm_arch_vcpu_dump_regs(vcpu); 124 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 125 ret = RESUME_HOST; 126 } 127 return ret; 128} 129 130static int kvm_trap_emul_handle_tlb_miss(struct kvm_vcpu *vcpu, bool store) 131{ 132 struct kvm_run *run = vcpu->run; 133 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 134 unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr; 135 u32 cause = vcpu->arch.host_cp0_cause; 136 enum emulation_result er = EMULATE_DONE; 137 int ret = RESUME_GUEST; 138 139 if (((badvaddr & PAGE_MASK) == KVM_GUEST_COMMPAGE_ADDR) 140 && KVM_GUEST_KERNEL_MODE(vcpu)) { 141 if (kvm_mips_handle_commpage_tlb_fault(badvaddr, vcpu) < 0) { 142 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 143 ret = RESUME_HOST; 144 } 145 } else if (KVM_GUEST_KSEGX(badvaddr) < KVM_GUEST_KSEG0 146 || KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG23) { 147 kvm_debug("USER ADDR TLB %s fault: cause %#x, PC: %p, BadVaddr: %#lx\n", 148 store ? "ST" : "LD", cause, opc, badvaddr); 149 150 /* 151 * User Address (UA) fault, this could happen if 152 * (1) TLB entry not present/valid in both Guest and shadow host 153 * TLBs, in this case we pass on the fault to the guest 154 * kernel and let it handle it. 155 * (2) TLB entry is present in the Guest TLB but not in the 156 * shadow, in this case we inject the TLB from the Guest TLB 157 * into the shadow host TLB 158 */ 159 160 er = kvm_mips_handle_tlbmiss(cause, opc, run, vcpu); 161 if (er == EMULATE_DONE) 162 ret = RESUME_GUEST; 163 else { 164 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 165 ret = RESUME_HOST; 166 } 167 } else if (KVM_GUEST_KSEGX(badvaddr) == KVM_GUEST_KSEG0) { 168 /* 169 * All KSEG0 faults are handled by KVM, as the guest kernel does 170 * not expect to ever get them 171 */ 172 if (kvm_mips_handle_kseg0_tlb_fault 173 (vcpu->arch.host_cp0_badvaddr, vcpu) < 0) { 174 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 175 ret = RESUME_HOST; 176 } 177 } else if (KVM_GUEST_KERNEL_MODE(vcpu) 178 && (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1)) { 179 /* 180 * With EVA we may get a TLB exception instead of an address 181 * error when the guest performs MMIO to KSeg1 addresses. 182 */ 183 kvm_debug("Emulate %s MMIO space\n", 184 store ? "Store to" : "Load from"); 185 er = kvm_mips_emulate_inst(cause, opc, run, vcpu); 186 if (er == EMULATE_FAIL) { 187 kvm_err("Emulate %s MMIO space failed\n", 188 store ? "Store to" : "Load from"); 189 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 190 ret = RESUME_HOST; 191 } else { 192 run->exit_reason = KVM_EXIT_MMIO; 193 ret = RESUME_HOST; 194 } 195 } else { 196 kvm_err("Illegal TLB %s fault address , cause %#x, PC: %p, BadVaddr: %#lx\n", 197 store ? "ST" : "LD", cause, opc, badvaddr); 198 kvm_mips_dump_host_tlbs(); 199 kvm_arch_vcpu_dump_regs(vcpu); 200 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 201 ret = RESUME_HOST; 202 } 203 return ret; 204} 205 206static int kvm_trap_emul_handle_tlb_st_miss(struct kvm_vcpu *vcpu) 207{ 208 return kvm_trap_emul_handle_tlb_miss(vcpu, true); 209} 210 211static int kvm_trap_emul_handle_tlb_ld_miss(struct kvm_vcpu *vcpu) 212{ 213 return kvm_trap_emul_handle_tlb_miss(vcpu, false); 214} 215 216static int kvm_trap_emul_handle_addr_err_st(struct kvm_vcpu *vcpu) 217{ 218 struct kvm_run *run = vcpu->run; 219 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 220 unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr; 221 u32 cause = vcpu->arch.host_cp0_cause; 222 enum emulation_result er = EMULATE_DONE; 223 int ret = RESUME_GUEST; 224 225 if (KVM_GUEST_KERNEL_MODE(vcpu) 226 && (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1)) { 227 kvm_debug("Emulate Store to MMIO space\n"); 228 er = kvm_mips_emulate_inst(cause, opc, run, vcpu); 229 if (er == EMULATE_FAIL) { 230 kvm_err("Emulate Store to MMIO space failed\n"); 231 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 232 ret = RESUME_HOST; 233 } else { 234 run->exit_reason = KVM_EXIT_MMIO; 235 ret = RESUME_HOST; 236 } 237 } else { 238 kvm_err("Address Error (STORE): cause %#x, PC: %p, BadVaddr: %#lx\n", 239 cause, opc, badvaddr); 240 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 241 ret = RESUME_HOST; 242 } 243 return ret; 244} 245 246static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu) 247{ 248 struct kvm_run *run = vcpu->run; 249 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 250 unsigned long badvaddr = vcpu->arch.host_cp0_badvaddr; 251 u32 cause = vcpu->arch.host_cp0_cause; 252 enum emulation_result er = EMULATE_DONE; 253 int ret = RESUME_GUEST; 254 255 if (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1) { 256 kvm_debug("Emulate Load from MMIO space @ %#lx\n", badvaddr); 257 er = kvm_mips_emulate_inst(cause, opc, run, vcpu); 258 if (er == EMULATE_FAIL) { 259 kvm_err("Emulate Load from MMIO space failed\n"); 260 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 261 ret = RESUME_HOST; 262 } else { 263 run->exit_reason = KVM_EXIT_MMIO; 264 ret = RESUME_HOST; 265 } 266 } else { 267 kvm_err("Address Error (LOAD): cause %#x, PC: %p, BadVaddr: %#lx\n", 268 cause, opc, badvaddr); 269 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 270 ret = RESUME_HOST; 271 er = EMULATE_FAIL; 272 } 273 return ret; 274} 275 276static int kvm_trap_emul_handle_syscall(struct kvm_vcpu *vcpu) 277{ 278 struct kvm_run *run = vcpu->run; 279 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 280 u32 cause = vcpu->arch.host_cp0_cause; 281 enum emulation_result er = EMULATE_DONE; 282 int ret = RESUME_GUEST; 283 284 er = kvm_mips_emulate_syscall(cause, opc, run, vcpu); 285 if (er == EMULATE_DONE) 286 ret = RESUME_GUEST; 287 else { 288 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 289 ret = RESUME_HOST; 290 } 291 return ret; 292} 293 294static int kvm_trap_emul_handle_res_inst(struct kvm_vcpu *vcpu) 295{ 296 struct kvm_run *run = vcpu->run; 297 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 298 u32 cause = vcpu->arch.host_cp0_cause; 299 enum emulation_result er = EMULATE_DONE; 300 int ret = RESUME_GUEST; 301 302 er = kvm_mips_handle_ri(cause, opc, run, vcpu); 303 if (er == EMULATE_DONE) 304 ret = RESUME_GUEST; 305 else { 306 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 307 ret = RESUME_HOST; 308 } 309 return ret; 310} 311 312static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu) 313{ 314 struct kvm_run *run = vcpu->run; 315 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 316 u32 cause = vcpu->arch.host_cp0_cause; 317 enum emulation_result er = EMULATE_DONE; 318 int ret = RESUME_GUEST; 319 320 er = kvm_mips_emulate_bp_exc(cause, opc, run, vcpu); 321 if (er == EMULATE_DONE) 322 ret = RESUME_GUEST; 323 else { 324 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 325 ret = RESUME_HOST; 326 } 327 return ret; 328} 329 330static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu) 331{ 332 struct kvm_run *run = vcpu->run; 333 u32 __user *opc = (u32 __user *)vcpu->arch.pc; 334 u32 cause = vcpu->arch.host_cp0_cause; 335 enum emulation_result er = EMULATE_DONE; 336 int ret = RESUME_GUEST; 337 338 er = kvm_mips_emulate_trap_exc(cause, opc, run, vcpu); 339 if (er == EMULATE_DONE) { 340 ret = RESUME_GUEST; 341 } else { 342 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 343 ret = RESUME_HOST; 344 } 345 return ret; 346} 347 348static int kvm_trap_emul_handle_msa_fpe(struct kvm_vcpu *vcpu) 349{ 350 struct kvm_run *run = vcpu->run; 351 u32 __user *opc = (u32 __user *)vcpu->arch.pc; 352 u32 cause = vcpu->arch.host_cp0_cause; 353 enum emulation_result er = EMULATE_DONE; 354 int ret = RESUME_GUEST; 355 356 er = kvm_mips_emulate_msafpe_exc(cause, opc, run, vcpu); 357 if (er == EMULATE_DONE) { 358 ret = RESUME_GUEST; 359 } else { 360 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 361 ret = RESUME_HOST; 362 } 363 return ret; 364} 365 366static int kvm_trap_emul_handle_fpe(struct kvm_vcpu *vcpu) 367{ 368 struct kvm_run *run = vcpu->run; 369 u32 __user *opc = (u32 __user *)vcpu->arch.pc; 370 u32 cause = vcpu->arch.host_cp0_cause; 371 enum emulation_result er = EMULATE_DONE; 372 int ret = RESUME_GUEST; 373 374 er = kvm_mips_emulate_fpe_exc(cause, opc, run, vcpu); 375 if (er == EMULATE_DONE) { 376 ret = RESUME_GUEST; 377 } else { 378 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 379 ret = RESUME_HOST; 380 } 381 return ret; 382} 383 384/** 385 * kvm_trap_emul_handle_msa_disabled() - Guest used MSA while disabled in root. 386 * @vcpu: Virtual CPU context. 387 * 388 * Handle when the guest attempts to use MSA when it is disabled. 389 */ 390static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu) 391{ 392 struct mips_coproc *cop0 = vcpu->arch.cop0; 393 struct kvm_run *run = vcpu->run; 394 u32 __user *opc = (u32 __user *) vcpu->arch.pc; 395 u32 cause = vcpu->arch.host_cp0_cause; 396 enum emulation_result er = EMULATE_DONE; 397 int ret = RESUME_GUEST; 398 399 if (!kvm_mips_guest_has_msa(&vcpu->arch) || 400 (kvm_read_c0_guest_status(cop0) & (ST0_CU1 | ST0_FR)) == ST0_CU1) { 401 /* 402 * No MSA in guest, or FPU enabled and not in FR=1 mode, 403 * guest reserved instruction exception 404 */ 405 er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu); 406 } else if (!(kvm_read_c0_guest_config5(cop0) & MIPS_CONF5_MSAEN)) { 407 /* MSA disabled by guest, guest MSA disabled exception */ 408 er = kvm_mips_emulate_msadis_exc(cause, opc, run, vcpu); 409 } else { 410 /* Restore MSA/FPU state */ 411 kvm_own_msa(vcpu); 412 er = EMULATE_DONE; 413 } 414 415 switch (er) { 416 case EMULATE_DONE: 417 ret = RESUME_GUEST; 418 break; 419 420 case EMULATE_FAIL: 421 run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 422 ret = RESUME_HOST; 423 break; 424 425 default: 426 BUG(); 427 } 428 return ret; 429} 430 431static int kvm_trap_emul_vm_init(struct kvm *kvm) 432{ 433 return 0; 434} 435 436static int kvm_trap_emul_vcpu_init(struct kvm_vcpu *vcpu) 437{ 438 vcpu->arch.kscratch_enabled = 0xfc; 439 440 return 0; 441} 442 443static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) 444{ 445 struct mips_coproc *cop0 = vcpu->arch.cop0; 446 u32 config, config1; 447 int vcpu_id = vcpu->vcpu_id; 448 449 /* 450 * Arch specific stuff, set up config registers properly so that the 451 * guest will come up as expected 452 */ 453#ifndef CONFIG_CPU_MIPSR6 454 /* r2-r5, simulate a MIPS 24kc */ 455 kvm_write_c0_guest_prid(cop0, 0x00019300); 456#else 457 /* r6+, simulate a generic QEMU machine */ 458 kvm_write_c0_guest_prid(cop0, 0x00010000); 459#endif 460 /* 461 * Have config1, Cacheable, noncoherent, write-back, write allocate. 462 * Endianness, arch revision & virtually tagged icache should match 463 * host. 464 */ 465 config = read_c0_config() & MIPS_CONF_AR; 466 config |= MIPS_CONF_M | CONF_CM_CACHABLE_NONCOHERENT | MIPS_CONF_MT_TLB; 467#ifdef CONFIG_CPU_BIG_ENDIAN 468 config |= CONF_BE; 469#endif 470 if (cpu_has_vtag_icache) 471 config |= MIPS_CONF_VI; 472 kvm_write_c0_guest_config(cop0, config); 473 474 /* Read the cache characteristics from the host Config1 Register */ 475 config1 = (read_c0_config1() & ~0x7f); 476 477 /* Set up MMU size */ 478 config1 &= ~(0x3f << 25); 479 config1 |= ((KVM_MIPS_GUEST_TLB_SIZE - 1) << 25); 480 481 /* We unset some bits that we aren't emulating */ 482 config1 &= ~(MIPS_CONF1_C2 | MIPS_CONF1_MD | MIPS_CONF1_PC | 483 MIPS_CONF1_WR | MIPS_CONF1_CA); 484 kvm_write_c0_guest_config1(cop0, config1); 485 486 /* Have config3, no tertiary/secondary caches implemented */ 487 kvm_write_c0_guest_config2(cop0, MIPS_CONF_M); 488 /* MIPS_CONF_M | (read_c0_config2() & 0xfff) */ 489 490 /* Have config4, UserLocal */ 491 kvm_write_c0_guest_config3(cop0, MIPS_CONF_M | MIPS_CONF3_ULRI); 492 493 /* Have config5 */ 494 kvm_write_c0_guest_config4(cop0, MIPS_CONF_M); 495 496 /* No config6 */ 497 kvm_write_c0_guest_config5(cop0, 0); 498 499 /* Set Wait IE/IXMT Ignore in Config7, IAR, AR */ 500 kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10)); 501 502 /* 503 * Setup IntCtl defaults, compatibility mode for timer interrupts (HW5) 504 */ 505 kvm_write_c0_guest_intctl(cop0, 0xFC000000); 506 507 /* Put in vcpu id as CPUNum into Ebase Reg to handle SMP Guests */ 508 kvm_write_c0_guest_ebase(cop0, KVM_GUEST_KSEG0 | 509 (vcpu_id & MIPS_EBASE_CPUNUM)); 510 511 return 0; 512} 513 514static unsigned long kvm_trap_emul_num_regs(struct kvm_vcpu *vcpu) 515{ 516 return 0; 517} 518 519static int kvm_trap_emul_copy_reg_indices(struct kvm_vcpu *vcpu, 520 u64 __user *indices) 521{ 522 return 0; 523} 524 525static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu, 526 const struct kvm_one_reg *reg, 527 s64 *v) 528{ 529 switch (reg->id) { 530 case KVM_REG_MIPS_CP0_COUNT: 531 *v = kvm_mips_read_count(vcpu); 532 break; 533 case KVM_REG_MIPS_COUNT_CTL: 534 *v = vcpu->arch.count_ctl; 535 break; 536 case KVM_REG_MIPS_COUNT_RESUME: 537 *v = ktime_to_ns(vcpu->arch.count_resume); 538 break; 539 case KVM_REG_MIPS_COUNT_HZ: 540 *v = vcpu->arch.count_hz; 541 break; 542 default: 543 return -EINVAL; 544 } 545 return 0; 546} 547 548static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, 549 const struct kvm_one_reg *reg, 550 s64 v) 551{ 552 struct mips_coproc *cop0 = vcpu->arch.cop0; 553 int ret = 0; 554 unsigned int cur, change; 555 556 switch (reg->id) { 557 case KVM_REG_MIPS_CP0_COUNT: 558 kvm_mips_write_count(vcpu, v); 559 break; 560 case KVM_REG_MIPS_CP0_COMPARE: 561 kvm_mips_write_compare(vcpu, v, false); 562 break; 563 case KVM_REG_MIPS_CP0_CAUSE: 564 /* 565 * If the timer is stopped or started (DC bit) it must look 566 * atomic with changes to the interrupt pending bits (TI, IRQ5). 567 * A timer interrupt should not happen in between. 568 */ 569 if ((kvm_read_c0_guest_cause(cop0) ^ v) & CAUSEF_DC) { 570 if (v & CAUSEF_DC) { 571 /* disable timer first */ 572 kvm_mips_count_disable_cause(vcpu); 573 kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v); 574 } else { 575 /* enable timer last */ 576 kvm_change_c0_guest_cause(cop0, ~CAUSEF_DC, v); 577 kvm_mips_count_enable_cause(vcpu); 578 } 579 } else { 580 kvm_write_c0_guest_cause(cop0, v); 581 } 582 break; 583 case KVM_REG_MIPS_CP0_CONFIG: 584 /* read-only for now */ 585 break; 586 case KVM_REG_MIPS_CP0_CONFIG1: 587 cur = kvm_read_c0_guest_config1(cop0); 588 change = (cur ^ v) & kvm_mips_config1_wrmask(vcpu); 589 if (change) { 590 v = cur ^ change; 591 kvm_write_c0_guest_config1(cop0, v); 592 } 593 break; 594 case KVM_REG_MIPS_CP0_CONFIG2: 595 /* read-only for now */ 596 break; 597 case KVM_REG_MIPS_CP0_CONFIG3: 598 cur = kvm_read_c0_guest_config3(cop0); 599 change = (cur ^ v) & kvm_mips_config3_wrmask(vcpu); 600 if (change) { 601 v = cur ^ change; 602 kvm_write_c0_guest_config3(cop0, v); 603 } 604 break; 605 case KVM_REG_MIPS_CP0_CONFIG4: 606 cur = kvm_read_c0_guest_config4(cop0); 607 change = (cur ^ v) & kvm_mips_config4_wrmask(vcpu); 608 if (change) { 609 v = cur ^ change; 610 kvm_write_c0_guest_config4(cop0, v); 611 } 612 break; 613 case KVM_REG_MIPS_CP0_CONFIG5: 614 cur = kvm_read_c0_guest_config5(cop0); 615 change = (cur ^ v) & kvm_mips_config5_wrmask(vcpu); 616 if (change) { 617 v = cur ^ change; 618 kvm_write_c0_guest_config5(cop0, v); 619 } 620 break; 621 case KVM_REG_MIPS_COUNT_CTL: 622 ret = kvm_mips_set_count_ctl(vcpu, v); 623 break; 624 case KVM_REG_MIPS_COUNT_RESUME: 625 ret = kvm_mips_set_count_resume(vcpu, v); 626 break; 627 case KVM_REG_MIPS_COUNT_HZ: 628 ret = kvm_mips_set_count_hz(vcpu, v); 629 break; 630 default: 631 return -EINVAL; 632 } 633 return ret; 634} 635 636static int kvm_trap_emul_vcpu_get_regs(struct kvm_vcpu *vcpu) 637{ 638 kvm_lose_fpu(vcpu); 639 640 return 0; 641} 642 643static int kvm_trap_emul_vcpu_set_regs(struct kvm_vcpu *vcpu) 644{ 645 return 0; 646} 647 648static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { 649 /* exit handlers */ 650 .handle_cop_unusable = kvm_trap_emul_handle_cop_unusable, 651 .handle_tlb_mod = kvm_trap_emul_handle_tlb_mod, 652 .handle_tlb_st_miss = kvm_trap_emul_handle_tlb_st_miss, 653 .handle_tlb_ld_miss = kvm_trap_emul_handle_tlb_ld_miss, 654 .handle_addr_err_st = kvm_trap_emul_handle_addr_err_st, 655 .handle_addr_err_ld = kvm_trap_emul_handle_addr_err_ld, 656 .handle_syscall = kvm_trap_emul_handle_syscall, 657 .handle_res_inst = kvm_trap_emul_handle_res_inst, 658 .handle_break = kvm_trap_emul_handle_break, 659 .handle_trap = kvm_trap_emul_handle_trap, 660 .handle_msa_fpe = kvm_trap_emul_handle_msa_fpe, 661 .handle_fpe = kvm_trap_emul_handle_fpe, 662 .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled, 663 664 .vm_init = kvm_trap_emul_vm_init, 665 .vcpu_init = kvm_trap_emul_vcpu_init, 666 .vcpu_setup = kvm_trap_emul_vcpu_setup, 667 .gva_to_gpa = kvm_trap_emul_gva_to_gpa_cb, 668 .queue_timer_int = kvm_mips_queue_timer_int_cb, 669 .dequeue_timer_int = kvm_mips_dequeue_timer_int_cb, 670 .queue_io_int = kvm_mips_queue_io_int_cb, 671 .dequeue_io_int = kvm_mips_dequeue_io_int_cb, 672 .irq_deliver = kvm_mips_irq_deliver_cb, 673 .irq_clear = kvm_mips_irq_clear_cb, 674 .num_regs = kvm_trap_emul_num_regs, 675 .copy_reg_indices = kvm_trap_emul_copy_reg_indices, 676 .get_one_reg = kvm_trap_emul_get_one_reg, 677 .set_one_reg = kvm_trap_emul_set_one_reg, 678 .vcpu_get_regs = kvm_trap_emul_vcpu_get_regs, 679 .vcpu_set_regs = kvm_trap_emul_vcpu_set_regs, 680}; 681 682int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks) 683{ 684 *install_callbacks = &kvm_trap_emul_callbacks; 685 return 0; 686}