@@ -335,6 +335,10 @@ struct nested_vmx {
unsigned long l1_arch_cr3;
/* L2 must run next, and mustn't decide to exit to L1. */
bool nested_run_pending;
+ /* true if last exit was of L2, and had a valid idt_vectoring_info */
+ bool valid_idt_vectoring_info;
+ /* These are saved if valid_idt_vectoring_info */
+ u32 vm_exit_instruction_len, idt_vectoring_error_code;
};
struct vcpu_vmx {
@@ -5384,6 +5388,22 @@ static void vmx_cancel_injection(struct
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);
}
+static void nested_handle_valid_idt_vectoring_info(struct vcpu_vmx *vmx)
+{
+ int irq = vmx->idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
+ int type = vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
+ int errCodeValid = vmx->idt_vectoring_info &
+ VECTORING_INFO_DELIVER_CODE_MASK;
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ irq | type | INTR_INFO_VALID_MASK | errCodeValid);
+
+ vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+ vmx->nested.vm_exit_instruction_len);
+ if (errCodeValid)
+ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ vmx->nested.idt_vectoring_error_code);
+}
+
static inline void sync_cached_regs_to_vmcs(struct kvm_vcpu *vcpu)
{
if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
@@ -5405,6 +5425,9 @@ static void vmx_vcpu_run(struct kvm_vcpu
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ if (is_guest_mode(vcpu) && vmx->nested.valid_idt_vectoring_info)
+ nested_handle_valid_idt_vectoring_info(vmx);
+
/* Record the guest's net vcpu time for enforced NMI injections. */
if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
vmx->entry_time = ktime_get();
@@ -5525,6 +5548,15 @@ static void vmx_vcpu_run(struct kvm_vcpu
vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ vmx->nested.valid_idt_vectoring_info = is_guest_mode(vcpu) &&
+ (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
+ if (vmx->nested.valid_idt_vectoring_info) {
+ vmx->nested.vm_exit_instruction_len =
+ vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+ vmx->nested.idt_vectoring_error_code =
+ vmcs_read32(IDT_VECTORING_ERROR_CODE);
+ }
+
asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
vmx->launched = 1;