diff options
author | Avi Kivity <avi@qumranet.com> | 2007-10-25 10:52:32 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 11:01:20 -0500 |
commit | b93463aa59d67b21b4921e30bd5c5dcc7c35ffbd (patch) | |
tree | 8de9a2789624d27155d8a94c93a23c01f473fea7 /arch/x86/kvm/lapic.c | |
parent | b209749f528488c4c0d20a42c0fbcbf49e6933b3 (diff) |
KVM: Accelerated apic support
This adds a mechanism for exposing the virtual apic tpr to the guest, and a
protocol for letting the guest update the tpr without causing a vmexit if
conditions allow (e.g. there is no interrupt pending with a higher priority
than the new tpr).
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 50c3f3a8dd3d..e7513bb98af1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -815,7 +815,8 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) | |||
815 | 815 | ||
816 | if (!apic) | 816 | if (!apic) |
817 | return; | 817 | return; |
818 | apic_set_tpr(apic, ((cr8 & 0x0f) << 4)); | 818 | apic_set_tpr(apic, ((cr8 & 0x0f) << 4) |
819 | | (apic_get_reg(apic, APIC_TASKPRI) & 4)); | ||
819 | } | 820 | } |
820 | 821 | ||
821 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) | 822 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) |
@@ -1104,3 +1105,51 @@ void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) | |||
1104 | hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); | 1105 | hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); |
1105 | } | 1106 | } |
1106 | EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer); | 1107 | EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer); |
1108 | |||
1109 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) | ||
1110 | { | ||
1111 | u32 data; | ||
1112 | void *vapic; | ||
1113 | |||
1114 | if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr) | ||
1115 | return; | ||
1116 | |||
1117 | vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); | ||
1118 | data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)); | ||
1119 | kunmap_atomic(vapic, KM_USER0); | ||
1120 | |||
1121 | apic_set_tpr(vcpu->arch.apic, data & 0xff); | ||
1122 | } | ||
1123 | |||
1124 | void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) | ||
1125 | { | ||
1126 | u32 data, tpr; | ||
1127 | int max_irr, max_isr; | ||
1128 | struct kvm_lapic *apic; | ||
1129 | void *vapic; | ||
1130 | |||
1131 | if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr) | ||
1132 | return; | ||
1133 | |||
1134 | apic = vcpu->arch.apic; | ||
1135 | tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff; | ||
1136 | max_irr = apic_find_highest_irr(apic); | ||
1137 | if (max_irr < 0) | ||
1138 | max_irr = 0; | ||
1139 | max_isr = apic_find_highest_isr(apic); | ||
1140 | if (max_isr < 0) | ||
1141 | max_isr = 0; | ||
1142 | data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); | ||
1143 | |||
1144 | vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); | ||
1145 | *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data; | ||
1146 | kunmap_atomic(vapic, KM_USER0); | ||
1147 | } | ||
1148 | |||
1149 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) | ||
1150 | { | ||
1151 | if (!irqchip_in_kernel(vcpu->kvm)) | ||
1152 | return; | ||
1153 | |||
1154 | vcpu->arch.apic->vapic_addr = vapic_addr; | ||
1155 | } | ||