diff options
author | Andre Przywara <andre.przywara@arm.com> | 2018-07-05 11:48:23 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2019-02-19 16:05:40 -0500 |
commit | 84135d3d18da2ff17d3ad1a609b2818cc3049552 (patch) | |
tree | c72a908ddb0d63d73e186273e3b12c0f180ea9c2 /virt/kvm | |
parent | 09838de943d4c0ee75a99cd7665940705ab8dcea (diff) |
KVM: arm/arm64: consolidate arch timer trap handlers
At the moment we have separate system register emulation handlers for
each timer register. Actually they are quite similar, and we rely on
kvm_arm_timer_[gs]et_reg() for the actual emulation anyways, so let's
just merge all of those handlers into one function, which just marshalls
the arguments and then hands off to a set of common accessors.
This makes extending the emulation to include EL2 timers much easier.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
[Fixed 32-bit VM breakage and reduced to reworking existing code]
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
[Fixed 32bit host, general cleanup]
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt/kvm')
-rw-r--r-- | virt/kvm/arm/arch_timer.c | 130 |
1 files changed, 113 insertions, 17 deletions
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 4986028d9829..f7d377448438 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <clocksource/arm_arch_timer.h> | 26 | #include <clocksource/arm_arch_timer.h> |
27 | #include <asm/arch_timer.h> | 27 | #include <asm/arch_timer.h> |
28 | #include <asm/kvm_emulate.h> | ||
28 | #include <asm/kvm_hyp.h> | 29 | #include <asm/kvm_hyp.h> |
29 | 30 | ||
30 | #include <kvm/arm_vgic.h> | 31 | #include <kvm/arm_vgic.h> |
@@ -52,6 +53,13 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx); | |||
52 | static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level, | 53 | static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level, |
53 | struct arch_timer_context *timer_ctx); | 54 | struct arch_timer_context *timer_ctx); |
54 | static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx); | 55 | static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx); |
56 | static void kvm_arm_timer_write(struct kvm_vcpu *vcpu, | ||
57 | struct arch_timer_context *timer, | ||
58 | enum kvm_arch_timer_regs treg, | ||
59 | u64 val); | ||
60 | static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu, | ||
61 | struct arch_timer_context *timer, | ||
62 | enum kvm_arch_timer_regs treg); | ||
55 | 63 | ||
56 | u64 kvm_phys_timer_read(void) | 64 | u64 kvm_phys_timer_read(void) |
57 | { | 65 | { |
@@ -628,24 +636,25 @@ static void kvm_timer_init_interrupt(void *info) | |||
628 | 636 | ||
629 | int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) | 637 | int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) |
630 | { | 638 | { |
631 | struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); | ||
632 | struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); | ||
633 | |||
634 | switch (regid) { | 639 | switch (regid) { |
635 | case KVM_REG_ARM_TIMER_CTL: | 640 | case KVM_REG_ARM_TIMER_CTL: |
636 | vtimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT; | 641 | kvm_arm_timer_write(vcpu, |
642 | vcpu_vtimer(vcpu), TIMER_REG_CTL, value); | ||
637 | break; | 643 | break; |
638 | case KVM_REG_ARM_TIMER_CNT: | 644 | case KVM_REG_ARM_TIMER_CNT: |
639 | update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value); | 645 | update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value); |
640 | break; | 646 | break; |
641 | case KVM_REG_ARM_TIMER_CVAL: | 647 | case KVM_REG_ARM_TIMER_CVAL: |
642 | vtimer->cnt_cval = value; | 648 | kvm_arm_timer_write(vcpu, |
649 | vcpu_vtimer(vcpu), TIMER_REG_CVAL, value); | ||
643 | break; | 650 | break; |
644 | case KVM_REG_ARM_PTIMER_CTL: | 651 | case KVM_REG_ARM_PTIMER_CTL: |
645 | ptimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT; | 652 | kvm_arm_timer_write(vcpu, |
653 | vcpu_ptimer(vcpu), TIMER_REG_CTL, value); | ||
646 | break; | 654 | break; |
647 | case KVM_REG_ARM_PTIMER_CVAL: | 655 | case KVM_REG_ARM_PTIMER_CVAL: |
648 | ptimer->cnt_cval = value; | 656 | kvm_arm_timer_write(vcpu, |
657 | vcpu_ptimer(vcpu), TIMER_REG_CVAL, value); | ||
649 | break; | 658 | break; |
650 | 659 | ||
651 | default: | 660 | default: |
@@ -672,26 +681,113 @@ static u64 read_timer_ctl(struct arch_timer_context *timer) | |||
672 | 681 | ||
673 | u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) | 682 | u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) |
674 | { | 683 | { |
675 | struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); | ||
676 | struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); | ||
677 | |||
678 | switch (regid) { | 684 | switch (regid) { |
679 | case KVM_REG_ARM_TIMER_CTL: | 685 | case KVM_REG_ARM_TIMER_CTL: |
680 | return read_timer_ctl(vtimer); | 686 | return kvm_arm_timer_read(vcpu, |
687 | vcpu_vtimer(vcpu), TIMER_REG_CTL); | ||
681 | case KVM_REG_ARM_TIMER_CNT: | 688 | case KVM_REG_ARM_TIMER_CNT: |
682 | return kvm_phys_timer_read() - vtimer->cntvoff; | 689 | return kvm_arm_timer_read(vcpu, |
690 | vcpu_vtimer(vcpu), TIMER_REG_CNT); | ||
683 | case KVM_REG_ARM_TIMER_CVAL: | 691 | case KVM_REG_ARM_TIMER_CVAL: |
684 | return vtimer->cnt_cval; | 692 | return kvm_arm_timer_read(vcpu, |
693 | vcpu_vtimer(vcpu), TIMER_REG_CVAL); | ||
685 | case KVM_REG_ARM_PTIMER_CTL: | 694 | case KVM_REG_ARM_PTIMER_CTL: |
686 | return read_timer_ctl(ptimer); | 695 | return kvm_arm_timer_read(vcpu, |
687 | case KVM_REG_ARM_PTIMER_CVAL: | 696 | vcpu_ptimer(vcpu), TIMER_REG_CTL); |
688 | return ptimer->cnt_cval; | ||
689 | case KVM_REG_ARM_PTIMER_CNT: | 697 | case KVM_REG_ARM_PTIMER_CNT: |
690 | return kvm_phys_timer_read(); | 698 | return kvm_arm_timer_read(vcpu, |
699 | vcpu_vtimer(vcpu), TIMER_REG_CNT); | ||
700 | case KVM_REG_ARM_PTIMER_CVAL: | ||
701 | return kvm_arm_timer_read(vcpu, | ||
702 | vcpu_ptimer(vcpu), TIMER_REG_CVAL); | ||
691 | } | 703 | } |
692 | return (u64)-1; | 704 | return (u64)-1; |
693 | } | 705 | } |
694 | 706 | ||
707 | static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu, | ||
708 | struct arch_timer_context *timer, | ||
709 | enum kvm_arch_timer_regs treg) | ||
710 | { | ||
711 | u64 val; | ||
712 | |||
713 | switch (treg) { | ||
714 | case TIMER_REG_TVAL: | ||
715 | val = kvm_phys_timer_read() - timer->cntvoff - timer->cnt_cval; | ||
716 | break; | ||
717 | |||
718 | case TIMER_REG_CTL: | ||
719 | val = read_timer_ctl(timer); | ||
720 | break; | ||
721 | |||
722 | case TIMER_REG_CVAL: | ||
723 | val = timer->cnt_cval; | ||
724 | break; | ||
725 | |||
726 | case TIMER_REG_CNT: | ||
727 | val = kvm_phys_timer_read() - timer->cntvoff; | ||
728 | break; | ||
729 | |||
730 | default: | ||
731 | BUG(); | ||
732 | } | ||
733 | |||
734 | return val; | ||
735 | } | ||
736 | |||
737 | u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu, | ||
738 | enum kvm_arch_timers tmr, | ||
739 | enum kvm_arch_timer_regs treg) | ||
740 | { | ||
741 | u64 val; | ||
742 | |||
743 | preempt_disable(); | ||
744 | kvm_timer_vcpu_put(vcpu); | ||
745 | |||
746 | val = kvm_arm_timer_read(vcpu, vcpu_get_timer(vcpu, tmr), treg); | ||
747 | |||
748 | kvm_timer_vcpu_load(vcpu); | ||
749 | preempt_enable(); | ||
750 | |||
751 | return val; | ||
752 | } | ||
753 | |||
754 | static void kvm_arm_timer_write(struct kvm_vcpu *vcpu, | ||
755 | struct arch_timer_context *timer, | ||
756 | enum kvm_arch_timer_regs treg, | ||
757 | u64 val) | ||
758 | { | ||
759 | switch (treg) { | ||
760 | case TIMER_REG_TVAL: | ||
761 | timer->cnt_cval = val - kvm_phys_timer_read() - timer->cntvoff; | ||
762 | break; | ||
763 | |||
764 | case TIMER_REG_CTL: | ||
765 | timer->cnt_ctl = val & ~ARCH_TIMER_CTRL_IT_STAT; | ||
766 | break; | ||
767 | |||
768 | case TIMER_REG_CVAL: | ||
769 | timer->cnt_cval = val; | ||
770 | break; | ||
771 | |||
772 | default: | ||
773 | BUG(); | ||
774 | } | ||
775 | } | ||
776 | |||
777 | void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu, | ||
778 | enum kvm_arch_timers tmr, | ||
779 | enum kvm_arch_timer_regs treg, | ||
780 | u64 val) | ||
781 | { | ||
782 | preempt_disable(); | ||
783 | kvm_timer_vcpu_put(vcpu); | ||
784 | |||
785 | kvm_arm_timer_write(vcpu, vcpu_get_timer(vcpu, tmr), treg, val); | ||
786 | |||
787 | kvm_timer_vcpu_load(vcpu); | ||
788 | preempt_enable(); | ||
789 | } | ||
790 | |||
695 | static int kvm_timer_starting_cpu(unsigned int cpu) | 791 | static int kvm_timer_starting_cpu(unsigned int cpu) |
696 | { | 792 | { |
697 | kvm_timer_init_interrupt(NULL); | 793 | kvm_timer_init_interrupt(NULL); |