|
7 | 7 | #include <asm/mmu_context.h>
|
8 | 8 |
|
9 | 9 | #include "cpuid.h"
|
| 10 | +#include "evmcs.h" |
10 | 11 | #include "hyperv.h"
|
11 | 12 | #include "mmu.h"
|
12 | 13 | #include "nested.h"
|
@@ -5101,27 +5102,49 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
|
5101 | 5102 | if (!nested_vmx_check_permission(vcpu))
|
5102 | 5103 | return 1;
|
5103 | 5104 |
|
5104 |
| - /* |
5105 |
| - * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA, |
5106 |
| - * any VMREAD sets the ALU flags for VMfailInvalid. |
5107 |
| - */ |
5108 |
| - if (vmx->nested.current_vmptr == INVALID_GPA || |
5109 |
| - (is_guest_mode(vcpu) && |
5110 |
| - get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA)) |
5111 |
| - return nested_vmx_failInvalid(vcpu); |
5112 |
| - |
5113 | 5105 | /* Decode instruction info and find the field to read */
|
5114 | 5106 | field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
|
5115 | 5107 |
|
5116 |
| - offset = get_vmcs12_field_offset(field); |
5117 |
| - if (offset < 0) |
5118 |
| - return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); |
| 5108 | + if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) { |
| 5109 | + /* |
| 5110 | + * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA, |
| 5111 | + * any VMREAD sets the ALU flags for VMfailInvalid. |
| 5112 | + */ |
| 5113 | + if (vmx->nested.current_vmptr == INVALID_GPA || |
| 5114 | + (is_guest_mode(vcpu) && |
| 5115 | + get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA)) |
| 5116 | + return nested_vmx_failInvalid(vcpu); |
5119 | 5117 |
|
5120 |
| - if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field)) |
5121 |
| - copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12); |
| 5118 | + offset = get_vmcs12_field_offset(field); |
| 5119 | + if (offset < 0) |
| 5120 | + return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); |
| 5121 | + |
| 5122 | + if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field)) |
| 5123 | + copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12); |
| 5124 | + |
| 5125 | + /* Read the field, zero-extended to a u64 value */ |
| 5126 | + value = vmcs12_read_any(vmcs12, field, offset); |
| 5127 | + } else { |
| 5128 | + /* |
| 5129 | + * Hyper-V TLFS (as of 6.0b) explicitly states, that while an |
| 5130 | + * enlightened VMCS is active VMREAD/VMWRITE instructions are |
| 5131 | + * unsupported. Unfortunately, certain versions of Windows 11 |
| 5132 | + * don't comply with this requirement which is not enforced in |
| 5133 | + * genuine Hyper-V. Allow VMREAD from an enlightened VMCS as a |
| 5134 | + * workaround, as misbehaving guests will panic on VM-Fail. |
| 5135 | + * Note, enlightened VMCS is incompatible with shadow VMCS so |
| 5136 | + * all VMREADs from L2 should go to L1. |
| 5137 | + */ |
| 5138 | + if (WARN_ON_ONCE(is_guest_mode(vcpu))) |
| 5139 | + return nested_vmx_failInvalid(vcpu); |
5122 | 5140 |
|
5123 |
| - /* Read the field, zero-extended to a u64 value */ |
5124 |
| - value = vmcs12_read_any(vmcs12, field, offset); |
| 5141 | + offset = evmcs_field_offset(field, NULL); |
| 5142 | + if (offset < 0) |
| 5143 | + return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); |
| 5144 | + |
| 5145 | + /* Read the field, zero-extended to a u64 value */ |
| 5146 | + value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset); |
| 5147 | + } |
5125 | 5148 |
|
5126 | 5149 | /*
|
5127 | 5150 | * Now copy part of this value to register or memory, as requested.
|
|
0 commit comments