>@@ -2713,21 +2715,43 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf, > &_vmentry_control)) > return -EIO; > >- for (i = 0; i < ARRAY_SIZE(vmcs_entry_exit_pairs); i++) { >- u32 n_ctrl = vmcs_entry_exit_pairs[i].entry_control; >- u32 x_ctrl = vmcs_entry_exit_pairs[i].exit_control; >- >- if (!(_vmentry_control & n_ctrl) == !(_vmexit_control & x_ctrl)) >+ if (_vmexit_control & VM_EXIT_ACTIVATE_SECONDARY_CONTROLS) >+ _secondary_vmexit_control = >+ adjust_vmx_controls64(KVM_OPTIONAL_VMX_SECONDARY_VM_EXIT_CONTROLS, >+ MSR_IA32_VMX_EXIT_CTLS2); >+ >+ for (i = 0; i < ARRAY_SIZE(vmcs_entry_exit_triplets); i++) { >+ u32 n_ctrl = vmcs_entry_exit_triplets[i].entry_control; >+ u32 x_ctrl = vmcs_entry_exit_triplets[i].exit_control; >+ u64 x_ctrl_2 = vmcs_entry_exit_triplets[i].exit_2nd_control; >+ bool has_n = n_ctrl && ((_vmentry_control & n_ctrl) == n_ctrl); >+ bool has_x = x_ctrl && ((_vmexit_control & x_ctrl) == x_ctrl); >+ bool has_x_2 = x_ctrl_2 && ((_secondary_vmexit_control & x_ctrl_2) == x_ctrl_2); >+ >+ if (x_ctrl_2) { >+ /* Only activate secondary VM exit control bit should be set */ >+ if ((_vmexit_control & x_ctrl) == VM_EXIT_ACTIVATE_SECONDARY_CONTROLS) { >+ if (has_n == has_x_2) >+ continue; >+ } else { >+ /* The feature should not be supported in any control */ >+ if (!has_n && !has_x && !has_x_2) >+ continue; >+ } >+ } else if (has_n == has_x) { > continue; >+ } > >- pr_warn_once("Inconsistent VM-Entry/VM-Exit pair, entry = %x, exit = %x\n", >- _vmentry_control & n_ctrl, _vmexit_control & x_ctrl); >+ pr_warn_once("Inconsistent VM-Entry/VM-Exit triplet, entry = %x, exit = %x, secondary_exit = %llx\n", >+ _vmentry_control & n_ctrl, _vmexit_control & x_ctrl, >+ _secondary_vmexit_control & x_ctrl_2); > > if (error_on_inconsistent_vmcs_config) > return -EIO; > > _vmentry_control &= ~n_ctrl; > _vmexit_control &= ~x_ctrl; w/ patch 4, VM_EXIT_ACTIVATE_SECONDARY_CONTROLS is cleared if FRED fails in the consistent check. this means, all features in the secondary vm-exit controls are removed. it is overkill. I prefer to maintain a separate table for the secondary VM-exit controls: struct { u32 entry_control; u64 exit2_control; } const vmcs_entry_exit2_pairs[] = { { VM_ENTRY_LOAD_IA32_FRED, SECONDARY_VM_EXIT_SAVE_IA32_FRED | SECONDARY_VM_EXIT_LOAD_IA32_FRED}, }; for (i = 0; i < ARRAY_SIZE(vmcs_entry_exit2_pairs); i++) { ... } >+ _secondary_vmexit_control &= ~x_ctrl_2; > } > > rdmsrl(MSR_IA32_VMX_BASIC, basic_msr);