aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2014-04-24 05:27:13 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2014-07-11 07:57:44 -0400
commit72564016aae45f42e488f926bc803f9a2e1c771c (patch)
tree80184b0510031158803482b803fd5d6ee1fb258e
parent0c557ed4983b7abe152212b5b1726c2a789b2c61 (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.h2
-rw-r--r--arch/arm64/include/asm/kvm_coproc.h3
-rw-r--r--arch/arm64/include/asm/kvm_host.h13
-rw-r--r--arch/arm64/kvm/handle_exit.c4
-rw-r--r--arch/arm64/kvm/sys_regs.c133
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
41int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run); 41int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
42int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run); 42int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
43int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
43int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run); 44int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
44int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run); 45int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
45int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run); 46int 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
152struct kvm_vm_stat { 157struct 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 */
498static 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
604int 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
610static 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 */
618static 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
652static 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 */
650int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run) 682static 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, &params); 715 if (!emulate_cp(vcpu, &params, target_specific, nr_specific))
716 goto out;
717 if (!emulate_cp(vcpu, &params, global, nr_global))
718 goto out;
680 719
720 unhandled_cp_access(vcpu, &params);
721
722out:
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 */
696int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run) 738static 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, &params); 757 if (!emulate_cp(vcpu, &params, target_specific, nr_specific))
758 return 1;
759 if (!emulate_cp(vcpu, &params, global, nr_global))
760 return 1;
761
762 unhandled_cp_access(vcpu, &params);
712 return 1; 763 return 1;
713} 764}
714 765
766int 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
777int 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
788int 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
795int 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
715static int emulate_sys_reg(struct kvm_vcpu *vcpu, 802static int emulate_sys_reg(struct kvm_vcpu *vcpu,
716 const struct sys_reg_params *params) 803 const struct sys_reg_params *params)
717{ 804{