Skip to content
This repository was archived by the owner on Jan 28, 2023. It is now read-only.

Fix incorrect VMX_ENTRY_CONTROLS loading. #225

Merged
merged 1 commit into from
Aug 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Fix incorrect VMX_ENTRY_CONTROLS loading.
There exists some issue when programming VMX_ENTRY_CONTROLS and GUEST_EFER:
- ENTRY_CONTROL_LONG_MODE_GUEST has no chance to clear.
- vmwrite_efer() called by vmwrite_cr() will check vmx field before
vmx field gets updated, and itself will also program VMX_ENTRY_CONTROLS,
which may cause incorrect VMX_ENTRY_CONTROLS programmed.
- vmx filed entry_ctls_base and entry_ctls are loaded from vmcs in:
vcpu_create()->vcpu_prepare()->fill_common_vmcs()->load_vmcs_common().
When vmwrite_cr() and vmwrite_efer() write a dirty VMX_ENTRY_CONTROLS,
it only updates vmx field entry_ctls, but it compares with value of
entry_ctls_base for dirty check, which may cause reduntant or miss
programming to VMX_ENTRY_CONTROLS.

Below changes are made:
- Add the missing clear of ENTRY_CONTROL_LONG_MODE_GUEST.
- Move vmwrite_efer() to last of vmwrite_cr() after VMX_ENTRY_CONTROLS
  programmed.
- Remove unnecessary entry_ctls_base in vmx field.

Signed-off-by: Colin Xu <[email protected]>
  • Loading branch information
coxuintel committed Aug 7, 2019
commit 834ffc191d8f78c468f36187ac278a9c32aa0a1d
3 changes: 1 addition & 2 deletions core/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,7 @@ void load_vmcs_common(struct vcpu_t *vcpu)

vmx(vcpu, exc_bitmap) = vmx(vcpu, exc_bitmap_base) = vmread(
vcpu, VMX_EXCEPTION_BITMAP);
vmx(vcpu, entry_ctls) = vmx(vcpu, entry_ctls_base) = vmread(
vcpu, VMX_ENTRY_CONTROLS);
vmx(vcpu, entry_ctls) = vmread(vcpu, VMX_ENTRY_CONTROLS);
vmx(vcpu, exit_ctls) = vmx(vcpu, exit_ctls_base) = vmread(
vcpu, VMX_EXIT_CONTROLS);

Expand Down
1 change: 0 additions & 1 deletion core/include/vcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ struct vcpu_vmx_data {
uint32_t pin_ctls_base;
uint32_t pcpu_ctls_base;
uint32_t scpu_ctls_base;
uint32_t entry_ctls_base;
uint32_t exc_bitmap_base;
uint32_t exit_ctls_base;

Expand Down
20 changes: 10 additions & 10 deletions core/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1900,7 +1900,7 @@ static void vmwrite_cr(struct vcpu_t *vcpu)
struct vcpu_state_t *state = vcpu->state;
struct per_cpu_data *cpu = current_cpu_data();

uint32_t entry_ctls = vmx(vcpu, entry_ctls_base);
uint32_t entry_ctls = vmx(vcpu, entry_ctls);
uint32_t pcpu_ctls = vmx(vcpu, pcpu_ctls_base);
uint32_t scpu_ctls = vmx(vcpu, scpu_ctls_base);
uint32_t exc_bitmap = vmx(vcpu, exc_bitmap_base);
Expand Down Expand Up @@ -2017,16 +2017,10 @@ static void vmwrite_cr(struct vcpu_t *vcpu)
if ((state->_cr4 & CR4_PAE) && (state->_cr0 & CR0_PG) &&
(state->_cr0 & CR0_PE)) {
entry_ctls |= ENTRY_CONTROL_LOAD_EFER;
vmx(vcpu, entry_ctls) |= ENTRY_CONTROL_LOAD_EFER;
} else {
entry_ctls &= ~ENTRY_CONTROL_LOAD_EFER;
vmx(vcpu, entry_ctls) &= ~ENTRY_CONTROL_LOAD_EFER;
}

vmwrite_efer(vcpu);
if (state->_efer & IA32_EFER_LMA) {
entry_ctls |= ENTRY_CONTROL_LONG_MODE_GUEST;
}
if (pcpu_ctls != vmx(vcpu, pcpu_ctls)) {
vmx(vcpu, pcpu_ctls) = pcpu_ctls;
vcpu->pcpu_ctls_dirty = 1;
Expand All @@ -2041,6 +2035,8 @@ static void vmwrite_cr(struct vcpu_t *vcpu)
if (entry_ctls != vmx(vcpu, entry_ctls)) {
vmwrite(vcpu, VMX_ENTRY_CONTROLS, vmx(vcpu, entry_ctls) = entry_ctls);
}

vmwrite_efer(vcpu);
}

static void vcpu_enter_fpu_state(struct vcpu_t *vcpu)
Expand Down Expand Up @@ -3489,14 +3485,14 @@ static int handle_msr_read(struct vcpu_t *vcpu, uint32_t msr, uint64_t *val)
static void vmwrite_efer(struct vcpu_t *vcpu)
{
struct vcpu_state_t *state = vcpu->state;
uint32_t entry_ctls = vmx(vcpu, entry_ctls);

if ((state->_cr0 & CR0_PG) && (state->_efer & IA32_EFER_LME)) {
state->_efer |= IA32_EFER_LMA;

vmwrite(vcpu, VMX_ENTRY_CONTROLS, vmread(vcpu, VMX_ENTRY_CONTROLS) |
ENTRY_CONTROL_LONG_MODE_GUEST);
entry_ctls |= ENTRY_CONTROL_LONG_MODE_GUEST;
} else {
state->_efer &= ~IA32_EFER_LMA;
entry_ctls &= ~ENTRY_CONTROL_LONG_MODE_GUEST;
}

if (vmx(vcpu, entry_ctls) & ENTRY_CONTROL_LOAD_EFER) {
Expand All @@ -3508,6 +3504,10 @@ static void vmwrite_efer(struct vcpu_t *vcpu)

vmwrite(vcpu, GUEST_EFER, guest_efer);
}

if (entry_ctls != vmx(vcpu, entry_ctls)) {
vmwrite(vcpu, VMX_ENTRY_CONTROLS, vmx(vcpu, entry_ctls) = entry_ctls);
}
}

static int misc_msr_write(struct vcpu_t *vcpu, uint32_t msr, uint64_t val)
Expand Down