diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2014-04-24 05:27:13 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-07-11 07:57:44 -0400 |
commit | 72564016aae45f42e488f926bc803f9a2e1c771c (patch) | |
tree | 80184b0510031158803482b803fd5d6ee1fb258e | |
parent | 0c557ed4983b7abe152212b5b1726c2a789b2c61 (diff) |
arm64: KVM: common infrastructure for handling AArch32 CP14/CP15
As we're about to trap a bunch of CP14 registers, let's rework
the CP15 handling so it can be generalized and work with multiple
tables.
Reviewed-by: Anup Patel <anup.patel@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | arch/arm64/include/asm/kvm_asm.h | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/kvm_coproc.h | 3 | ||||
-rw-r--r-- | arch/arm64/include/asm/kvm_host.h | 13 | ||||
-rw-r--r-- | arch/arm64/kvm/handle_exit.c | 4 | ||||
-rw-r--r-- | arch/arm64/kvm/sys_regs.c | 133 |
5 files changed, 124 insertions, 31 deletions
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 660f75c48bbb..69027ded5006 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h | |||
@@ -95,7 +95,7 @@ | |||
95 | #define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */ | 95 | #define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */ |
96 | #define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */ | 96 | #define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */ |
97 | #define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */ | 97 | #define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */ |
98 | #define NR_CP15_REGS (NR_SYS_REGS * 2) | 98 | #define NR_COPRO_REGS (NR_SYS_REGS * 2) |
99 | 99 | ||
100 | #define ARM_EXCEPTION_IRQ 0 | 100 | #define ARM_EXCEPTION_IRQ 0 |
101 | #define ARM_EXCEPTION_TRAP 1 | 101 | #define ARM_EXCEPTION_TRAP 1 |
diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h index 9a59301cd014..0b52377a6c11 100644 --- a/arch/arm64/include/asm/kvm_coproc.h +++ b/arch/arm64/include/asm/kvm_coproc.h | |||
@@ -39,7 +39,8 @@ void kvm_register_target_sys_reg_table(unsigned int target, | |||
39 | struct kvm_sys_reg_target_table *table); | 39 | struct kvm_sys_reg_target_table *table); |
40 | 40 | ||
41 | int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); | 41 | int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); |
42 | int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); | 42 | int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run); |
43 | int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run); | ||
43 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); | 44 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); |
44 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); | 45 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); |
45 | int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run); | 46 | int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run); |
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8e410f761918..79812be4f25f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h | |||
@@ -86,7 +86,7 @@ struct kvm_cpu_context { | |||
86 | struct kvm_regs gp_regs; | 86 | struct kvm_regs gp_regs; |
87 | union { | 87 | union { |
88 | u64 sys_regs[NR_SYS_REGS]; | 88 | u64 sys_regs[NR_SYS_REGS]; |
89 | u32 cp15[NR_CP15_REGS]; | 89 | u32 copro[NR_COPRO_REGS]; |
90 | }; | 90 | }; |
91 | }; | 91 | }; |
92 | 92 | ||
@@ -141,12 +141,17 @@ struct kvm_vcpu_arch { | |||
141 | 141 | ||
142 | #define vcpu_gp_regs(v) (&(v)->arch.ctxt.gp_regs) | 142 | #define vcpu_gp_regs(v) (&(v)->arch.ctxt.gp_regs) |
143 | #define vcpu_sys_reg(v,r) ((v)->arch.ctxt.sys_regs[(r)]) | 143 | #define vcpu_sys_reg(v,r) ((v)->arch.ctxt.sys_regs[(r)]) |
144 | #define vcpu_cp15(v,r) ((v)->arch.ctxt.cp15[(r)]) | 144 | /* |
145 | * CP14 and CP15 live in the same array, as they are backed by the | ||
146 | * same system registers. | ||
147 | */ | ||
148 | #define vcpu_cp14(v,r) ((v)->arch.ctxt.copro[(r)]) | ||
149 | #define vcpu_cp15(v,r) ((v)->arch.ctxt.copro[(r)]) | ||
145 | 150 | ||
146 | #ifdef CONFIG_CPU_BIG_ENDIAN | 151 | #ifdef CONFIG_CPU_BIG_ENDIAN |
147 | #define vcpu_cp15_64_low(v,r) ((v)->arch.ctxt.cp15[((r) + 1)]) | 152 | #define vcpu_cp15_64_low(v,r) ((v)->arch.ctxt.copro[((r) + 1)]) |
148 | #else | 153 | #else |
149 | #define vcpu_cp15_64_low(v,r) ((v)->arch.ctxt.cp15[((r) + 0)]) | 154 | #define vcpu_cp15_64_low(v,r) ((v)->arch.ctxt.copro[((r) + 0)]) |
150 | #endif | 155 | #endif |
151 | 156 | ||
152 | struct kvm_vm_stat { | 157 | struct kvm_vm_stat { |
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 182415e1a952..e28be510380c 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c | |||
@@ -73,9 +73,9 @@ static exit_handle_fn arm_exit_handlers[] = { | |||
73 | [ESR_EL2_EC_WFI] = kvm_handle_wfx, | 73 | [ESR_EL2_EC_WFI] = kvm_handle_wfx, |
74 | [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, | 74 | [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, |
75 | [ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64, | 75 | [ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64, |
76 | [ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_access, | 76 | [ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_32, |
77 | [ESR_EL2_EC_CP14_LS] = kvm_handle_cp14_load_store, | 77 | [ESR_EL2_EC_CP14_LS] = kvm_handle_cp14_load_store, |
78 | [ESR_EL2_EC_CP14_64] = kvm_handle_cp14_access, | 78 | [ESR_EL2_EC_CP14_64] = kvm_handle_cp14_64, |
79 | [ESR_EL2_EC_HVC32] = handle_hvc, | 79 | [ESR_EL2_EC_HVC32] = handle_hvc, |
80 | [ESR_EL2_EC_SMC32] = handle_smc, | 80 | [ESR_EL2_EC_SMC32] = handle_smc, |
81 | [ESR_EL2_EC_HVC64] = handle_hvc, | 81 | [ESR_EL2_EC_HVC64] = handle_hvc, |
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index d53ce430b178..266afd972ad3 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c | |||
@@ -494,6 +494,10 @@ static const struct sys_reg_desc sys_reg_descs[] = { | |||
494 | NULL, reset_val, FPEXC32_EL2, 0x70 }, | 494 | NULL, reset_val, FPEXC32_EL2, 0x70 }, |
495 | }; | 495 | }; |
496 | 496 | ||
497 | /* Trapped cp14 registers */ | ||
498 | static const struct sys_reg_desc cp14_regs[] = { | ||
499 | }; | ||
500 | |||
497 | /* | 501 | /* |
498 | * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding, | 502 | * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding, |
499 | * depending on the way they are accessed (as a 32bit or a 64bit | 503 | * depending on the way they are accessed (as a 32bit or a 64bit |
@@ -601,26 +605,29 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
601 | return 1; | 605 | return 1; |
602 | } | 606 | } |
603 | 607 | ||
604 | int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run) | 608 | /* |
605 | { | 609 | * emulate_cp -- tries to match a sys_reg access in a handling table, and |
606 | kvm_inject_undefined(vcpu); | 610 | * call the corresponding trap handler. |
607 | return 1; | 611 | * |
608 | } | 612 | * @params: pointer to the descriptor of the access |
609 | 613 | * @table: array of trap descriptors | |
610 | static void emulate_cp15(struct kvm_vcpu *vcpu, | 614 | * @num: size of the trap descriptor array |
611 | const struct sys_reg_params *params) | 615 | * |
616 | * Return 0 if the access has been handled, and -1 if not. | ||
617 | */ | ||
618 | static int emulate_cp(struct kvm_vcpu *vcpu, | ||
619 | const struct sys_reg_params *params, | ||
620 | const struct sys_reg_desc *table, | ||
621 | size_t num) | ||
612 | { | 622 | { |
613 | size_t num; | 623 | const struct sys_reg_desc *r; |
614 | const struct sys_reg_desc *table, *r; | ||
615 | 624 | ||
616 | table = get_target_table(vcpu->arch.target, false, &num); | 625 | if (!table) |
626 | return -1; /* Not handled */ | ||
617 | 627 | ||
618 | /* Search target-specific then generic table. */ | ||
619 | r = find_reg(params, table, num); | 628 | r = find_reg(params, table, num); |
620 | if (!r) | ||
621 | r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs)); | ||
622 | 629 | ||
623 | if (likely(r)) { | 630 | if (r) { |
624 | /* | 631 | /* |
625 | * Not having an accessor means that we have | 632 | * Not having an accessor means that we have |
626 | * configured a trap that we don't know how to | 633 | * configured a trap that we don't know how to |
@@ -632,22 +639,51 @@ static void emulate_cp15(struct kvm_vcpu *vcpu, | |||
632 | if (likely(r->access(vcpu, params, r))) { | 639 | if (likely(r->access(vcpu, params, r))) { |
633 | /* Skip instruction, since it was emulated */ | 640 | /* Skip instruction, since it was emulated */ |
634 | kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); | 641 | kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); |
635 | return; | ||
636 | } | 642 | } |
637 | /* If access function fails, it should complain. */ | 643 | |
644 | /* Handled */ | ||
645 | return 0; | ||
638 | } | 646 | } |
639 | 647 | ||
640 | kvm_err("Unsupported guest CP15 access at: %08lx\n", *vcpu_pc(vcpu)); | 648 | /* Not handled */ |
649 | return -1; | ||
650 | } | ||
651 | |||
652 | static void unhandled_cp_access(struct kvm_vcpu *vcpu, | ||
653 | struct sys_reg_params *params) | ||
654 | { | ||
655 | u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu); | ||
656 | int cp; | ||
657 | |||
658 | switch(hsr_ec) { | ||
659 | case ESR_EL2_EC_CP15_32: | ||
660 | case ESR_EL2_EC_CP15_64: | ||
661 | cp = 15; | ||
662 | break; | ||
663 | case ESR_EL2_EC_CP14_MR: | ||
664 | case ESR_EL2_EC_CP14_64: | ||
665 | cp = 14; | ||
666 | break; | ||
667 | default: | ||
668 | WARN_ON((cp = -1)); | ||
669 | } | ||
670 | |||
671 | kvm_err("Unsupported guest CP%d access at: %08lx\n", | ||
672 | cp, *vcpu_pc(vcpu)); | ||
641 | print_sys_reg_instr(params); | 673 | print_sys_reg_instr(params); |
642 | kvm_inject_undefined(vcpu); | 674 | kvm_inject_undefined(vcpu); |
643 | } | 675 | } |
644 | 676 | ||
645 | /** | 677 | /** |
646 | * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access | 678 | * kvm_handle_cp_64 -- handles a mrrc/mcrr trap on a guest CP15 access |
647 | * @vcpu: The VCPU pointer | 679 | * @vcpu: The VCPU pointer |
648 | * @run: The kvm_run struct | 680 | * @run: The kvm_run struct |
649 | */ | 681 | */ |
650 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | 682 | static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, |
683 | const struct sys_reg_desc *global, | ||
684 | size_t nr_global, | ||
685 | const struct sys_reg_desc *target_specific, | ||
686 | size_t nr_specific) | ||
651 | { | 687 | { |
652 | struct sys_reg_params params; | 688 | struct sys_reg_params params; |
653 | u32 hsr = kvm_vcpu_get_hsr(vcpu); | 689 | u32 hsr = kvm_vcpu_get_hsr(vcpu); |
@@ -676,8 +712,14 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
676 | *vcpu_reg(vcpu, params.Rt) = val; | 712 | *vcpu_reg(vcpu, params.Rt) = val; |
677 | } | 713 | } |
678 | 714 | ||
679 | emulate_cp15(vcpu, ¶ms); | 715 | if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) |
716 | goto out; | ||
717 | if (!emulate_cp(vcpu, ¶ms, global, nr_global)) | ||
718 | goto out; | ||
680 | 719 | ||
720 | unhandled_cp_access(vcpu, ¶ms); | ||
721 | |||
722 | out: | ||
681 | /* Do the opposite hack for the read side */ | 723 | /* Do the opposite hack for the read side */ |
682 | if (!params.is_write) { | 724 | if (!params.is_write) { |
683 | u64 val = *vcpu_reg(vcpu, params.Rt); | 725 | u64 val = *vcpu_reg(vcpu, params.Rt); |
@@ -693,7 +735,11 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
693 | * @vcpu: The VCPU pointer | 735 | * @vcpu: The VCPU pointer |
694 | * @run: The kvm_run struct | 736 | * @run: The kvm_run struct |
695 | */ | 737 | */ |
696 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) | 738 | static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, |
739 | const struct sys_reg_desc *global, | ||
740 | size_t nr_global, | ||
741 | const struct sys_reg_desc *target_specific, | ||
742 | size_t nr_specific) | ||
697 | { | 743 | { |
698 | struct sys_reg_params params; | 744 | struct sys_reg_params params; |
699 | u32 hsr = kvm_vcpu_get_hsr(vcpu); | 745 | u32 hsr = kvm_vcpu_get_hsr(vcpu); |
@@ -708,10 +754,51 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
708 | params.Op1 = (hsr >> 14) & 0x7; | 754 | params.Op1 = (hsr >> 14) & 0x7; |
709 | params.Op2 = (hsr >> 17) & 0x7; | 755 | params.Op2 = (hsr >> 17) & 0x7; |
710 | 756 | ||
711 | emulate_cp15(vcpu, ¶ms); | 757 | if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) |
758 | return 1; | ||
759 | if (!emulate_cp(vcpu, ¶ms, global, nr_global)) | ||
760 | return 1; | ||
761 | |||
762 | unhandled_cp_access(vcpu, ¶ms); | ||
712 | return 1; | 763 | return 1; |
713 | } | 764 | } |
714 | 765 | ||
766 | int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
767 | { | ||
768 | const struct sys_reg_desc *target_specific; | ||
769 | size_t num; | ||
770 | |||
771 | target_specific = get_target_table(vcpu->arch.target, false, &num); | ||
772 | return kvm_handle_cp_64(vcpu, | ||
773 | cp15_regs, ARRAY_SIZE(cp15_regs), | ||
774 | target_specific, num); | ||
775 | } | ||
776 | |||
777 | int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
778 | { | ||
779 | const struct sys_reg_desc *target_specific; | ||
780 | size_t num; | ||
781 | |||
782 | target_specific = get_target_table(vcpu->arch.target, false, &num); | ||
783 | return kvm_handle_cp_32(vcpu, | ||
784 | cp15_regs, ARRAY_SIZE(cp15_regs), | ||
785 | target_specific, num); | ||
786 | } | ||
787 | |||
788 | int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
789 | { | ||
790 | return kvm_handle_cp_64(vcpu, | ||
791 | cp14_regs, ARRAY_SIZE(cp14_regs), | ||
792 | NULL, 0); | ||
793 | } | ||
794 | |||
795 | int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run) | ||
796 | { | ||
797 | return kvm_handle_cp_32(vcpu, | ||
798 | cp14_regs, ARRAY_SIZE(cp14_regs), | ||
799 | NULL, 0); | ||
800 | } | ||
801 | |||
715 | static int emulate_sys_reg(struct kvm_vcpu *vcpu, | 802 | static int emulate_sys_reg(struct kvm_vcpu *vcpu, |
716 | const struct sys_reg_params *params) | 803 | const struct sys_reg_params *params) |
717 | { | 804 | { |