diff options
| -rw-r--r-- | arch/arm/include/asm/kvm_arm.h | 11 | ||||
| -rw-r--r-- | arch/arm/include/asm/kvm_coproc.h | 14 | ||||
| -rw-r--r-- | arch/arm/include/asm/kvm_emulate.h | 6 | ||||
| -rw-r--r-- | arch/arm/include/asm/kvm_host.h | 4 | ||||
| -rw-r--r-- | arch/arm/kvm/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/kvm/arm.c | 169 | ||||
| -rw-r--r-- | arch/arm/kvm/coproc.c | 360 | ||||
| -rw-r--r-- | arch/arm/kvm/coproc.h | 153 | ||||
| -rw-r--r-- | arch/arm/kvm/coproc_a15.c | 162 | ||||
| -rw-r--r-- | arch/arm/kvm/emulate.c | 218 | ||||
| -rw-r--r-- | arch/arm/kvm/trace.h | 65 |
11 files changed, 1160 insertions, 4 deletions
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h index c69936b1fc53..9a34c20d41ec 100644 --- a/arch/arm/include/asm/kvm_arm.h +++ b/arch/arm/include/asm/kvm_arm.h | |||
| @@ -70,6 +70,11 @@ | |||
| 70 | HCR_SWIO | HCR_TIDCP) | 70 | HCR_SWIO | HCR_TIDCP) |
| 71 | #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) | 71 | #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) |
| 72 | 72 | ||
| 73 | /* System Control Register (SCTLR) bits */ | ||
| 74 | #define SCTLR_TE (1 << 30) | ||
| 75 | #define SCTLR_EE (1 << 25) | ||
| 76 | #define SCTLR_V (1 << 13) | ||
| 77 | |||
| 73 | /* Hyp System Control Register (HSCTLR) bits */ | 78 | /* Hyp System Control Register (HSCTLR) bits */ |
| 74 | #define HSCTLR_TE (1 << 30) | 79 | #define HSCTLR_TE (1 << 30) |
| 75 | #define HSCTLR_EE (1 << 25) | 80 | #define HSCTLR_EE (1 << 25) |
| @@ -171,6 +176,10 @@ | |||
| 171 | #define HSR_FSC (0x3f) | 176 | #define HSR_FSC (0x3f) |
| 172 | #define HSR_FSC_TYPE (0x3c) | 177 | #define HSR_FSC_TYPE (0x3c) |
| 173 | #define HSR_WNR (1 << 6) | 178 | #define HSR_WNR (1 << 6) |
| 179 | #define HSR_CV_SHIFT (24) | ||
| 180 | #define HSR_CV (1U << HSR_CV_SHIFT) | ||
| 181 | #define HSR_COND_SHIFT (20) | ||
| 182 | #define HSR_COND (0xfU << HSR_COND_SHIFT) | ||
| 174 | 183 | ||
| 175 | #define FSC_FAULT (0x04) | 184 | #define FSC_FAULT (0x04) |
| 176 | #define FSC_PERM (0x0c) | 185 | #define FSC_PERM (0x0c) |
| @@ -197,4 +206,6 @@ | |||
| 197 | #define HSR_EC_DABT (0x24) | 206 | #define HSR_EC_DABT (0x24) |
| 198 | #define HSR_EC_DABT_HYP (0x25) | 207 | #define HSR_EC_DABT_HYP (0x25) |
| 199 | 208 | ||
| 209 | #define HSR_HVC_IMM_MASK ((1UL << 16) - 1) | ||
| 210 | |||
| 200 | #endif /* __ARM_KVM_ARM_H__ */ | 211 | #endif /* __ARM_KVM_ARM_H__ */ |
diff --git a/arch/arm/include/asm/kvm_coproc.h b/arch/arm/include/asm/kvm_coproc.h index b6d023deb426..bd1ace030495 100644 --- a/arch/arm/include/asm/kvm_coproc.h +++ b/arch/arm/include/asm/kvm_coproc.h | |||
| @@ -21,4 +21,18 @@ | |||
| 21 | 21 | ||
| 22 | void kvm_reset_coprocs(struct kvm_vcpu *vcpu); | 22 | void kvm_reset_coprocs(struct kvm_vcpu *vcpu); |
| 23 | 23 | ||
| 24 | struct kvm_coproc_target_table { | ||
| 25 | unsigned target; | ||
| 26 | const struct coproc_reg *table; | ||
| 27 | size_t num; | ||
| 28 | }; | ||
| 29 | void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table); | ||
| 30 | |||
| 31 | int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 32 | int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 33 | int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 34 | int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 35 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 36 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 37 | void kvm_coproc_table_init(void); | ||
| 24 | #endif /* __ARM_KVM_COPROC_H__ */ | 38 | #endif /* __ARM_KVM_COPROC_H__ */ |
diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 17dad674b90f..01a755b80632 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h | |||
| @@ -25,6 +25,12 @@ | |||
| 25 | u32 *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); | 25 | u32 *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num); |
| 26 | u32 *vcpu_spsr(struct kvm_vcpu *vcpu); | 26 | u32 *vcpu_spsr(struct kvm_vcpu *vcpu); |
| 27 | 27 | ||
| 28 | int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
| 29 | void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr); | ||
| 30 | void kvm_inject_undefined(struct kvm_vcpu *vcpu); | ||
| 31 | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); | ||
| 32 | void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); | ||
| 33 | |||
| 28 | static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu) | 34 | static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu) |
| 29 | { | 35 | { |
| 30 | return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc; | 36 | return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc; |
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 7a121089c733..e1d4168d4f19 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h | |||
| @@ -94,6 +94,10 @@ struct kvm_vcpu_arch { | |||
| 94 | * Anything that is not used directly from assembly code goes | 94 | * Anything that is not used directly from assembly code goes |
| 95 | * here. | 95 | * here. |
| 96 | */ | 96 | */ |
| 97 | /* dcache set/way operation pending */ | ||
| 98 | int last_pcpu; | ||
| 99 | cpumask_t require_dcache_flush; | ||
| 100 | |||
| 97 | /* Interrupt related fields */ | 101 | /* Interrupt related fields */ |
| 98 | u32 irq_lines; /* IRQ and FIQ levels */ | 102 | u32 irq_lines; /* IRQ and FIQ levels */ |
| 99 | 103 | ||
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile index dfc293f277b3..88edce6c97d4 100644 --- a/arch/arm/kvm/Makefile +++ b/arch/arm/kvm/Makefile | |||
| @@ -18,4 +18,4 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) | |||
| 18 | 18 | ||
| 19 | obj-y += kvm-arm.o init.o interrupts.o | 19 | obj-y += kvm-arm.o init.o interrupts.o |
| 20 | obj-y += arm.o guest.o mmu.o emulate.o reset.o | 20 | obj-y += arm.o guest.o mmu.o emulate.o reset.o |
| 21 | obj-y += coproc.o | 21 | obj-y += coproc.o coproc_a15.o |
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9e9fa4477884..be06c5de51e3 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c | |||
| @@ -36,11 +36,14 @@ | |||
| 36 | #include <asm/mman.h> | 36 | #include <asm/mman.h> |
| 37 | #include <asm/cputype.h> | 37 | #include <asm/cputype.h> |
| 38 | #include <asm/tlbflush.h> | 38 | #include <asm/tlbflush.h> |
| 39 | #include <asm/cacheflush.h> | ||
| 39 | #include <asm/virt.h> | 40 | #include <asm/virt.h> |
| 40 | #include <asm/kvm_arm.h> | 41 | #include <asm/kvm_arm.h> |
| 41 | #include <asm/kvm_asm.h> | 42 | #include <asm/kvm_asm.h> |
| 42 | #include <asm/kvm_mmu.h> | 43 | #include <asm/kvm_mmu.h> |
| 43 | #include <asm/kvm_emulate.h> | 44 | #include <asm/kvm_emulate.h> |
| 45 | #include <asm/kvm_coproc.h> | ||
| 46 | #include <asm/opcodes.h> | ||
| 44 | 47 | ||
| 45 | #ifdef REQUIRES_VIRT | 48 | #ifdef REQUIRES_VIRT |
| 46 | __asm__(".arch_extension virt"); | 49 | __asm__(".arch_extension virt"); |
| @@ -294,6 +297,15 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
| 294 | { | 297 | { |
| 295 | vcpu->cpu = cpu; | 298 | vcpu->cpu = cpu; |
| 296 | vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state); | 299 | vcpu->arch.vfp_host = this_cpu_ptr(kvm_host_vfp_state); |
| 300 | |||
| 301 | /* | ||
| 302 | * Check whether this vcpu requires the cache to be flushed on | ||
| 303 | * this physical CPU. This is a consequence of doing dcache | ||
| 304 | * operations by set/way on this vcpu. We do it here to be in | ||
| 305 | * a non-preemptible section. | ||
| 306 | */ | ||
| 307 | if (cpumask_test_and_clear_cpu(cpu, &vcpu->arch.require_dcache_flush)) | ||
| 308 | flush_cache_all(); /* We'd really want v7_flush_dcache_all() */ | ||
| 297 | } | 309 | } |
| 298 | 310 | ||
| 299 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | 311 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) |
| @@ -319,9 +331,16 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | |||
| 319 | return -EINVAL; | 331 | return -EINVAL; |
| 320 | } | 332 | } |
| 321 | 333 | ||
| 334 | /** | ||
| 335 | * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled | ||
| 336 | * @v: The VCPU pointer | ||
| 337 | * | ||
| 338 | * If the guest CPU is not waiting for interrupts or an interrupt line is | ||
| 339 | * asserted, the CPU is by definition runnable. | ||
| 340 | */ | ||
| 322 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) | 341 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) |
| 323 | { | 342 | { |
| 324 | return 0; | 343 | return !!v->arch.irq_lines; |
| 325 | } | 344 | } |
| 326 | 345 | ||
| 327 | /* Just ensure a guest exit from a particular CPU */ | 346 | /* Just ensure a guest exit from a particular CPU */ |
| @@ -411,6 +430,110 @@ static void update_vttbr(struct kvm *kvm) | |||
| 411 | spin_unlock(&kvm_vmid_lock); | 430 | spin_unlock(&kvm_vmid_lock); |
| 412 | } | 431 | } |
| 413 | 432 | ||
| 433 | static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 434 | { | ||
| 435 | /* SVC called from Hyp mode should never get here */ | ||
| 436 | kvm_debug("SVC called from Hyp mode shouldn't go here\n"); | ||
| 437 | BUG(); | ||
| 438 | return -EINVAL; /* Squash warning */ | ||
| 439 | } | ||
| 440 | |||
| 441 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 442 | { | ||
| 443 | trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), | ||
| 444 | vcpu->arch.hsr & HSR_HVC_IMM_MASK); | ||
| 445 | |||
| 446 | kvm_inject_undefined(vcpu); | ||
| 447 | return 1; | ||
| 448 | } | ||
| 449 | |||
| 450 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 451 | { | ||
| 452 | /* We don't support SMC; don't do that. */ | ||
| 453 | kvm_debug("smc: at %08x", *vcpu_pc(vcpu)); | ||
| 454 | kvm_inject_undefined(vcpu); | ||
| 455 | return 1; | ||
| 456 | } | ||
| 457 | |||
| 458 | static int handle_pabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 459 | { | ||
| 460 | /* The hypervisor should never cause aborts */ | ||
| 461 | kvm_err("Prefetch Abort taken from Hyp mode at %#08x (HSR: %#08x)\n", | ||
| 462 | vcpu->arch.hxfar, vcpu->arch.hsr); | ||
| 463 | return -EFAULT; | ||
| 464 | } | ||
| 465 | |||
| 466 | static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 467 | { | ||
| 468 | /* This is either an error in the ws. code or an external abort */ | ||
| 469 | kvm_err("Data Abort taken from Hyp mode at %#08x (HSR: %#08x)\n", | ||
| 470 | vcpu->arch.hxfar, vcpu->arch.hsr); | ||
| 471 | return -EFAULT; | ||
| 472 | } | ||
| 473 | |||
| 474 | typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *); | ||
| 475 | static exit_handle_fn arm_exit_handlers[] = { | ||
| 476 | [HSR_EC_WFI] = kvm_handle_wfi, | ||
| 477 | [HSR_EC_CP15_32] = kvm_handle_cp15_32, | ||
| 478 | [HSR_EC_CP15_64] = kvm_handle_cp15_64, | ||
| 479 | [HSR_EC_CP14_MR] = kvm_handle_cp14_access, | ||
| 480 | [HSR_EC_CP14_LS] = kvm_handle_cp14_load_store, | ||
| 481 | [HSR_EC_CP14_64] = kvm_handle_cp14_access, | ||
| 482 | [HSR_EC_CP_0_13] = kvm_handle_cp_0_13_access, | ||
| 483 | [HSR_EC_CP10_ID] = kvm_handle_cp10_id, | ||
| 484 | [HSR_EC_SVC_HYP] = handle_svc_hyp, | ||
| 485 | [HSR_EC_HVC] = handle_hvc, | ||
| 486 | [HSR_EC_SMC] = handle_smc, | ||
| 487 | [HSR_EC_IABT] = kvm_handle_guest_abort, | ||
| 488 | [HSR_EC_IABT_HYP] = handle_pabt_hyp, | ||
| 489 | [HSR_EC_DABT] = kvm_handle_guest_abort, | ||
| 490 | [HSR_EC_DABT_HYP] = handle_dabt_hyp, | ||
| 491 | }; | ||
| 492 | |||
| 493 | /* | ||
| 494 | * A conditional instruction is allowed to trap, even though it | ||
| 495 | * wouldn't be executed. So let's re-implement the hardware, in | ||
| 496 | * software! | ||
| 497 | */ | ||
| 498 | static bool kvm_condition_valid(struct kvm_vcpu *vcpu) | ||
| 499 | { | ||
| 500 | unsigned long cpsr, cond, insn; | ||
| 501 | |||
| 502 | /* | ||
| 503 | * Exception Code 0 can only happen if we set HCR.TGE to 1, to | ||
| 504 | * catch undefined instructions, and then we won't get past | ||
| 505 | * the arm_exit_handlers test anyway. | ||
| 506 | */ | ||
| 507 | BUG_ON(((vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT) == 0); | ||
| 508 | |||
| 509 | /* Top two bits non-zero? Unconditional. */ | ||
| 510 | if (vcpu->arch.hsr >> 30) | ||
| 511 | return true; | ||
| 512 | |||
| 513 | cpsr = *vcpu_cpsr(vcpu); | ||
| 514 | |||
| 515 | /* Is condition field valid? */ | ||
| 516 | if ((vcpu->arch.hsr & HSR_CV) >> HSR_CV_SHIFT) | ||
| 517 | cond = (vcpu->arch.hsr & HSR_COND) >> HSR_COND_SHIFT; | ||
| 518 | else { | ||
| 519 | /* This can happen in Thumb mode: examine IT state. */ | ||
| 520 | unsigned long it; | ||
| 521 | |||
| 522 | it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3); | ||
| 523 | |||
| 524 | /* it == 0 => unconditional. */ | ||
| 525 | if (it == 0) | ||
| 526 | return true; | ||
| 527 | |||
| 528 | /* The cond for this insn works out as the top 4 bits. */ | ||
| 529 | cond = (it >> 4); | ||
| 530 | } | ||
| 531 | |||
| 532 | /* Shift makes it look like an ARM-mode instruction */ | ||
| 533 | insn = cond << 28; | ||
| 534 | return arm_check_condition(insn, cpsr) != ARM_OPCODE_CONDTEST_FAIL; | ||
| 535 | } | ||
| 536 | |||
| 414 | /* | 537 | /* |
| 415 | * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on | 538 | * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on |
| 416 | * proper exit to QEMU. | 539 | * proper exit to QEMU. |
| @@ -418,8 +541,46 @@ static void update_vttbr(struct kvm *kvm) | |||
| 418 | static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, | 541 | static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, |
| 419 | int exception_index) | 542 | int exception_index) |
| 420 | { | 543 | { |
| 421 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | 544 | unsigned long hsr_ec; |
| 422 | return 0; | 545 | |
| 546 | switch (exception_index) { | ||
| 547 | case ARM_EXCEPTION_IRQ: | ||
| 548 | return 1; | ||
| 549 | case ARM_EXCEPTION_UNDEFINED: | ||
| 550 | kvm_err("Undefined exception in Hyp mode at: %#08x\n", | ||
| 551 | vcpu->arch.hyp_pc); | ||
| 552 | BUG(); | ||
| 553 | panic("KVM: Hypervisor undefined exception!\n"); | ||
| 554 | case ARM_EXCEPTION_DATA_ABORT: | ||
| 555 | case ARM_EXCEPTION_PREF_ABORT: | ||
| 556 | case ARM_EXCEPTION_HVC: | ||
| 557 | hsr_ec = (vcpu->arch.hsr & HSR_EC) >> HSR_EC_SHIFT; | ||
| 558 | |||
| 559 | if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) | ||
| 560 | || !arm_exit_handlers[hsr_ec]) { | ||
| 561 | kvm_err("Unkown exception class: %#08lx, " | ||
| 562 | "hsr: %#08x\n", hsr_ec, | ||
| 563 | (unsigned int)vcpu->arch.hsr); | ||
| 564 | BUG(); | ||
| 565 | } | ||
| 566 | |||
| 567 | /* | ||
| 568 | * See ARM ARM B1.14.1: "Hyp traps on instructions | ||
| 569 | * that fail their condition code check" | ||
| 570 | */ | ||
| 571 | if (!kvm_condition_valid(vcpu)) { | ||
| 572 | bool is_wide = vcpu->arch.hsr & HSR_IL; | ||
| 573 | kvm_skip_instr(vcpu, is_wide); | ||
| 574 | return 1; | ||
| 575 | } | ||
| 576 | |||
| 577 | return arm_exit_handlers[hsr_ec](vcpu, run); | ||
| 578 | default: | ||
| 579 | kvm_pr_unimpl("Unsupported exception type: %d", | ||
| 580 | exception_index); | ||
| 581 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | ||
| 582 | return 0; | ||
| 583 | } | ||
| 423 | } | 584 | } |
| 424 | 585 | ||
| 425 | static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) | 586 | static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) |
| @@ -493,6 +654,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
| 493 | ret = kvm_call_hyp(__kvm_vcpu_run, vcpu); | 654 | ret = kvm_call_hyp(__kvm_vcpu_run, vcpu); |
| 494 | 655 | ||
| 495 | vcpu->mode = OUTSIDE_GUEST_MODE; | 656 | vcpu->mode = OUTSIDE_GUEST_MODE; |
| 657 | vcpu->arch.last_pcpu = smp_processor_id(); | ||
| 496 | kvm_guest_exit(); | 658 | kvm_guest_exit(); |
| 497 | trace_kvm_exit(*vcpu_pc(vcpu)); | 659 | trace_kvm_exit(*vcpu_pc(vcpu)); |
| 498 | /* | 660 | /* |
| @@ -801,6 +963,7 @@ int kvm_arch_init(void *opaque) | |||
| 801 | if (err) | 963 | if (err) |
| 802 | goto out_err; | 964 | goto out_err; |
| 803 | 965 | ||
| 966 | kvm_coproc_table_init(); | ||
| 804 | return 0; | 967 | return 0; |
| 805 | out_err: | 968 | out_err: |
| 806 | return err; | 969 | return err; |
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 0c433558591c..722efe3b1675 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c | |||
| @@ -16,8 +16,368 @@ | |||
| 16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 17 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 18 | */ | 18 | */ |
| 19 | #include <linux/mm.h> | ||
| 19 | #include <linux/kvm_host.h> | 20 | #include <linux/kvm_host.h> |
| 21 | #include <asm/kvm_arm.h> | ||
| 22 | #include <asm/kvm_host.h> | ||
| 23 | #include <asm/kvm_emulate.h> | ||
| 24 | #include <asm/kvm_coproc.h> | ||
| 25 | #include <asm/cacheflush.h> | ||
| 26 | #include <asm/cputype.h> | ||
| 27 | #include <trace/events/kvm.h> | ||
| 20 | 28 | ||
| 29 | #include "trace.h" | ||
| 30 | #include "coproc.h" | ||
| 31 | |||
| 32 | |||
| 33 | /****************************************************************************** | ||
| 34 | * Co-processor emulation | ||
| 35 | *****************************************************************************/ | ||
| 36 | |||
| 37 | int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 38 | { | ||
| 39 | kvm_inject_undefined(vcpu); | ||
| 40 | return 1; | ||
| 41 | } | ||
| 42 | |||
| 43 | int kvm_handle_cp_0_13_access(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 44 | { | ||
| 45 | /* | ||
| 46 | * We can get here, if the host has been built without VFPv3 support, | ||
| 47 | * but the guest attempted a floating point operation. | ||
| 48 | */ | ||
| 49 | kvm_inject_undefined(vcpu); | ||
| 50 | return 1; | ||
| 51 | } | ||
| 52 | |||
| 53 | int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 54 | { | ||
| 55 | kvm_inject_undefined(vcpu); | ||
| 56 | return 1; | ||
| 57 | } | ||
| 58 | |||
| 59 | int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 60 | { | ||
| 61 | kvm_inject_undefined(vcpu); | ||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* See note at ARM ARM B1.14.4 */ | ||
| 66 | static bool access_dcsw(struct kvm_vcpu *vcpu, | ||
| 67 | const struct coproc_params *p, | ||
| 68 | const struct coproc_reg *r) | ||
| 69 | { | ||
| 70 | u32 val; | ||
| 71 | int cpu; | ||
| 72 | |||
| 73 | cpu = get_cpu(); | ||
| 74 | |||
| 75 | if (!p->is_write) | ||
| 76 | return read_from_write_only(vcpu, p); | ||
| 77 | |||
| 78 | cpumask_setall(&vcpu->arch.require_dcache_flush); | ||
| 79 | cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush); | ||
| 80 | |||
| 81 | /* If we were already preempted, take the long way around */ | ||
| 82 | if (cpu != vcpu->arch.last_pcpu) { | ||
| 83 | flush_cache_all(); | ||
| 84 | goto done; | ||
| 85 | } | ||
| 86 | |||
| 87 | val = *vcpu_reg(vcpu, p->Rt1); | ||
| 88 | |||
| 89 | switch (p->CRm) { | ||
| 90 | case 6: /* Upgrade DCISW to DCCISW, as per HCR.SWIO */ | ||
| 91 | case 14: /* DCCISW */ | ||
| 92 | asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r" (val)); | ||
| 93 | break; | ||
| 94 | |||
| 95 | case 10: /* DCCSW */ | ||
| 96 | asm volatile("mcr p15, 0, %0, c7, c10, 2" : : "r" (val)); | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | done: | ||
| 101 | put_cpu(); | ||
| 102 | |||
| 103 | return true; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * We could trap ID_DFR0 and tell the guest we don't support performance | ||
| 108 | * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was | ||
| 109 | * NAKed, so it will read the PMCR anyway. | ||
| 110 | * | ||
| 111 | * Therefore we tell the guest we have 0 counters. Unfortunately, we | ||
| 112 | * must always support PMCCNTR (the cycle counter): we just RAZ/WI for | ||
| 113 | * all PM registers, which doesn't crash the guest kernel at least. | ||
| 114 | */ | ||
| 115 | static bool pm_fake(struct kvm_vcpu *vcpu, | ||
| 116 | const struct coproc_params *p, | ||
| 117 | const struct coproc_reg *r) | ||
| 118 | { | ||
| 119 | if (p->is_write) | ||
| 120 | return ignore_write(vcpu, p); | ||
| 121 | else | ||
| 122 | return read_zero(vcpu, p); | ||
| 123 | } | ||
| 124 | |||
| 125 | #define access_pmcr pm_fake | ||
| 126 | #define access_pmcntenset pm_fake | ||
| 127 | #define access_pmcntenclr pm_fake | ||
| 128 | #define access_pmovsr pm_fake | ||
| 129 | #define access_pmselr pm_fake | ||
| 130 | #define access_pmceid0 pm_fake | ||
| 131 | #define access_pmceid1 pm_fake | ||
| 132 | #define access_pmccntr pm_fake | ||
| 133 | #define access_pmxevtyper pm_fake | ||
| 134 | #define access_pmxevcntr pm_fake | ||
| 135 | #define access_pmuserenr pm_fake | ||
| 136 | #define access_pmintenset pm_fake | ||
| 137 | #define access_pmintenclr pm_fake | ||
| 138 | |||
| 139 | /* Architected CP15 registers. | ||
| 140 | * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 | ||
| 141 | */ | ||
| 142 | static const struct coproc_reg cp15_regs[] = { | ||
| 143 | /* CSSELR: swapped by interrupt.S. */ | ||
| 144 | { CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32, | ||
| 145 | NULL, reset_unknown, c0_CSSELR }, | ||
| 146 | |||
| 147 | /* TTBR0/TTBR1: swapped by interrupt.S. */ | ||
| 148 | { CRm( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 }, | ||
| 149 | { CRm( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 }, | ||
| 150 | |||
| 151 | /* TTBCR: swapped by interrupt.S. */ | ||
| 152 | { CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32, | ||
| 153 | NULL, reset_val, c2_TTBCR, 0x00000000 }, | ||
| 154 | |||
| 155 | /* DACR: swapped by interrupt.S. */ | ||
| 156 | { CRn( 3), CRm( 0), Op1( 0), Op2( 0), is32, | ||
| 157 | NULL, reset_unknown, c3_DACR }, | ||
| 158 | |||
| 159 | /* DFSR/IFSR/ADFSR/AIFSR: swapped by interrupt.S. */ | ||
| 160 | { CRn( 5), CRm( 0), Op1( 0), Op2( 0), is32, | ||
| 161 | NULL, reset_unknown, c5_DFSR }, | ||
| 162 | { CRn( 5), CRm( 0), Op1( 0), Op2( 1), is32, | ||
| 163 | NULL, reset_unknown, c5_IFSR }, | ||
| 164 | { CRn( 5), CRm( 1), Op1( 0), Op2( 0), is32, | ||
| 165 | NULL, reset_unknown, c5_ADFSR }, | ||
| 166 | { CRn( 5), CRm( 1), Op1( 0), Op2( 1), is32, | ||
| 167 | NULL, reset_unknown, c5_AIFSR }, | ||
| 168 | |||
| 169 | /* DFAR/IFAR: swapped by interrupt.S. */ | ||
| 170 | { CRn( 6), CRm( 0), Op1( 0), Op2( 0), is32, | ||
| 171 | NULL, reset_unknown, c6_DFAR }, | ||
| 172 | { CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32, | ||
| 173 | NULL, reset_unknown, c6_IFAR }, | ||
| 174 | /* | ||
| 175 | * DC{C,I,CI}SW operations: | ||
| 176 | */ | ||
| 177 | { CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw}, | ||
| 178 | { CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw}, | ||
| 179 | { CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw}, | ||
| 180 | /* | ||
| 181 | * Dummy performance monitor implementation. | ||
| 182 | */ | ||
| 183 | { CRn( 9), CRm(12), Op1( 0), Op2( 0), is32, access_pmcr}, | ||
| 184 | { CRn( 9), CRm(12), Op1( 0), Op2( 1), is32, access_pmcntenset}, | ||
| 185 | { CRn( 9), CRm(12), Op1( 0), Op2( 2), is32, access_pmcntenclr}, | ||
| 186 | { CRn( 9), CRm(12), Op1( 0), Op2( 3), is32, access_pmovsr}, | ||
| 187 | { CRn( 9), CRm(12), Op1( 0), Op2( 5), is32, access_pmselr}, | ||
| 188 | { CRn( 9), CRm(12), Op1( 0), Op2( 6), is32, access_pmceid0}, | ||
| 189 | { CRn( 9), CRm(12), Op1( 0), Op2( 7), is32, access_pmceid1}, | ||
| 190 | { CRn( 9), CRm(13), Op1( 0), Op2( 0), is32, access_pmccntr}, | ||
| 191 | { CRn( 9), CRm(13), Op1( 0), Op2( 1), is32, access_pmxevtyper}, | ||
| 192 | { CRn( 9), CRm(13), Op1( 0), Op2( 2), is32, access_pmxevcntr}, | ||
| 193 | { CRn( 9), CRm(14), Op1( 0), Op2( 0), is32, access_pmuserenr}, | ||
| 194 | { CRn( 9), CRm(14), Op1( 0), Op2( 1), is32, access_pmintenset}, | ||
| 195 | { CRn( 9), CRm(14), Op1( 0), Op2( 2), is32, access_pmintenclr}, | ||
| 196 | |||
| 197 | /* PRRR/NMRR (aka MAIR0/MAIR1): swapped by interrupt.S. */ | ||
| 198 | { CRn(10), CRm( 2), Op1( 0), Op2( 0), is32, | ||
| 199 | NULL, reset_unknown, c10_PRRR}, | ||
| 200 | { CRn(10), CRm( 2), Op1( 0), Op2( 1), is32, | ||
| 201 | NULL, reset_unknown, c10_NMRR}, | ||
| 202 | |||
| 203 | /* VBAR: swapped by interrupt.S. */ | ||
| 204 | { CRn(12), CRm( 0), Op1( 0), Op2( 0), is32, | ||
| 205 | NULL, reset_val, c12_VBAR, 0x00000000 }, | ||
| 206 | |||
| 207 | /* CONTEXTIDR/TPIDRURW/TPIDRURO/TPIDRPRW: swapped by interrupt.S. */ | ||
| 208 | { CRn(13), CRm( 0), Op1( 0), Op2( 1), is32, | ||
| 209 | NULL, reset_val, c13_CID, 0x00000000 }, | ||
| 210 | { CRn(13), CRm( 0), Op1( 0), Op2( 2), is32, | ||
| 211 | NULL, reset_unknown, c13_TID_URW }, | ||
| 212 | { CRn(13), CRm( 0), Op1( 0), Op2( 3), is32, | ||
| 213 | NULL, reset_unknown, c13_TID_URO }, | ||
| 214 | { CRn(13), CRm( 0), Op1( 0), Op2( 4), is32, | ||
| 215 | NULL, reset_unknown, c13_TID_PRIV }, | ||
| 216 | }; | ||
| 217 | |||
| 218 | /* Target specific emulation tables */ | ||
| 219 | static struct kvm_coproc_target_table *target_tables[KVM_ARM_NUM_TARGETS]; | ||
| 220 | |||
| 221 | void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table) | ||
| 222 | { | ||
| 223 | target_tables[table->target] = table; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* Get specific register table for this target. */ | ||
| 227 | static const struct coproc_reg *get_target_table(unsigned target, size_t *num) | ||
| 228 | { | ||
| 229 | struct kvm_coproc_target_table *table; | ||
| 230 | |||
| 231 | table = target_tables[target]; | ||
| 232 | *num = table->num; | ||
| 233 | return table->table; | ||
| 234 | } | ||
| 235 | |||
| 236 | static const struct coproc_reg *find_reg(const struct coproc_params *params, | ||
| 237 | const struct coproc_reg table[], | ||
| 238 | unsigned int num) | ||
| 239 | { | ||
| 240 | unsigned int i; | ||
| 241 | |||
| 242 | for (i = 0; i < num; i++) { | ||
| 243 | const struct coproc_reg *r = &table[i]; | ||
| 244 | |||
| 245 | if (params->is_64bit != r->is_64) | ||
| 246 | continue; | ||
| 247 | if (params->CRn != r->CRn) | ||
| 248 | continue; | ||
| 249 | if (params->CRm != r->CRm) | ||
| 250 | continue; | ||
| 251 | if (params->Op1 != r->Op1) | ||
| 252 | continue; | ||
| 253 | if (params->Op2 != r->Op2) | ||
| 254 | continue; | ||
| 255 | |||
| 256 | return r; | ||
| 257 | } | ||
| 258 | return NULL; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int emulate_cp15(struct kvm_vcpu *vcpu, | ||
| 262 | const struct coproc_params *params) | ||
| 263 | { | ||
| 264 | size_t num; | ||
| 265 | const struct coproc_reg *table, *r; | ||
| 266 | |||
| 267 | trace_kvm_emulate_cp15_imp(params->Op1, params->Rt1, params->CRn, | ||
| 268 | params->CRm, params->Op2, params->is_write); | ||
| 269 | |||
| 270 | table = get_target_table(vcpu->arch.target, &num); | ||
| 271 | |||
| 272 | /* Search target-specific then generic table. */ | ||
| 273 | r = find_reg(params, table, num); | ||
| 274 | if (!r) | ||
| 275 | r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs)); | ||
| 276 | |||
| 277 | if (likely(r)) { | ||
| 278 | /* If we don't have an accessor, we should never get here! */ | ||
| 279 | BUG_ON(!r->access); | ||
| 280 | |||
| 281 | if (likely(r->access(vcpu, params, r))) { | ||
| 282 | /* Skip instruction, since it was emulated */ | ||
| 283 | kvm_skip_instr(vcpu, (vcpu->arch.hsr >> 25) & 1); | ||
| 284 | return 1; | ||
| 285 | } | ||
| 286 | /* If access function fails, it should complain. */ | ||
| 287 | } else { | ||
| 288 | kvm_err("Unsupported guest CP15 access at: %08x\n", | ||
| 289 | *vcpu_pc(vcpu)); | ||
| 290 | print_cp_instr(params); | ||
| 291 | } | ||
| 292 | kvm_inject_undefined(vcpu); | ||
| 293 | return 1; | ||
| 294 | } | ||
| 295 | |||
| 296 | /** | ||
| 297 | * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access | ||
| 298 | * @vcpu: The VCPU pointer | ||
| 299 | * @run: The kvm_run struct | ||
| 300 | */ | ||
| 301 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 302 | { | ||
| 303 | struct coproc_params params; | ||
| 304 | |||
| 305 | params.CRm = (vcpu->arch.hsr >> 1) & 0xf; | ||
| 306 | params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf; | ||
| 307 | params.is_write = ((vcpu->arch.hsr & 1) == 0); | ||
| 308 | params.is_64bit = true; | ||
| 309 | |||
| 310 | params.Op1 = (vcpu->arch.hsr >> 16) & 0xf; | ||
| 311 | params.Op2 = 0; | ||
| 312 | params.Rt2 = (vcpu->arch.hsr >> 10) & 0xf; | ||
| 313 | params.CRn = 0; | ||
| 314 | |||
| 315 | return emulate_cp15(vcpu, ¶ms); | ||
| 316 | } | ||
| 317 | |||
| 318 | static void reset_coproc_regs(struct kvm_vcpu *vcpu, | ||
| 319 | const struct coproc_reg *table, size_t num) | ||
| 320 | { | ||
| 321 | unsigned long i; | ||
| 322 | |||
| 323 | for (i = 0; i < num; i++) | ||
| 324 | if (table[i].reset) | ||
| 325 | table[i].reset(vcpu, &table[i]); | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access | ||
| 330 | * @vcpu: The VCPU pointer | ||
| 331 | * @run: The kvm_run struct | ||
| 332 | */ | ||
| 333 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 334 | { | ||
| 335 | struct coproc_params params; | ||
| 336 | |||
| 337 | params.CRm = (vcpu->arch.hsr >> 1) & 0xf; | ||
| 338 | params.Rt1 = (vcpu->arch.hsr >> 5) & 0xf; | ||
| 339 | params.is_write = ((vcpu->arch.hsr & 1) == 0); | ||
| 340 | params.is_64bit = false; | ||
| 341 | |||
| 342 | params.CRn = (vcpu->arch.hsr >> 10) & 0xf; | ||
| 343 | params.Op1 = (vcpu->arch.hsr >> 14) & 0x7; | ||
| 344 | params.Op2 = (vcpu->arch.hsr >> 17) & 0x7; | ||
| 345 | params.Rt2 = 0; | ||
| 346 | |||
| 347 | return emulate_cp15(vcpu, ¶ms); | ||
| 348 | } | ||
| 349 | |||
| 350 | void kvm_coproc_table_init(void) | ||
| 351 | { | ||
| 352 | unsigned int i; | ||
| 353 | |||
| 354 | /* Make sure tables are unique and in order. */ | ||
| 355 | for (i = 1; i < ARRAY_SIZE(cp15_regs); i++) | ||
| 356 | BUG_ON(cmp_reg(&cp15_regs[i-1], &cp15_regs[i]) >= 0); | ||
| 357 | } | ||
| 358 | |||
| 359 | /** | ||
| 360 | * kvm_reset_coprocs - sets cp15 registers to reset value | ||
| 361 | * @vcpu: The VCPU pointer | ||
| 362 | * | ||
| 363 | * This function finds the right table above and sets the registers on the | ||
| 364 | * virtual CPU struct to their architecturally defined reset values. | ||
| 365 | */ | ||
| 21 | void kvm_reset_coprocs(struct kvm_vcpu *vcpu) | 366 | void kvm_reset_coprocs(struct kvm_vcpu *vcpu) |
| 22 | { | 367 | { |
| 368 | size_t num; | ||
| 369 | const struct coproc_reg *table; | ||
| 370 | |||
| 371 | /* Catch someone adding a register without putting in reset entry. */ | ||
| 372 | memset(vcpu->arch.cp15, 0x42, sizeof(vcpu->arch.cp15)); | ||
| 373 | |||
| 374 | /* Generic chip reset first (so target could override). */ | ||
| 375 | reset_coproc_regs(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs)); | ||
| 376 | |||
| 377 | table = get_target_table(vcpu->arch.target, &num); | ||
| 378 | reset_coproc_regs(vcpu, table, num); | ||
| 379 | |||
| 380 | for (num = 1; num < NR_CP15_REGS; num++) | ||
| 381 | if (vcpu->arch.cp15[num] == 0x42424242) | ||
| 382 | panic("Didn't reset vcpu->arch.cp15[%zi]", num); | ||
| 23 | } | 383 | } |
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h new file mode 100644 index 000000000000..992adfafa2ff --- /dev/null +++ b/arch/arm/kvm/coproc.h | |||
| @@ -0,0 +1,153 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 - Virtual Open Systems and Columbia University | ||
| 3 | * Authors: Christoffer Dall <c.dall@virtualopensystems.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License, version 2, as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __ARM_KVM_COPROC_LOCAL_H__ | ||
| 20 | #define __ARM_KVM_COPROC_LOCAL_H__ | ||
| 21 | |||
| 22 | struct coproc_params { | ||
| 23 | unsigned long CRn; | ||
| 24 | unsigned long CRm; | ||
| 25 | unsigned long Op1; | ||
| 26 | unsigned long Op2; | ||
| 27 | unsigned long Rt1; | ||
| 28 | unsigned long Rt2; | ||
| 29 | bool is_64bit; | ||
| 30 | bool is_write; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct coproc_reg { | ||
| 34 | /* MRC/MCR/MRRC/MCRR instruction which accesses it. */ | ||
| 35 | unsigned long CRn; | ||
| 36 | unsigned long CRm; | ||
| 37 | unsigned long Op1; | ||
| 38 | unsigned long Op2; | ||
| 39 | |||
| 40 | bool is_64; | ||
| 41 | |||
| 42 | /* Trapped access from guest, if non-NULL. */ | ||
| 43 | bool (*access)(struct kvm_vcpu *, | ||
| 44 | const struct coproc_params *, | ||
| 45 | const struct coproc_reg *); | ||
| 46 | |||
| 47 | /* Initialization for vcpu. */ | ||
| 48 | void (*reset)(struct kvm_vcpu *, const struct coproc_reg *); | ||
| 49 | |||
| 50 | /* Index into vcpu->arch.cp15[], or 0 if we don't need to save it. */ | ||
| 51 | unsigned long reg; | ||
| 52 | |||
| 53 | /* Value (usually reset value) */ | ||
| 54 | u64 val; | ||
| 55 | }; | ||
| 56 | |||
| 57 | static inline void print_cp_instr(const struct coproc_params *p) | ||
| 58 | { | ||
| 59 | /* Look, we even formatted it for you to paste into the table! */ | ||
| 60 | if (p->is_64bit) { | ||
| 61 | kvm_pr_unimpl(" { CRm(%2lu), Op1(%2lu), is64, func_%s },\n", | ||
| 62 | p->CRm, p->Op1, p->is_write ? "write" : "read"); | ||
| 63 | } else { | ||
| 64 | kvm_pr_unimpl(" { CRn(%2lu), CRm(%2lu), Op1(%2lu), Op2(%2lu), is32," | ||
| 65 | " func_%s },\n", | ||
| 66 | p->CRn, p->CRm, p->Op1, p->Op2, | ||
| 67 | p->is_write ? "write" : "read"); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline bool ignore_write(struct kvm_vcpu *vcpu, | ||
| 72 | const struct coproc_params *p) | ||
| 73 | { | ||
| 74 | return true; | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline bool read_zero(struct kvm_vcpu *vcpu, | ||
| 78 | const struct coproc_params *p) | ||
| 79 | { | ||
| 80 | *vcpu_reg(vcpu, p->Rt1) = 0; | ||
| 81 | return true; | ||
| 82 | } | ||
| 83 | |||
| 84 | static inline bool write_to_read_only(struct kvm_vcpu *vcpu, | ||
| 85 | const struct coproc_params *params) | ||
| 86 | { | ||
| 87 | kvm_debug("CP15 write to read-only register at: %08x\n", | ||
| 88 | *vcpu_pc(vcpu)); | ||
| 89 | print_cp_instr(params); | ||
| 90 | return false; | ||
| 91 | } | ||
| 92 | |||
| 93 | static inline bool read_from_write_only(struct kvm_vcpu *vcpu, | ||
| 94 | const struct coproc_params *params) | ||
| 95 | { | ||
| 96 | kvm_debug("CP15 read to write-only register at: %08x\n", | ||
| 97 | *vcpu_pc(vcpu)); | ||
| 98 | print_cp_instr(params); | ||
| 99 | return false; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* Reset functions */ | ||
| 103 | static inline void reset_unknown(struct kvm_vcpu *vcpu, | ||
| 104 | const struct coproc_reg *r) | ||
| 105 | { | ||
| 106 | BUG_ON(!r->reg); | ||
| 107 | BUG_ON(r->reg >= ARRAY_SIZE(vcpu->arch.cp15)); | ||
| 108 | vcpu->arch.cp15[r->reg] = 0xdecafbad; | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline void reset_val(struct kvm_vcpu *vcpu, const struct coproc_reg *r) | ||
| 112 | { | ||
| 113 | BUG_ON(!r->reg); | ||
| 114 | BUG_ON(r->reg >= ARRAY_SIZE(vcpu->arch.cp15)); | ||
| 115 | vcpu->arch.cp15[r->reg] = r->val; | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline void reset_unknown64(struct kvm_vcpu *vcpu, | ||
| 119 | const struct coproc_reg *r) | ||
| 120 | { | ||
| 121 | BUG_ON(!r->reg); | ||
| 122 | BUG_ON(r->reg + 1 >= ARRAY_SIZE(vcpu->arch.cp15)); | ||
| 123 | |||
| 124 | vcpu->arch.cp15[r->reg] = 0xdecafbad; | ||
| 125 | vcpu->arch.cp15[r->reg+1] = 0xd0c0ffee; | ||
| 126 | } | ||
| 127 | |||
| 128 | static inline int cmp_reg(const struct coproc_reg *i1, | ||
| 129 | const struct coproc_reg *i2) | ||
| 130 | { | ||
| 131 | BUG_ON(i1 == i2); | ||
| 132 | if (!i1) | ||
| 133 | return 1; | ||
| 134 | else if (!i2) | ||
| 135 | return -1; | ||
| 136 | if (i1->CRn != i2->CRn) | ||
| 137 | return i1->CRn - i2->CRn; | ||
| 138 | if (i1->CRm != i2->CRm) | ||
| 139 | return i1->CRm - i2->CRm; | ||
| 140 | if (i1->Op1 != i2->Op1) | ||
| 141 | return i1->Op1 - i2->Op1; | ||
| 142 | return i1->Op2 - i2->Op2; | ||
| 143 | } | ||
| 144 | |||
| 145 | |||
| 146 | #define CRn(_x) .CRn = _x | ||
| 147 | #define CRm(_x) .CRm = _x | ||
| 148 | #define Op1(_x) .Op1 = _x | ||
| 149 | #define Op2(_x) .Op2 = _x | ||
| 150 | #define is64 .is_64 = true | ||
| 151 | #define is32 .is_64 = false | ||
| 152 | |||
| 153 | #endif /* __ARM_KVM_COPROC_LOCAL_H__ */ | ||
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c new file mode 100644 index 000000000000..685063a6d0cf --- /dev/null +++ b/arch/arm/kvm/coproc_a15.c | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 - Virtual Open Systems and Columbia University | ||
| 3 | * Authors: Rusty Russell <rusty@rustcorp.au> | ||
| 4 | * Christoffer Dall <c.dall@virtualopensystems.com> | ||
| 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, as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 18 | */ | ||
| 19 | #include <linux/kvm_host.h> | ||
| 20 | #include <asm/cputype.h> | ||
| 21 | #include <asm/kvm_arm.h> | ||
| 22 | #include <asm/kvm_host.h> | ||
| 23 | #include <asm/kvm_emulate.h> | ||
| 24 | #include <asm/kvm_coproc.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | |||
| 27 | static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) | ||
| 28 | { | ||
| 29 | /* | ||
| 30 | * Compute guest MPIDR: | ||
| 31 | * (Even if we present only one VCPU to the guest on an SMP | ||
| 32 | * host we don't set the U bit in the MPIDR, or vice versa, as | ||
| 33 | * revealing the underlying hardware properties is likely to | ||
| 34 | * be the best choice). | ||
| 35 | */ | ||
| 36 | vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & ~MPIDR_LEVEL_MASK) | ||
| 37 | | (vcpu->vcpu_id & MPIDR_LEVEL_MASK); | ||
| 38 | } | ||
| 39 | |||
| 40 | #include "coproc.h" | ||
| 41 | |||
| 42 | /* A15 TRM 4.3.28: RO WI */ | ||
| 43 | static bool access_actlr(struct kvm_vcpu *vcpu, | ||
| 44 | const struct coproc_params *p, | ||
| 45 | const struct coproc_reg *r) | ||
| 46 | { | ||
| 47 | if (p->is_write) | ||
| 48 | return ignore_write(vcpu, p); | ||
| 49 | |||
| 50 | *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR]; | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* A15 TRM 4.3.60: R/O. */ | ||
| 55 | static bool access_cbar(struct kvm_vcpu *vcpu, | ||
| 56 | const struct coproc_params *p, | ||
| 57 | const struct coproc_reg *r) | ||
| 58 | { | ||
| 59 | if (p->is_write) | ||
| 60 | return write_to_read_only(vcpu, p); | ||
| 61 | return read_zero(vcpu, p); | ||
| 62 | } | ||
| 63 | |||
| 64 | /* A15 TRM 4.3.48: R/O WI. */ | ||
| 65 | static bool access_l2ctlr(struct kvm_vcpu *vcpu, | ||
| 66 | const struct coproc_params *p, | ||
| 67 | const struct coproc_reg *r) | ||
| 68 | { | ||
| 69 | if (p->is_write) | ||
| 70 | return ignore_write(vcpu, p); | ||
| 71 | |||
| 72 | *vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR]; | ||
| 73 | return true; | ||
| 74 | } | ||
| 75 | |||
| 76 | static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) | ||
| 77 | { | ||
| 78 | u32 l2ctlr, ncores; | ||
| 79 | |||
| 80 | asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr)); | ||
| 81 | l2ctlr &= ~(3 << 24); | ||
| 82 | ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1; | ||
| 83 | l2ctlr |= (ncores & 3) << 24; | ||
| 84 | |||
| 85 | vcpu->arch.cp15[c9_L2CTLR] = l2ctlr; | ||
| 86 | } | ||
| 87 | |||
| 88 | static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r) | ||
| 89 | { | ||
| 90 | u32 actlr; | ||
| 91 | |||
| 92 | /* ACTLR contains SMP bit: make sure you create all cpus first! */ | ||
| 93 | asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr)); | ||
| 94 | /* Make the SMP bit consistent with the guest configuration */ | ||
| 95 | if (atomic_read(&vcpu->kvm->online_vcpus) > 1) | ||
| 96 | actlr |= 1U << 6; | ||
| 97 | else | ||
| 98 | actlr &= ~(1U << 6); | ||
| 99 | |||
| 100 | vcpu->arch.cp15[c1_ACTLR] = actlr; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* A15 TRM 4.3.49: R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). */ | ||
| 104 | static bool access_l2ectlr(struct kvm_vcpu *vcpu, | ||
| 105 | const struct coproc_params *p, | ||
| 106 | const struct coproc_reg *r) | ||
| 107 | { | ||
| 108 | if (p->is_write) | ||
| 109 | return ignore_write(vcpu, p); | ||
| 110 | |||
| 111 | *vcpu_reg(vcpu, p->Rt1) = 0; | ||
| 112 | return true; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* | ||
| 116 | * A15-specific CP15 registers. | ||
| 117 | * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 | ||
| 118 | */ | ||
| 119 | static const struct coproc_reg a15_regs[] = { | ||
| 120 | /* MPIDR: we use VMPIDR for guest access. */ | ||
| 121 | { CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32, | ||
| 122 | NULL, reset_mpidr, c0_MPIDR }, | ||
| 123 | |||
| 124 | /* SCTLR: swapped by interrupt.S. */ | ||
| 125 | { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, | ||
| 126 | NULL, reset_val, c1_SCTLR, 0x00C50078 }, | ||
| 127 | /* ACTLR: trapped by HCR.TAC bit. */ | ||
| 128 | { CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32, | ||
| 129 | access_actlr, reset_actlr, c1_ACTLR }, | ||
| 130 | /* CPACR: swapped by interrupt.S. */ | ||
| 131 | { CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32, | ||
| 132 | NULL, reset_val, c1_CPACR, 0x00000000 }, | ||
| 133 | |||
| 134 | /* | ||
| 135 | * L2CTLR access (guest wants to know #CPUs). | ||
| 136 | */ | ||
| 137 | { CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32, | ||
| 138 | access_l2ctlr, reset_l2ctlr, c9_L2CTLR }, | ||
| 139 | { CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr}, | ||
| 140 | |||
| 141 | /* The Configuration Base Address Register. */ | ||
| 142 | { CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar}, | ||
| 143 | }; | ||
| 144 | |||
| 145 | static struct kvm_coproc_target_table a15_target_table = { | ||
| 146 | .target = KVM_ARM_TARGET_CORTEX_A15, | ||
| 147 | .table = a15_regs, | ||
| 148 | .num = ARRAY_SIZE(a15_regs), | ||
| 149 | }; | ||
| 150 | |||
| 151 | static int __init coproc_a15_init(void) | ||
| 152 | { | ||
| 153 | unsigned int i; | ||
| 154 | |||
| 155 | for (i = 1; i < ARRAY_SIZE(a15_regs); i++) | ||
| 156 | BUG_ON(cmp_reg(&a15_regs[i-1], | ||
| 157 | &a15_regs[i]) >= 0); | ||
| 158 | |||
| 159 | kvm_register_target_coproc_table(&a15_target_table); | ||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | late_initcall(coproc_a15_init); | ||
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c index 3eadc25e95de..d61450ac6665 100644 --- a/arch/arm/kvm/emulate.c +++ b/arch/arm/kvm/emulate.c | |||
| @@ -16,7 +16,13 @@ | |||
| 16 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <linux/mm.h> | ||
| 20 | #include <linux/kvm_host.h> | ||
| 21 | #include <asm/kvm_arm.h> | ||
| 19 | #include <asm/kvm_emulate.h> | 22 | #include <asm/kvm_emulate.h> |
| 23 | #include <trace/events/kvm.h> | ||
| 24 | |||
| 25 | #include "trace.h" | ||
| 20 | 26 | ||
| 21 | #define VCPU_NR_MODES 6 | 27 | #define VCPU_NR_MODES 6 |
| 22 | #define VCPU_REG_OFFSET_USR 0 | 28 | #define VCPU_REG_OFFSET_USR 0 |
| @@ -153,3 +159,215 @@ u32 *vcpu_spsr(struct kvm_vcpu *vcpu) | |||
| 153 | BUG(); | 159 | BUG(); |
| 154 | } | 160 | } |
| 155 | } | 161 | } |
| 162 | |||
| 163 | /** | ||
| 164 | * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest | ||
| 165 | * @vcpu: the vcpu pointer | ||
| 166 | * @run: the kvm_run structure pointer | ||
| 167 | * | ||
| 168 | * Simply sets the wait_for_interrupts flag on the vcpu structure, which will | ||
| 169 | * halt execution of world-switches and schedule other host processes until | ||
| 170 | * there is an incoming IRQ or FIQ to the VM. | ||
| 171 | */ | ||
| 172 | int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
| 173 | { | ||
| 174 | trace_kvm_wfi(*vcpu_pc(vcpu)); | ||
| 175 | kvm_vcpu_block(vcpu); | ||
| 176 | return 1; | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * adjust_itstate - adjust ITSTATE when emulating instructions in IT-block | ||
| 181 | * @vcpu: The VCPU pointer | ||
| 182 | * | ||
| 183 | * When exceptions occur while instructions are executed in Thumb IF-THEN | ||
| 184 | * blocks, the ITSTATE field of the CPSR is not advanved (updated), so we have | ||
| 185 | * to do this little bit of work manually. The fields map like this: | ||
| 186 | * | ||
| 187 | * IT[7:0] -> CPSR[26:25],CPSR[15:10] | ||
| 188 | */ | ||
| 189 | static void kvm_adjust_itstate(struct kvm_vcpu *vcpu) | ||
| 190 | { | ||
| 191 | unsigned long itbits, cond; | ||
| 192 | unsigned long cpsr = *vcpu_cpsr(vcpu); | ||
| 193 | bool is_arm = !(cpsr & PSR_T_BIT); | ||
| 194 | |||
| 195 | BUG_ON(is_arm && (cpsr & PSR_IT_MASK)); | ||
| 196 | |||
| 197 | if (!(cpsr & PSR_IT_MASK)) | ||
| 198 | return; | ||
| 199 | |||
| 200 | cond = (cpsr & 0xe000) >> 13; | ||
| 201 | itbits = (cpsr & 0x1c00) >> (10 - 2); | ||
| 202 | itbits |= (cpsr & (0x3 << 25)) >> 25; | ||
| 203 | |||
| 204 | /* Perform ITAdvance (see page A-52 in ARM DDI 0406C) */ | ||
| 205 | if ((itbits & 0x7) == 0) | ||
| 206 | itbits = cond = 0; | ||
| 207 | else | ||
| 208 | itbits = (itbits << 1) & 0x1f; | ||
| 209 | |||
| 210 | cpsr &= ~PSR_IT_MASK; | ||
| 211 | cpsr |= cond << 13; | ||
| 212 | cpsr |= (itbits & 0x1c) << (10 - 2); | ||
| 213 | cpsr |= (itbits & 0x3) << 25; | ||
| 214 | *vcpu_cpsr(vcpu) = cpsr; | ||
| 215 | } | ||
| 216 | |||
| 217 | /** | ||
| 218 | * kvm_skip_instr - skip a trapped instruction and proceed to the next | ||
| 219 | * @vcpu: The vcpu pointer | ||
| 220 | */ | ||
| 221 | void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr) | ||
| 222 | { | ||
| 223 | bool is_thumb; | ||
| 224 | |||
| 225 | is_thumb = !!(*vcpu_cpsr(vcpu) & PSR_T_BIT); | ||
| 226 | if (is_thumb && !is_wide_instr) | ||
| 227 | *vcpu_pc(vcpu) += 2; | ||
| 228 | else | ||
| 229 | *vcpu_pc(vcpu) += 4; | ||
| 230 | kvm_adjust_itstate(vcpu); | ||
| 231 | } | ||
| 232 | |||
| 233 | |||
| 234 | /****************************************************************************** | ||
| 235 | * Inject exceptions into the guest | ||
| 236 | */ | ||
| 237 | |||
| 238 | static u32 exc_vector_base(struct kvm_vcpu *vcpu) | ||
| 239 | { | ||
| 240 | u32 sctlr = vcpu->arch.cp15[c1_SCTLR]; | ||
| 241 | u32 vbar = vcpu->arch.cp15[c12_VBAR]; | ||
| 242 | |||
| 243 | if (sctlr & SCTLR_V) | ||
| 244 | return 0xffff0000; | ||
| 245 | else /* always have security exceptions */ | ||
| 246 | return vbar; | ||
| 247 | } | ||
| 248 | |||
| 249 | /** | ||
| 250 | * kvm_inject_undefined - inject an undefined exception into the guest | ||
| 251 | * @vcpu: The VCPU to receive the undefined exception | ||
| 252 | * | ||
| 253 | * It is assumed that this code is called from the VCPU thread and that the | ||
| 254 | * VCPU therefore is not currently executing guest code. | ||
| 255 | * | ||
| 256 | * Modelled after TakeUndefInstrException() pseudocode. | ||
| 257 | */ | ||
| 258 | void kvm_inject_undefined(struct kvm_vcpu *vcpu) | ||
| 259 | { | ||
| 260 | u32 new_lr_value; | ||
| 261 | u32 new_spsr_value; | ||
| 262 | u32 cpsr = *vcpu_cpsr(vcpu); | ||
| 263 | u32 sctlr = vcpu->arch.cp15[c1_SCTLR]; | ||
| 264 | bool is_thumb = (cpsr & PSR_T_BIT); | ||
| 265 | u32 vect_offset = 4; | ||
| 266 | u32 return_offset = (is_thumb) ? 2 : 4; | ||
| 267 | |||
| 268 | new_spsr_value = cpsr; | ||
| 269 | new_lr_value = *vcpu_pc(vcpu) - return_offset; | ||
| 270 | |||
| 271 | *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | UND_MODE; | ||
| 272 | *vcpu_cpsr(vcpu) |= PSR_I_BIT; | ||
| 273 | *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT); | ||
| 274 | |||
| 275 | if (sctlr & SCTLR_TE) | ||
| 276 | *vcpu_cpsr(vcpu) |= PSR_T_BIT; | ||
| 277 | if (sctlr & SCTLR_EE) | ||
| 278 | *vcpu_cpsr(vcpu) |= PSR_E_BIT; | ||
| 279 | |||
| 280 | /* Note: These now point to UND banked copies */ | ||
| 281 | *vcpu_spsr(vcpu) = cpsr; | ||
| 282 | *vcpu_reg(vcpu, 14) = new_lr_value; | ||
| 283 | |||
| 284 | /* Branch to exception vector */ | ||
| 285 | *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* | ||
| 289 | * Modelled after TakeDataAbortException() and TakePrefetchAbortException | ||
| 290 | * pseudocode. | ||
| 291 | */ | ||
| 292 | static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr) | ||
| 293 | { | ||
| 294 | u32 new_lr_value; | ||
| 295 | u32 new_spsr_value; | ||
| 296 | u32 cpsr = *vcpu_cpsr(vcpu); | ||
| 297 | u32 sctlr = vcpu->arch.cp15[c1_SCTLR]; | ||
| 298 | bool is_thumb = (cpsr & PSR_T_BIT); | ||
| 299 | u32 vect_offset; | ||
| 300 | u32 return_offset = (is_thumb) ? 4 : 0; | ||
| 301 | bool is_lpae; | ||
| 302 | |||
| 303 | new_spsr_value = cpsr; | ||
| 304 | new_lr_value = *vcpu_pc(vcpu) + return_offset; | ||
| 305 | |||
| 306 | *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | ABT_MODE; | ||
| 307 | *vcpu_cpsr(vcpu) |= PSR_I_BIT | PSR_A_BIT; | ||
| 308 | *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT); | ||
| 309 | |||
| 310 | if (sctlr & SCTLR_TE) | ||
| 311 | *vcpu_cpsr(vcpu) |= PSR_T_BIT; | ||
| 312 | if (sctlr & SCTLR_EE) | ||
| 313 | *vcpu_cpsr(vcpu) |= PSR_E_BIT; | ||
| 314 | |||
| 315 | /* Note: These now point to ABT banked copies */ | ||
| 316 | *vcpu_spsr(vcpu) = cpsr; | ||
| 317 | *vcpu_reg(vcpu, 14) = new_lr_value; | ||
| 318 | |||
| 319 | if (is_pabt) | ||
| 320 | vect_offset = 12; | ||
| 321 | else | ||
| 322 | vect_offset = 16; | ||
| 323 | |||
| 324 | /* Branch to exception vector */ | ||
| 325 | *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset; | ||
| 326 | |||
| 327 | if (is_pabt) { | ||
| 328 | /* Set DFAR and DFSR */ | ||
| 329 | vcpu->arch.cp15[c6_IFAR] = addr; | ||
| 330 | is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31); | ||
| 331 | /* Always give debug fault for now - should give guest a clue */ | ||
| 332 | if (is_lpae) | ||
| 333 | vcpu->arch.cp15[c5_IFSR] = 1 << 9 | 0x22; | ||
| 334 | else | ||
| 335 | vcpu->arch.cp15[c5_IFSR] = 2; | ||
| 336 | } else { /* !iabt */ | ||
| 337 | /* Set DFAR and DFSR */ | ||
| 338 | vcpu->arch.cp15[c6_DFAR] = addr; | ||
| 339 | is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31); | ||
| 340 | /* Always give debug fault for now - should give guest a clue */ | ||
| 341 | if (is_lpae) | ||
| 342 | vcpu->arch.cp15[c5_DFSR] = 1 << 9 | 0x22; | ||
| 343 | else | ||
| 344 | vcpu->arch.cp15[c5_DFSR] = 2; | ||
| 345 | } | ||
| 346 | |||
| 347 | } | ||
| 348 | |||
| 349 | /** | ||
| 350 | * kvm_inject_dabt - inject a data abort into the guest | ||
| 351 | * @vcpu: The VCPU to receive the undefined exception | ||
| 352 | * @addr: The address to report in the DFAR | ||
| 353 | * | ||
| 354 | * It is assumed that this code is called from the VCPU thread and that the | ||
| 355 | * VCPU therefore is not currently executing guest code. | ||
| 356 | */ | ||
| 357 | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr) | ||
| 358 | { | ||
| 359 | inject_abt(vcpu, false, addr); | ||
| 360 | } | ||
| 361 | |||
| 362 | /** | ||
| 363 | * kvm_inject_pabt - inject a prefetch abort into the guest | ||
| 364 | * @vcpu: The VCPU to receive the undefined exception | ||
| 365 | * @addr: The address to report in the DFAR | ||
| 366 | * | ||
| 367 | * It is assumed that this code is called from the VCPU thread and that the | ||
| 368 | * VCPU therefore is not currently executing guest code. | ||
| 369 | */ | ||
| 370 | void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr) | ||
| 371 | { | ||
| 372 | inject_abt(vcpu, true, addr); | ||
| 373 | } | ||
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h index 105d1f79909a..022305b38c27 100644 --- a/arch/arm/kvm/trace.h +++ b/arch/arm/kvm/trace.h | |||
| @@ -64,6 +64,51 @@ TRACE_EVENT(kvm_irq_line, | |||
| 64 | __entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level) | 64 | __entry->type, __entry->vcpu_idx, __entry->irq_num, __entry->level) |
| 65 | ); | 65 | ); |
| 66 | 66 | ||
| 67 | /* Architecturally implementation defined CP15 register access */ | ||
| 68 | TRACE_EVENT(kvm_emulate_cp15_imp, | ||
| 69 | TP_PROTO(unsigned long Op1, unsigned long Rt1, unsigned long CRn, | ||
| 70 | unsigned long CRm, unsigned long Op2, bool is_write), | ||
| 71 | TP_ARGS(Op1, Rt1, CRn, CRm, Op2, is_write), | ||
| 72 | |||
| 73 | TP_STRUCT__entry( | ||
| 74 | __field( unsigned int, Op1 ) | ||
| 75 | __field( unsigned int, Rt1 ) | ||
| 76 | __field( unsigned int, CRn ) | ||
| 77 | __field( unsigned int, CRm ) | ||
| 78 | __field( unsigned int, Op2 ) | ||
| 79 | __field( bool, is_write ) | ||
| 80 | ), | ||
| 81 | |||
| 82 | TP_fast_assign( | ||
| 83 | __entry->is_write = is_write; | ||
| 84 | __entry->Op1 = Op1; | ||
| 85 | __entry->Rt1 = Rt1; | ||
| 86 | __entry->CRn = CRn; | ||
| 87 | __entry->CRm = CRm; | ||
| 88 | __entry->Op2 = Op2; | ||
| 89 | ), | ||
| 90 | |||
| 91 | TP_printk("Implementation defined CP15: %s\tp15, %u, r%u, c%u, c%u, %u", | ||
| 92 | (__entry->is_write) ? "mcr" : "mrc", | ||
| 93 | __entry->Op1, __entry->Rt1, __entry->CRn, | ||
| 94 | __entry->CRm, __entry->Op2) | ||
| 95 | ); | ||
| 96 | |||
| 97 | TRACE_EVENT(kvm_wfi, | ||
| 98 | TP_PROTO(unsigned long vcpu_pc), | ||
| 99 | TP_ARGS(vcpu_pc), | ||
| 100 | |||
| 101 | TP_STRUCT__entry( | ||
| 102 | __field( unsigned long, vcpu_pc ) | ||
| 103 | ), | ||
| 104 | |||
| 105 | TP_fast_assign( | ||
| 106 | __entry->vcpu_pc = vcpu_pc; | ||
| 107 | ), | ||
| 108 | |||
| 109 | TP_printk("guest executed wfi at: 0x%08lx", __entry->vcpu_pc) | ||
| 110 | ); | ||
| 111 | |||
| 67 | TRACE_EVENT(kvm_unmap_hva, | 112 | TRACE_EVENT(kvm_unmap_hva, |
| 68 | TP_PROTO(unsigned long hva), | 113 | TP_PROTO(unsigned long hva), |
| 69 | TP_ARGS(hva), | 114 | TP_ARGS(hva), |
| @@ -112,6 +157,26 @@ TRACE_EVENT(kvm_set_spte_hva, | |||
| 112 | TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva) | 157 | TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva) |
| 113 | ); | 158 | ); |
| 114 | 159 | ||
| 160 | TRACE_EVENT(kvm_hvc, | ||
| 161 | TP_PROTO(unsigned long vcpu_pc, unsigned long r0, unsigned long imm), | ||
| 162 | TP_ARGS(vcpu_pc, r0, imm), | ||
| 163 | |||
| 164 | TP_STRUCT__entry( | ||
| 165 | __field( unsigned long, vcpu_pc ) | ||
| 166 | __field( unsigned long, r0 ) | ||
| 167 | __field( unsigned long, imm ) | ||
| 168 | ), | ||
| 169 | |||
| 170 | TP_fast_assign( | ||
| 171 | __entry->vcpu_pc = vcpu_pc; | ||
| 172 | __entry->r0 = r0; | ||
| 173 | __entry->imm = imm; | ||
| 174 | ), | ||
| 175 | |||
| 176 | TP_printk("HVC at 0x%08lx (r0: 0x%08lx, imm: 0x%lx", | ||
| 177 | __entry->vcpu_pc, __entry->r0, __entry->imm) | ||
| 178 | ); | ||
| 179 | |||
| 115 | #endif /* _TRACE_KVM_H */ | 180 | #endif /* _TRACE_KVM_H */ |
| 116 | 181 | ||
| 117 | #undef TRACE_INCLUDE_PATH | 182 | #undef TRACE_INCLUDE_PATH |
