diff --git a/hypervisor/arch/x86/guest/nested.c b/hypervisor/arch/x86/guest/nested.c index 8a1d23e3a..d710b5405 100644 --- a/hypervisor/arch/x86/guest/nested.c +++ b/hypervisor/arch/x86/guest/nested.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -220,3 +221,43 @@ int32_t read_vmx_msr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val) *val = v; return err; } + +void nested_vmx_result(enum VMXResult result, int error_number) +{ + uint64_t rflags = exec_vmread(VMX_GUEST_RFLAGS); + + /* ISDM: section 30.2 CONVENTIONS */ + rflags &= ~(RFLAGS_C | RFLAGS_P | RFLAGS_A | RFLAGS_Z | RFLAGS_S | RFLAGS_O); + + if (result == VMfailValid) { + rflags |= RFLAGS_Z; + exec_vmwrite(VMX_INSTR_ERROR, error_number); + } else if (result == VMfailInvalid) { + rflags |= RFLAGS_C; + } else { + /* VMsucceed, do nothing */ + } + + if (result != VMsucceed) { + pr_err("VMX failed: %d/%d", result, error_number); + } + + exec_vmwrite(VMX_GUEST_RFLAGS, rflags); +} + +/* + * @pre vcpu != NULL + */ +int32_t vmxon_vmexit_handler(struct acrn_vcpu *vcpu) +{ + /* Will do permission check in next patch */ + if (is_nvmx_configured(vcpu->vm)) { + vcpu->arch.nested.vmxon = true; + + nested_vmx_result(VMsucceed, 0); + } else { + vcpu_inject_ud(vcpu); + } + + return 0; +} diff --git a/hypervisor/arch/x86/guest/vmexit.c b/hypervisor/arch/x86/guest/vmexit.c index c62e136e2..0c8ed839b 100644 --- a/hypervisor/arch/x86/guest/vmexit.c +++ b/hypervisor/arch/x86/guest/vmexit.c @@ -94,8 +94,14 @@ static const struct vm_exit_dispatch dispatch_table[NR_VMX_EXIT_REASONS] = { .handler = undefined_vmexit_handler}, [VMX_EXIT_REASON_VMXOFF] = { .handler = undefined_vmexit_handler}, +#ifndef CONFIG_NVMX_ENABLED [VMX_EXIT_REASON_VMXON] = { .handler = undefined_vmexit_handler}, +#else + [VMX_EXIT_REASON_VMXON] = { + .handler = vmxon_vmexit_handler, + .need_exit_qualification = 1}, +#endif [VMX_EXIT_REASON_CR_ACCESS] = { .handler = cr_access_vmexit_handler, .need_exit_qualification = 1}, @@ -460,10 +466,8 @@ static int32_t loadiwkey_vmexit_handler(struct acrn_vcpu *vcpu) return 0; } -/* vmexit handler for just injecting a #UD exception - * - * ACRN doesn't support nested virtualization, the following VMExit will inject #UD - * VMCLEAR/VMLAUNCH/VMPTRST/VMREAD/VMRESUME/VMWRITE/VMXOFF/VMXON. +/* + * vmexit handler for just injecting a #UD exception * ACRN doesn't enable VMFUNC, VMFUNC treated as undefined. */ static int32_t undefined_vmexit_handler(struct acrn_vcpu *vcpu) diff --git a/hypervisor/include/arch/x86/asm/cpu.h b/hypervisor/include/arch/x86/asm/cpu.h index a1b4d806c..79bd41af0 100644 --- a/hypervisor/include/arch/x86/asm/cpu.h +++ b/hypervisor/include/arch/x86/asm/cpu.h @@ -133,7 +133,11 @@ #define EFER_LMA 0x00000400U /* Long mode active (R) */ #define RFLAGS_C (1U<<0U) +#define RFLAGS_P (1U<<2U) +#define RFLAGS_A (1U<<4U) #define RFLAGS_Z (1U<<6U) +#define RFLAGS_S (1U<<7U) +#define RFLAGS_O (1U<<11U) #define RFLAGS_AC (1U<<18U) /* CPU clock frequencies (FSB) */ diff --git a/hypervisor/include/arch/x86/asm/guest/nested.h b/hypervisor/include/arch/x86/asm/guest/nested.h index 930ba99cc..d85ffc072 100644 --- a/hypervisor/include/arch/x86/asm/guest/nested.h +++ b/hypervisor/include/arch/x86/asm/guest/nested.h @@ -51,11 +51,25 @@ union value_64 { */ #define VMCS12_REVISION_ID 0x15407E12U +enum VMXResult { + VMsucceed, + VMfailValid, + VMfailInvalid, +}; +void nested_vmx_result(enum VMXResult, int error_number); +int32_t vmxon_vmexit_handler(struct acrn_vcpu *vcpu); + #ifdef CONFIG_NVMX_ENABLED +struct acrn_nested { + bool vmxon; /* To indicate if vCPU entered VMX operation */ +} __aligned(PAGE_SIZE); + bool is_vmx_msr(uint32_t msr); void init_vmx_msrs(struct acrn_vcpu *vcpu); int32_t read_vmx_msr(__unused struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val); #else +struct acrn_nested {}; + static inline bool is_vmx_msr(__unused uint32_t msr) { /* diff --git a/hypervisor/include/arch/x86/asm/guest/vcpu.h b/hypervisor/include/arch/x86/asm/guest/vcpu.h index 42216eeb6..0f29dd9e6 100644 --- a/hypervisor/include/arch/x86/asm/guest/vcpu.h +++ b/hypervisor/include/arch/x86/asm/guest/vcpu.h @@ -219,6 +219,9 @@ struct acrn_vcpu_arch { /* vmcs region for this vcpu, MUST be 4KB-aligned */ uint8_t vmcs[PAGE_SIZE]; + /* context for nested virtualization, 4KB-aligned */ + struct acrn_nested nested; + /* MSR bitmap region for this vcpu, MUST be 4-Kbyte aligned */ uint8_t msr_bitmap[PAGE_SIZE];