[RFC V3 4/6] KVM: x86: do lazy_tscdeadline init and exit

From: Wang Jianchao
Date: Sun Jul 16 2023 - 22:36:10 EST


This patch only add the code of init and exit of lazy_tscdeadline.
The initialization of lazy tscdeadline is only invoked when guest
write specific msr and does following things:
- map the GVA of struct kvm_lazy_tscdeadline to HVA of kernel side.
- get one reference of the page

We assume the page of kvm_lazy_tscdeadline of guest won't be changed.
If the vcpu is reboot in normal or abnormal way, exit path will put
the page and unmmap it. This is archived by covering following path:
- clear msr of lazy_tscdeadline, for normal reboot case
- lapic reset, for abnormal reboot case
- vcpu destroy, for the case that guest is gone

Signed-off-by: Li Shujin <arkinjob@xxxxxxxxxxx>
Signed-off-by: Wang Jianchao <jianchwa@xxxxxxxxxxx>
---
arch/x86/include/asm/kvm_host.h | 3 +++
arch/x86/kvm/lapic.c | 45 +++++++++++++++++++++++++++++++++++++++++
arch/x86/kvm/lapic.h | 3 +++
arch/x86/kvm/x86.c | 13 +++++++++++-
4 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 439e4a7..b036874 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -715,6 +715,9 @@ struct kvm_queued_exception {

struct kvm_host_lazy_tscdeadline {
u64 msr_val;
+ u64 cached_armed;
+ struct page *page;
+ struct kvm_lazy_tscdeadline *guest;
};

struct kvm_vcpu_arch {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 113ca96..71da41e 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1676,6 +1676,50 @@ static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
return 0;
}

+int kvm_lazy_tscdeadline_init(struct kvm_vcpu *vcpu)
+{
+ struct kvm_memory_slot *slot;
+ struct kvm_memslots *slots;
+ struct page *page;
+ kvm_pfn_t pfn;
+ gfn_t gfn;
+ void *hva;
+ u64 msr;
+
+ slots = kvm_memslots(vcpu->kvm);
+ msr = vcpu->arch.lazy_tscdeadline.msr_val;
+ gfn = msr >> PAGE_SHIFT;
+ slot = __gfn_to_memslot(slots, gfn);
+ pfn = gfn_to_pfn_memslot(slot, gfn);
+
+ if (!pfn_valid(pfn))
+ return -EINVAL;
+
+ page = pfn_to_page(pfn);
+ hva = kmap(page);
+ if (!hva)
+ return -EFAULT;
+
+ hva += offset_in_page(msr - KVM_MSR_ENABLED);
+ get_page(page);
+ vcpu->arch.lazy_tscdeadline.page = page;
+ vcpu->arch.lazy_tscdeadline.guest = hva;
+
+ return 0;
+}
+
+void kvm_lazy_tscdeadline_exit(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.lazy_tscdeadline.page) {
+ kunmap((void *)vcpu->arch.lazy_tscdeadline.guest);
+ put_page(vcpu->arch.lazy_tscdeadline.page);
+ }
+
+ vcpu->arch.lazy_tscdeadline.cached_armed = 0;
+ vcpu->arch.lazy_tscdeadline.page = NULL;
+ vcpu->arch.lazy_tscdeadline.guest = NULL;
+}
+
static void update_divide_count(struct kvm_lapic *apic)
{
u32 tmp1, tmp2, tdcr;
@@ -2652,6 +2696,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)

/* Stop the timer in case it's a reset to an active apic */
hrtimer_cancel(&apic->lapic_timer.timer);
+ kvm_lazy_tscdeadline_exit(vcpu);

/* The xAPIC ID is set at RESET even if the APIC was already enabled. */
if (!init_event)
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 0a0ea4b..51b9d5b 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -278,4 +278,7 @@ static inline u8 kvm_xapic_id(struct kvm_lapic *apic)
return kvm_lapic_get_reg(apic, APIC_ID) >> 24;
}

+int kvm_lazy_tscdeadline_init(struct kvm_vcpu *vcpu);
+void kvm_lazy_tscdeadline_exit(struct kvm_vcpu *vcpu);
+
#endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index dbbae8f..7225fc9 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3878,7 +3878,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (!guest_pv_has(vcpu, KVM_FEATURE_LAZY_TSCDEADLINE))
return 1;

- vcpu->arch.lazy_tscdeadline.msr_val = data;
+ if (!(data & KVM_MSR_ENABLED)) {
+ kvm_lazy_tscdeadline_exit(vcpu);
+ } else {
+ kvm_lazy_tscdeadline_exit(vcpu);
+ vcpu->arch.lazy_tscdeadline.msr_val = data;
+ if (kvm_lazy_tscdeadline_init(vcpu)) {
+ vcpu->arch.lazy_tscdeadline.msr_val = 0;
+ return 1;
+ }
+ }

break;
case MSR_IA32_MCG_CTL:
@@ -11964,6 +11973,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)

kvmclock_reset(vcpu);

+ kvm_lazy_tscdeadline_exit(vcpu);
+
static_call(kvm_x86_vcpu_free)(vcpu);

kmem_cache_free(x86_emulator_cache, vcpu->arch.emulate_ctxt);
--
2.7.4