aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/kvm_host.h3
-rw-r--r--arch/arm64/kvm/hyp/switch.c6
-rw-r--r--arch/arm64/kvm/pmu.c39
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
592void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr); 592void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr);
593void kvm_clr_pmu_events(u32 clr); 593void kvm_clr_pmu_events(u32 clr);
594
595void __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt);
596bool __pmu_switch_to_guest(struct kvm_cpu_context *host_ctxt);
594#else 597#else
595static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {} 598static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {}
596static inline void kvm_clr_pmu_events(u32 clr) {} 599static 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 */
51bool __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 */
71void __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}