diff options
-rw-r--r-- | arch/arm64/include/asm/kvm_host.h | 3 | ||||
-rw-r--r-- | arch/arm64/kvm/hyp/switch.c | 6 | ||||
-rw-r--r-- | arch/arm64/kvm/pmu.c | 39 |
3 files changed, 48 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 655ad08edc3a..645d74c705d6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h | |||
@@ -591,6 +591,9 @@ static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) | |||
591 | 591 | ||
592 | void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr); | 592 | void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr); |
593 | void kvm_clr_pmu_events(u32 clr); | 593 | void kvm_clr_pmu_events(u32 clr); |
594 | |||
595 | void __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt); | ||
596 | bool __pmu_switch_to_guest(struct kvm_cpu_context *host_ctxt); | ||
594 | #else | 597 | #else |
595 | static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {} | 598 | static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {} |
596 | static inline void kvm_clr_pmu_events(u32 clr) {} | 599 | static inline void kvm_clr_pmu_events(u32 clr) {} |
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 5444b9c6fb5c..22b4c335e0b2 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c | |||
@@ -566,6 +566,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu) | |||
566 | { | 566 | { |
567 | struct kvm_cpu_context *host_ctxt; | 567 | struct kvm_cpu_context *host_ctxt; |
568 | struct kvm_cpu_context *guest_ctxt; | 568 | struct kvm_cpu_context *guest_ctxt; |
569 | bool pmu_switch_needed; | ||
569 | u64 exit_code; | 570 | u64 exit_code; |
570 | 571 | ||
571 | /* | 572 | /* |
@@ -585,6 +586,8 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu) | |||
585 | host_ctxt->__hyp_running_vcpu = vcpu; | 586 | host_ctxt->__hyp_running_vcpu = vcpu; |
586 | guest_ctxt = &vcpu->arch.ctxt; | 587 | guest_ctxt = &vcpu->arch.ctxt; |
587 | 588 | ||
589 | pmu_switch_needed = __pmu_switch_to_guest(host_ctxt); | ||
590 | |||
588 | __sysreg_save_state_nvhe(host_ctxt); | 591 | __sysreg_save_state_nvhe(host_ctxt); |
589 | 592 | ||
590 | __activate_vm(kern_hyp_va(vcpu->kvm)); | 593 | __activate_vm(kern_hyp_va(vcpu->kvm)); |
@@ -631,6 +634,9 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu) | |||
631 | */ | 634 | */ |
632 | __debug_switch_to_host(vcpu); | 635 | __debug_switch_to_host(vcpu); |
633 | 636 | ||
637 | if (pmu_switch_needed) | ||
638 | __pmu_switch_to_host(host_ctxt); | ||
639 | |||
634 | /* Returning to host will clear PSR.I, remask PMR if needed */ | 640 | /* Returning to host will clear PSR.I, remask PMR if needed */ |
635 | if (system_uses_irq_prio_masking()) | 641 | if (system_uses_irq_prio_masking()) |
636 | gic_write_pmr(GIC_PRIO_IRQOFF); | 642 | gic_write_pmr(GIC_PRIO_IRQOFF); |
diff --git a/arch/arm64/kvm/pmu.c b/arch/arm64/kvm/pmu.c index 5414b134f99a..599e6d3f692e 100644 --- a/arch/arm64/kvm/pmu.c +++ b/arch/arm64/kvm/pmu.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | #include <linux/kvm_host.h> | 6 | #include <linux/kvm_host.h> |
7 | #include <linux/perf_event.h> | 7 | #include <linux/perf_event.h> |
8 | #include <asm/kvm_hyp.h> | ||
8 | 9 | ||
9 | /* | 10 | /* |
10 | * Given the exclude_{host,guest} attributes, determine if we are going | 11 | * Given the exclude_{host,guest} attributes, determine if we are going |
@@ -43,3 +44,41 @@ void kvm_clr_pmu_events(u32 clr) | |||
43 | ctx->pmu_events.events_host &= ~clr; | 44 | ctx->pmu_events.events_host &= ~clr; |
44 | ctx->pmu_events.events_guest &= ~clr; | 45 | ctx->pmu_events.events_guest &= ~clr; |
45 | } | 46 | } |
47 | |||
48 | /** | ||
49 | * Disable host events, enable guest events | ||
50 | */ | ||
51 | bool __hyp_text __pmu_switch_to_guest(struct kvm_cpu_context *host_ctxt) | ||
52 | { | ||
53 | struct kvm_host_data *host; | ||
54 | struct kvm_pmu_events *pmu; | ||
55 | |||
56 | host = container_of(host_ctxt, struct kvm_host_data, host_ctxt); | ||
57 | pmu = &host->pmu_events; | ||
58 | |||
59 | if (pmu->events_host) | ||
60 | write_sysreg(pmu->events_host, pmcntenclr_el0); | ||
61 | |||
62 | if (pmu->events_guest) | ||
63 | write_sysreg(pmu->events_guest, pmcntenset_el0); | ||
64 | |||
65 | return (pmu->events_host || pmu->events_guest); | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Disable guest events, enable host events | ||
70 | */ | ||
71 | void __hyp_text __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt) | ||
72 | { | ||
73 | struct kvm_host_data *host; | ||
74 | struct kvm_pmu_events *pmu; | ||
75 | |||
76 | host = container_of(host_ctxt, struct kvm_host_data, host_ctxt); | ||
77 | pmu = &host->pmu_events; | ||
78 | |||
79 | if (pmu->events_guest) | ||
80 | write_sysreg(pmu->events_guest, pmcntenclr_el0); | ||
81 | |||
82 | if (pmu->events_host) | ||
83 | write_sysreg(pmu->events_host, pmcntenset_el0); | ||
84 | } | ||