On 06/08/21 12:07, Hikaru Nishida wrote:
+#if defined(CONFIG_KVM_VIRT_SUSPEND_TIMING) || \ + defined(CONFIG_KVM_VIRT_SUSPEND_TIMING_GUEST) +#define VIRT_SUSPEND_TIMING_VECTOR 0xec +#endif
No need to use a new vector. You can rename the existing MSR_KVM_ASYNC_PF_INT to MSR_KVM_HYPERVISOR_CALLBACK_INT or something like that, and add the code to sysvec_kvm_asyncpf_interrupt.
+static void kvm_make_suspend_time_interrupt(struct kvm_vcpu *vcpu) +{ + kvm_queue_interrupt(vcpu, VIRT_SUSPEND_TIMING_VECTOR, false); + kvm_make_request(KVM_REQ_EVENT, vcpu); +}
Use kvm_apic_set_irq which will inject the interrupt as soon as possible, so you do not even need to check kvm_vcpu_ready_for_interrupt_injection.
+#ifdef CONFIG_KVM_VIRT_SUSPEND_TIMING + if (kvm->suspend_injection_requested && + kvm_vcpu_ready_for_interrupt_injection(vcpu)) { + kvm_write_suspend_time(kvm); + kvm_make_suspend_time_interrupt(vcpu); + kvm->suspend_injection_requested = false; + } +#endif
Do not read variables in vcpu_run; There is KVM_REQ_* if you need to do work in the vCPU run loop.
+ mutex_lock(&kvm_lock); + list_for_each_entry(kvm, &vm_list, vm_list) { + if (!(kvm->arch.msr_suspend_time & KVM_MSR_ENABLED)) + continue; + + kvm_for_each_vcpu(i, vcpu, kvm) + vcpu->arch.tsc_offset_adjustment -= adj; + + /* + * Move the offset of kvm_clock here as if it is stopped + * during the suspension. + */ + kvm->arch.kvmclock_offset -= suspend_time_ns; + + /* suspend_time is accumulated per VM. */ + kvm->suspend_time_ns += suspend_time_ns; + kvm->suspend_injection_requested = true; + /* + * This adjustment will be reflected to the struct provided + * from the guest via MSR_KVM_HOST_SUSPEND_TIME before + * the notification interrupt is injected. + */ + } + mutex_unlock(&kvm_lock); +}
As pointed out by Thomas, this should be a work item. Paolo