diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 0c87966f2a..3d3bfce1b4 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -210,6 +210,7 @@ static void __init vmx_display_features(void) P(cpu_has_vmx_virt_exceptions, "Virtualisation Exceptions"); P(cpu_has_vmx_pml, "Page Modification Logging"); P(cpu_has_vmx_tsc_scaling, "TSC Scaling"); + P(cpu_has_vmx_virt_spec_ctrl, "Virtualize SPEC_CTRL"); #undef P if ( !printed ) @@ -370,7 +371,7 @@ static int vmx_init_vmcs_config(bool bsp) if ( _vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS ) { - uint64_t opt = 0; + uint64_t opt = TERTIARY_EXEC_VIRT_SPEC_CTRL; _vmx_tertiary_exec_control = adjust_vmx_controls2( "Tertiary Exec Control", 0, opt, @@ -1379,6 +1380,12 @@ static int construct_vmcs(struct vcpu *v) if ( cpu_has_vmx_tsc_scaling ) __vmwrite(TSC_MULTIPLIER, d->arch.hvm.tsc_scaling_ratio); + if ( cpu_has_vmx_virt_spec_ctrl ) + { + __vmwrite(SPEC_CTRL_MASK, 0); + __vmwrite(SPEC_CTRL_SHADOW, 0); + } + /* will update HOST & GUEST_CR3 as reqd */ paging_update_paging_modes(v); @@ -2089,6 +2096,9 @@ void vmcs_dump_vcpu(struct vcpu *v) if ( v->arch.hvm.vmx.secondary_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY ) printk("InterruptStatus = %04x\n", vmr16(GUEST_INTR_STATUS)); + if ( cpu_has_vmx_virt_spec_ctrl ) + printk("SPEC_CTRL mask = 0x%016lx shadow = 0x%016lx\n", + vmr(SPEC_CTRL_MASK), vmr(SPEC_CTRL_SHADOW)); printk("*** Host State ***\n"); printk("RIP = 0x%016lx (%ps) RSP = 0x%016lx\n", diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index a7f9fefa8c..f15baef8ad 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -618,23 +618,28 @@ static void vmx_cpuid_policy_changed(struct vcpu *v) /* * We can safely pass MSR_SPEC_CTRL through to the guest, even if STIBP * isn't enumerated in hardware, as SPEC_CTRL_STIBP is ignored. + * + * If VMX_VIRT_SPEC_CTRL is available, it is activated by default and the + * guest MSR_SPEC_CTRL value lives in the VMCS. Otherwise, it lives in + * the MSR load/save list. */ if ( cp->feat.ibrsb ) { vmx_clear_msr_intercept(v, MSR_SPEC_CTRL, VMX_MSR_RW); - rc = vmx_add_guest_msr(v, MSR_SPEC_CTRL, 0); - if ( rc ) - goto out; + if ( !cpu_has_vmx_virt_spec_ctrl ) + { + rc = vmx_add_guest_msr(v, MSR_SPEC_CTRL, 0); + if ( rc ) + goto out; + } } else { vmx_set_msr_intercept(v, MSR_SPEC_CTRL, VMX_MSR_RW); - rc = vmx_del_msr(v, MSR_SPEC_CTRL, VMX_MSR_GUEST); - if ( rc && rc != -ESRCH ) - goto out; - rc = 0; /* Tolerate -ESRCH */ + if ( !cpu_has_vmx_virt_spec_ctrl ) + vmx_del_msr(v, MSR_SPEC_CTRL, VMX_MSR_GUEST); } /* MSR_PRED_CMD is safe to pass through if the guest knows about it. */ @@ -2444,9 +2449,14 @@ static uint64_t vmx_get_reg(struct vcpu *v, unsigned int reg) uint64_t val = 0; int rc; + /* Logic which doesn't require remote VMCS acquisition. */ switch ( reg ) { case MSR_SPEC_CTRL: + if ( cpu_has_vmx_virt_spec_ctrl ) + /* Guest value in VMCS - fetched below. */ + break; + rc = vmx_read_guest_msr(v, reg, &val); if ( rc ) { @@ -2455,13 +2465,26 @@ static uint64_t vmx_get_reg(struct vcpu *v, unsigned int reg) domain_crash(d); } return val; + } + + /* Logic which maybe requires remote VMCS acquisition. */ + vmx_vmcs_enter(v); + switch ( reg ) + { + case MSR_SPEC_CTRL: + ASSERT(cpu_has_vmx_virt_spec_ctrl); + __vmread(SPEC_CTRL_SHADOW, &val); + break; default: printk(XENLOG_G_ERR "%s(%pv, 0x%08x) Bad register\n", __func__, v, reg); domain_crash(d); - return 0; + break; } + vmx_vmcs_exit(v); + + return val; } static void vmx_set_reg(struct vcpu *v, unsigned int reg, uint64_t val) @@ -2469,9 +2492,14 @@ static void vmx_set_reg(struct vcpu *v, unsigned int reg, uint64_t val) struct domain *d = v->domain; int rc; + /* Logic which doesn't require remote VMCS acquisition. */ switch ( reg ) { case MSR_SPEC_CTRL: + if ( cpu_has_vmx_virt_spec_ctrl ) + /* Guest value in VMCS - set below. */ + break; + rc = vmx_write_guest_msr(v, reg, val); if ( rc ) { @@ -2480,12 +2508,23 @@ static void vmx_set_reg(struct vcpu *v, unsigned int reg, uint64_t val) domain_crash(d); } break; + } + + /* Logic which maybe requires remote VMCS acquisition. */ + vmx_vmcs_enter(v); + switch ( reg ) + { + case MSR_SPEC_CTRL: + ASSERT(cpu_has_vmx_virt_spec_ctrl); + __vmwrite(SPEC_CTRL_SHADOW, val); + break; default: printk(XENLOG_G_ERR "%s(%pv, 0x%08x, 0x%016"PRIx64") Bad register\n", __func__, v, reg, val); domain_crash(d); } + vmx_vmcs_exit(v); } static struct hvm_function_table __initdata vmx_function_table = { diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index 9b246b802b..2b4de99ed4 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -279,6 +279,9 @@ extern u32 vmx_secondary_exec_control; #define TERTIARY_EXEC_VIRT_SPEC_CTRL BIT(7, UL) extern uint64_t vmx_tertiary_exec_control; +#define cpu_has_vmx_virt_spec_ctrl \ + (vmx_tertiary_exec_control & TERTIARY_EXEC_VIRT_SPEC_CTRL) + #define VMX_EPT_EXEC_ONLY_SUPPORTED 0x00000001 #define VMX_EPT_WALK_LENGTH_4_SUPPORTED 0x00000040 #define VMX_EPT_MEMORY_TYPE_UC 0x00000100 @@ -436,6 +439,8 @@ enum vmcs_field { XSS_EXIT_BITMAP = 0x0000202c, TSC_MULTIPLIER = 0x00002032, TERTIARY_VM_EXEC_CONTROL = 0x00002034, + SPEC_CTRL_MASK = 0x0000204a, + SPEC_CTRL_SHADOW = 0x0000204c, GUEST_PHYSICAL_ADDRESS = 0x00002400, VMCS_LINK_POINTER = 0x00002800, GUEST_IA32_DEBUGCTL = 0x00002802, diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h index c37b9e771b..a7ad9bd189 100644 --- a/xen/include/asm-x86/msr.h +++ b/xen/include/asm-x86/msr.h @@ -289,8 +289,11 @@ struct vcpu_msrs * For PV guests, this holds the guest kernel value. It is accessed on * every entry/exit path. * - * For VT-x guests, the guest value is held in the MSR guest load/save - * list. + * For VT-x guests, one of two situations exist: + * + * - If hardware supports virtualized MSR_SPEC_CTRL, it is active by + * default and the guest value lives in the VMCS. + * - Otherwise, the guest value is held in the MSR load/save list. * * For SVM, the guest value lives in the VMCB, and hardware saves/restores * the host value automatically. However, guests run with the OR of the