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 | } | ||
