diff mbox series

[v4,3/8] VMX: tertiary execution control infrastructure

Message ID aa553449-888f-4e52-85b7-0bc0b7f010b4@suse.com (mailing list archive)
State New, archived
Headers show
Series x86emul: misc additions | expand

Commit Message

Jan Beulich Jan. 11, 2024, 9 a.m. UTC
This is a prereq to enabling the MSRLIST feature.

Note that the PROCBASED_CTLS3 MSR is different from other VMX feature
reporting MSRs, in that all 64 bits report allowed 1-settings.

vVMX code is left alone, though, for the time being.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v2: New.

Comments

Roger Pau Monné Feb. 1, 2024, 11:50 a.m. UTC | #1
On Thu, Jan 11, 2024 at 10:00:10AM +0100, Jan Beulich wrote:
> This is a prereq to enabling the MSRLIST feature.
> 
> Note that the PROCBASED_CTLS3 MSR is different from other VMX feature
> reporting MSRs, in that all 64 bits report allowed 1-settings.
> 
> vVMX code is left alone, though, for the time being.
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> ---
> v2: New.
> 
> --- a/xen/arch/x86/hvm/vmx/vmcs.c
> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
> @@ -164,6 +164,7 @@ static int cf_check parse_ept_param_runt
>  u32 vmx_pin_based_exec_control __read_mostly;
>  u32 vmx_cpu_based_exec_control __read_mostly;
>  u32 vmx_secondary_exec_control __read_mostly;
> +uint64_t vmx_tertiary_exec_control __read_mostly;
>  u32 vmx_vmexit_control __read_mostly;
>  u32 vmx_vmentry_control __read_mostly;
>  u64 vmx_ept_vpid_cap __read_mostly;
> @@ -228,10 +229,32 @@ static u32 adjust_vmx_controls(
>      return ctl;
>  }
>  
> -static bool cap_check(const char *name, u32 expected, u32 saw)
> +static uint64_t adjust_vmx_controls2(
> +    const char *name, uint64_t ctl_min, uint64_t ctl_opt, unsigned int msr,
> +    bool *mismatch)
> +{
> +    uint64_t vmx_msr, ctl = ctl_min | ctl_opt;
> +
> +    rdmsrl(msr, vmx_msr);
> +
> +    ctl &= vmx_msr; /* bit == 0 ==> must be zero */
> +
> +    /* Ensure minimum (required) set of control bits are supported. */
> +    if ( ctl_min & ~ctl )
> +    {
> +        *mismatch = true;
> +        printk("VMX: CPU%u has insufficient %s (%#lx; requires %#lx)\n",
> +               smp_processor_id(), name, ctl, ctl_min);
> +    }
> +
> +    return ctl;
> +}
> +
> +static bool cap_check(
> +    const char *name, unsigned long expected, unsigned long saw)
>  {
>      if ( saw != expected )
> -        printk("VMX %s: saw %#x expected %#x\n", name, saw, expected);
> +        printk("VMX %s: saw %#lx expected %#lx\n", name, saw, expected);
>      return saw != expected;
>  }
>  
> @@ -241,6 +264,7 @@ static int vmx_init_vmcs_config(bool bsp
>      u32 _vmx_pin_based_exec_control;
>      u32 _vmx_cpu_based_exec_control;
>      u32 _vmx_secondary_exec_control = 0;
> +    uint64_t _vmx_tertiary_exec_control = 0;
>      u64 _vmx_ept_vpid_cap = 0;
>      u64 _vmx_misc_cap = 0;
>      u32 _vmx_vmexit_control;
> @@ -274,7 +298,8 @@ static int vmx_init_vmcs_config(bool bsp
>      opt = (CPU_BASED_ACTIVATE_MSR_BITMAP |
>             CPU_BASED_TPR_SHADOW |
>             CPU_BASED_MONITOR_TRAP_FLAG |
> -           CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
> +           CPU_BASED_ACTIVATE_SECONDARY_CONTROLS |
> +           CPU_BASED_ACTIVATE_TERTIARY_CONTROLS);
>      _vmx_cpu_based_exec_control = adjust_vmx_controls(
>          "CPU-Based Exec Control", min, opt,
>          MSR_IA32_VMX_PROCBASED_CTLS, &mismatch);
> @@ -338,6 +363,15 @@ static int vmx_init_vmcs_config(bool bsp
>              MSR_IA32_VMX_PROCBASED_CTLS2, &mismatch);
>      }
>  
> +    if ( _vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS )
> +    {
> +        uint64_t opt = 0;
> +
> +        _vmx_tertiary_exec_control = adjust_vmx_controls2(
> +            "Tertiary Exec Control", 0, opt,
> +            MSR_IA32_VMX_PROCBASED_CTLS3, &mismatch);
> +    }
> +
>      /* The IA32_VMX_EPT_VPID_CAP MSR exists only when EPT or VPID available */
>      if ( _vmx_secondary_exec_control & (SECONDARY_EXEC_ENABLE_EPT |
>                                          SECONDARY_EXEC_ENABLE_VPID) )
> @@ -468,6 +502,7 @@ static int vmx_init_vmcs_config(bool bsp
>          vmx_pin_based_exec_control = _vmx_pin_based_exec_control;
>          vmx_cpu_based_exec_control = _vmx_cpu_based_exec_control;
>          vmx_secondary_exec_control = _vmx_secondary_exec_control;
> +        vmx_tertiary_exec_control  = _vmx_tertiary_exec_control;
>          vmx_ept_vpid_cap           = _vmx_ept_vpid_cap;
>          vmx_vmexit_control         = _vmx_vmexit_control;
>          vmx_vmentry_control        = _vmx_vmentry_control;
> @@ -503,6 +538,9 @@ static int vmx_init_vmcs_config(bool bsp
>              "Secondary Exec Control",
>              vmx_secondary_exec_control, _vmx_secondary_exec_control);
>          mismatch |= cap_check(
> +            "Tertiary Exec Control",
> +            vmx_tertiary_exec_control, _vmx_tertiary_exec_control);

I know it's done to match the surrounding style, but couldn't you move
the name parameter one line up, and then limit the call to two lines?

(I don't think it will compromise readability).

> +        mismatch |= cap_check(
>              "VMExit Control",
>              vmx_vmexit_control, _vmx_vmexit_control);
>          mismatch |= cap_check(
> @@ -1080,6 +1118,7 @@ static int construct_vmcs(struct vcpu *v
>          v->arch.hvm.vmx.exec_control |= CPU_BASED_RDTSC_EXITING;
>  
>      v->arch.hvm.vmx.secondary_exec_control = vmx_secondary_exec_control;
> +    v->arch.hvm.vmx.tertiary_exec_control  = vmx_tertiary_exec_control;
>  
>      /*
>       * Disable features which we don't want active by default:
> @@ -1134,6 +1173,10 @@ static int construct_vmcs(struct vcpu *v
>          __vmwrite(SECONDARY_VM_EXEC_CONTROL,
>                    v->arch.hvm.vmx.secondary_exec_control);
>  
> +    if ( cpu_has_vmx_tertiary_exec_control )
> +        __vmwrite(TERTIARY_VM_EXEC_CONTROL,
> +                  v->arch.hvm.vmx.tertiary_exec_control);
> +
>      /* MSR access bitmap. */
>      if ( cpu_has_vmx_msr_bitmap )
>      {
> @@ -2068,10 +2111,12 @@ void vmcs_dump_vcpu(struct vcpu *v)
>                 vmr(HOST_PERF_GLOBAL_CTRL));
>  
>      printk("*** Control State ***\n");
> -    printk("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
> +    printk("PinBased=%08x CPUBased=%08x\n",
>             vmr32(PIN_BASED_VM_EXEC_CONTROL),
> -           vmr32(CPU_BASED_VM_EXEC_CONTROL),
> -           vmr32(SECONDARY_VM_EXEC_CONTROL));
> +           vmr32(CPU_BASED_VM_EXEC_CONTROL));
> +    printk("SecondaryExec=%08x TertiaryExec=%08lx\n",

For consistency, shouldn't TertiaryExec use 016 instead of 08 (as it's
a 64bit filed).

> +           vmr32(SECONDARY_VM_EXEC_CONTROL),
> +           vmr(TERTIARY_VM_EXEC_CONTROL));
>      printk("EntryControls=%08x ExitControls=%08x\n", vmentry_ctl, vmexit_ctl);
>      printk("ExceptionBitmap=%08x PFECmask=%08x PFECmatch=%08x\n",
>             vmr32(EXCEPTION_BITMAP),
> --- a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
> +++ b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
> @@ -114,6 +114,7 @@ struct vmx_vcpu {
>      /* Cache of cpu execution control. */
>      u32                  exec_control;
>      u32                  secondary_exec_control;
> +    uint64_t             tertiary_exec_control;
>      u32                  exception_bitmap;
>  
>      uint64_t             shadow_gs;
> @@ -196,6 +197,7 @@ void vmx_vmcs_reload(struct vcpu *v);
>  #define CPU_BASED_RDTSC_EXITING               0x00001000U
>  #define CPU_BASED_CR3_LOAD_EXITING            0x00008000U
>  #define CPU_BASED_CR3_STORE_EXITING           0x00010000U
> +#define CPU_BASED_ACTIVATE_TERTIARY_CONTROLS  0x00020000U
>  #define CPU_BASED_CR8_LOAD_EXITING            0x00080000U
>  #define CPU_BASED_CR8_STORE_EXITING           0x00100000U
>  #define CPU_BASED_TPR_SHADOW                  0x00200000U
> @@ -260,6 +262,13 @@ extern u32 vmx_vmentry_control;
>  #define SECONDARY_EXEC_NOTIFY_VM_EXITING        0x80000000U
>  extern u32 vmx_secondary_exec_control;
>  
> +#define TERTIARY_EXEC_LOADIWKEY_EXITING         BIT(0, UL)
> +#define TERTIARY_EXEC_ENABLE_HLAT               BIT(1, UL)
> +#define TERTIARY_EXEC_EPT_PAGING_WRITE          BIT(2, UL)
> +#define TERTIARY_EXEC_GUEST_PAGING_VERIFY       BIT(3, UL)
> +#define TERTIARY_EXEC_IPI_VIRT                  BIT(4, UL)

While at it, my copy of the SDM also has:

#define TERTIARY_EXEC_VIRT_SPEC_CTRL               BIT(7, UL)

> +extern uint64_t vmx_tertiary_exec_control;
> +
>  #define VMX_EPT_EXEC_ONLY_SUPPORTED                         0x00000001
>  #define VMX_EPT_WALK_LENGTH_4_SUPPORTED                     0x00000040
>  #define VMX_EPT_MEMORY_TYPE_UC                              0x00000100
> @@ -295,6 +304,8 @@ extern u64 vmx_ept_vpid_cap;
>      (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_MSR_BITMAP)
>  #define cpu_has_vmx_secondary_exec_control \
>      (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
> +#define cpu_has_vmx_tertiary_exec_control \
> +    (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS)
>  #define cpu_has_vmx_ept \
>      (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT)
>  #define cpu_has_vmx_dt_exiting \
> @@ -422,6 +433,7 @@ enum vmcs_field {
>      VIRT_EXCEPTION_INFO             = 0x0000202a,
>      XSS_EXIT_BITMAP                 = 0x0000202c,
>      TSC_MULTIPLIER                  = 0x00002032,
> +    TERTIARY_VM_EXEC_CONTROL        = 0x00002034,
>      GUEST_PHYSICAL_ADDRESS          = 0x00002400,
>      VMCS_LINK_POINTER               = 0x00002800,
>      GUEST_IA32_DEBUGCTL             = 0x00002802,
> --- a/xen/arch/x86/include/asm/msr-index.h
> +++ b/xen/arch/x86/include/asm/msr-index.h
> @@ -347,6 +347,7 @@
>  #define MSR_IA32_VMX_TRUE_EXIT_CTLS             0x48f
>  #define MSR_IA32_VMX_TRUE_ENTRY_CTLS            0x490
>  #define MSR_IA32_VMX_VMFUNC                     0x491
> +#define MSR_IA32_VMX_PROCBASED_CTLS3            0x492

Shouldn't this be added above the "Legacy MSR constants in need of
cleanup.  No new MSRs below this comment." line?

>  
>  /* K7/K8 MSRs. Not complete. See the architecture manual for a more
>     complete list. */
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -760,6 +760,12 @@ void vmx_update_secondary_exec_control(s
>                    v->arch.hvm.vmx.secondary_exec_control);
>  }
>  
> +void vmx_update_tertiary_exec_control(struct vcpu *v)

const vcpu?

Thanks, Roger.
Jan Beulich Feb. 1, 2024, 12:09 p.m. UTC | #2
On 01.02.2024 12:50, Roger Pau Monné wrote:
> On Thu, Jan 11, 2024 at 10:00:10AM +0100, Jan Beulich wrote:
>> @@ -503,6 +538,9 @@ static int vmx_init_vmcs_config(bool bsp
>>              "Secondary Exec Control",
>>              vmx_secondary_exec_control, _vmx_secondary_exec_control);
>>          mismatch |= cap_check(
>> +            "Tertiary Exec Control",
>> +            vmx_tertiary_exec_control, _vmx_tertiary_exec_control);
> 
> I know it's done to match the surrounding style, but couldn't you move
> the name parameter one line up, and then limit the call to two lines?
> 
> (I don't think it will compromise readability).

You mean like this:

        mismatch |= cap_check("Tertiary Exec Control",
            vmx_tertiary_exec_control, _vmx_tertiary_exec_control);

? No, I view this as a mix of two possible styles. If the string literal
was moved up, the other legitimate style would only be

        mismatch |= cap_check("Tertiary Exec Control",
                              vmx_tertiary_exec_control,
                              _vmx_tertiary_exec_control);

aiui (again extending over 3 lines). Yet none of this is written down
anywhere.

But anyway - consistency with surrounding code trumps here, I think.

>> @@ -2068,10 +2111,12 @@ void vmcs_dump_vcpu(struct vcpu *v)
>>                 vmr(HOST_PERF_GLOBAL_CTRL));
>>  
>>      printk("*** Control State ***\n");
>> -    printk("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
>> +    printk("PinBased=%08x CPUBased=%08x\n",
>>             vmr32(PIN_BASED_VM_EXEC_CONTROL),
>> -           vmr32(CPU_BASED_VM_EXEC_CONTROL),
>> -           vmr32(SECONDARY_VM_EXEC_CONTROL));
>> +           vmr32(CPU_BASED_VM_EXEC_CONTROL));
>> +    printk("SecondaryExec=%08x TertiaryExec=%08lx\n",
> 
> For consistency, shouldn't TertiaryExec use 016 instead of 08 (as it's
> a 64bit filed).

Perhaps, assuming we'll gets bits 32 and populated sooner or later.
However, I view 16-digit literal numbers as hard to read, so I'd be
inclined to insert a separator (e.g. an underscore) between the low
and high halves. Thoughts?

>> @@ -260,6 +262,13 @@ extern u32 vmx_vmentry_control;
>>  #define SECONDARY_EXEC_NOTIFY_VM_EXITING        0x80000000U
>>  extern u32 vmx_secondary_exec_control;
>>  
>> +#define TERTIARY_EXEC_LOADIWKEY_EXITING         BIT(0, UL)
>> +#define TERTIARY_EXEC_ENABLE_HLAT               BIT(1, UL)
>> +#define TERTIARY_EXEC_EPT_PAGING_WRITE          BIT(2, UL)
>> +#define TERTIARY_EXEC_GUEST_PAGING_VERIFY       BIT(3, UL)
>> +#define TERTIARY_EXEC_IPI_VIRT                  BIT(4, UL)
> 
> While at it, my copy of the SDM also has:
> 
> #define TERTIARY_EXEC_VIRT_SPEC_CTRL               BIT(7, UL)

Ah yes, this must have appeared in the over 9 months that have
passed since I originally wrote this patch.

>> --- a/xen/arch/x86/include/asm/msr-index.h
>> +++ b/xen/arch/x86/include/asm/msr-index.h
>> @@ -347,6 +347,7 @@
>>  #define MSR_IA32_VMX_TRUE_EXIT_CTLS             0x48f
>>  #define MSR_IA32_VMX_TRUE_ENTRY_CTLS            0x490
>>  #define MSR_IA32_VMX_VMFUNC                     0x491
>> +#define MSR_IA32_VMX_PROCBASED_CTLS3            0x492
> 
> Shouldn't this be added above the "Legacy MSR constants in need of
> cleanup.  No new MSRs below this comment." line?

Now this is a question I'd like to forward to Andrew. Imo grouping the
new MSR with the other VMX ones is more important than respecting that
comment. But yes, I could of course add yet another patch to move the
entire block up first ...

>> --- a/xen/arch/x86/hvm/vmx/vmx.c
>> +++ b/xen/arch/x86/hvm/vmx/vmx.c
>> @@ -760,6 +760,12 @@ void vmx_update_secondary_exec_control(s
>>                    v->arch.hvm.vmx.secondary_exec_control);
>>  }
>>  
>> +void vmx_update_tertiary_exec_control(struct vcpu *v)
> 
> const vcpu?

Hmm, yes - overly blind copy-and-paste.

Jan
Roger Pau Monné Feb. 1, 2024, 5:10 p.m. UTC | #3
On Thu, Feb 01, 2024 at 01:09:11PM +0100, Jan Beulich wrote:
> On 01.02.2024 12:50, Roger Pau Monné wrote:
> > On Thu, Jan 11, 2024 at 10:00:10AM +0100, Jan Beulich wrote:
> >> @@ -503,6 +538,9 @@ static int vmx_init_vmcs_config(bool bsp
> >>              "Secondary Exec Control",
> >>              vmx_secondary_exec_control, _vmx_secondary_exec_control);
> >>          mismatch |= cap_check(
> >> +            "Tertiary Exec Control",
> >> +            vmx_tertiary_exec_control, _vmx_tertiary_exec_control);
> > 
> > I know it's done to match the surrounding style, but couldn't you move
> > the name parameter one line up, and then limit the call to two lines?
> > 
> > (I don't think it will compromise readability).
> 
> You mean like this:
> 
>         mismatch |= cap_check("Tertiary Exec Control",
>             vmx_tertiary_exec_control, _vmx_tertiary_exec_control);
> 
> ? No, I view this as a mix of two possible styles. If the string literal
> was moved up, the other legitimate style would only be
> 
>         mismatch |= cap_check("Tertiary Exec Control",
>                               vmx_tertiary_exec_control,
>                               _vmx_tertiary_exec_control);
> 
> aiui (again extending over 3 lines). Yet none of this is written down
> anywhere.
> 
> But anyway - consistency with surrounding code trumps here, I think.

I was hoping it could still fit on 2 lines, but if you need 3 never
mind then.

> >> @@ -2068,10 +2111,12 @@ void vmcs_dump_vcpu(struct vcpu *v)
> >>                 vmr(HOST_PERF_GLOBAL_CTRL));
> >>  
> >>      printk("*** Control State ***\n");
> >> -    printk("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
> >> +    printk("PinBased=%08x CPUBased=%08x\n",
> >>             vmr32(PIN_BASED_VM_EXEC_CONTROL),
> >> -           vmr32(CPU_BASED_VM_EXEC_CONTROL),
> >> -           vmr32(SECONDARY_VM_EXEC_CONTROL));
> >> +           vmr32(CPU_BASED_VM_EXEC_CONTROL));
> >> +    printk("SecondaryExec=%08x TertiaryExec=%08lx\n",
> > 
> > For consistency, shouldn't TertiaryExec use 016 instead of 08 (as it's
> > a 64bit filed).
> 
> Perhaps, assuming we'll gets bits 32 and populated sooner or later.
> However, I view 16-digit literal numbers as hard to read, so I'd be
> inclined to insert a separator (e.g. an underscore) between the low
> and high halves. Thoughts?

Works for me.

Thanks, Roger.
diff mbox series

Patch

--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -164,6 +164,7 @@  static int cf_check parse_ept_param_runt
 u32 vmx_pin_based_exec_control __read_mostly;
 u32 vmx_cpu_based_exec_control __read_mostly;
 u32 vmx_secondary_exec_control __read_mostly;
+uint64_t vmx_tertiary_exec_control __read_mostly;
 u32 vmx_vmexit_control __read_mostly;
 u32 vmx_vmentry_control __read_mostly;
 u64 vmx_ept_vpid_cap __read_mostly;
@@ -228,10 +229,32 @@  static u32 adjust_vmx_controls(
     return ctl;
 }
 
-static bool cap_check(const char *name, u32 expected, u32 saw)
+static uint64_t adjust_vmx_controls2(
+    const char *name, uint64_t ctl_min, uint64_t ctl_opt, unsigned int msr,
+    bool *mismatch)
+{
+    uint64_t vmx_msr, ctl = ctl_min | ctl_opt;
+
+    rdmsrl(msr, vmx_msr);
+
+    ctl &= vmx_msr; /* bit == 0 ==> must be zero */
+
+    /* Ensure minimum (required) set of control bits are supported. */
+    if ( ctl_min & ~ctl )
+    {
+        *mismatch = true;
+        printk("VMX: CPU%u has insufficient %s (%#lx; requires %#lx)\n",
+               smp_processor_id(), name, ctl, ctl_min);
+    }
+
+    return ctl;
+}
+
+static bool cap_check(
+    const char *name, unsigned long expected, unsigned long saw)
 {
     if ( saw != expected )
-        printk("VMX %s: saw %#x expected %#x\n", name, saw, expected);
+        printk("VMX %s: saw %#lx expected %#lx\n", name, saw, expected);
     return saw != expected;
 }
 
@@ -241,6 +264,7 @@  static int vmx_init_vmcs_config(bool bsp
     u32 _vmx_pin_based_exec_control;
     u32 _vmx_cpu_based_exec_control;
     u32 _vmx_secondary_exec_control = 0;
+    uint64_t _vmx_tertiary_exec_control = 0;
     u64 _vmx_ept_vpid_cap = 0;
     u64 _vmx_misc_cap = 0;
     u32 _vmx_vmexit_control;
@@ -274,7 +298,8 @@  static int vmx_init_vmcs_config(bool bsp
     opt = (CPU_BASED_ACTIVATE_MSR_BITMAP |
            CPU_BASED_TPR_SHADOW |
            CPU_BASED_MONITOR_TRAP_FLAG |
-           CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
+           CPU_BASED_ACTIVATE_SECONDARY_CONTROLS |
+           CPU_BASED_ACTIVATE_TERTIARY_CONTROLS);
     _vmx_cpu_based_exec_control = adjust_vmx_controls(
         "CPU-Based Exec Control", min, opt,
         MSR_IA32_VMX_PROCBASED_CTLS, &mismatch);
@@ -338,6 +363,15 @@  static int vmx_init_vmcs_config(bool bsp
             MSR_IA32_VMX_PROCBASED_CTLS2, &mismatch);
     }
 
+    if ( _vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS )
+    {
+        uint64_t opt = 0;
+
+        _vmx_tertiary_exec_control = adjust_vmx_controls2(
+            "Tertiary Exec Control", 0, opt,
+            MSR_IA32_VMX_PROCBASED_CTLS3, &mismatch);
+    }
+
     /* The IA32_VMX_EPT_VPID_CAP MSR exists only when EPT or VPID available */
     if ( _vmx_secondary_exec_control & (SECONDARY_EXEC_ENABLE_EPT |
                                         SECONDARY_EXEC_ENABLE_VPID) )
@@ -468,6 +502,7 @@  static int vmx_init_vmcs_config(bool bsp
         vmx_pin_based_exec_control = _vmx_pin_based_exec_control;
         vmx_cpu_based_exec_control = _vmx_cpu_based_exec_control;
         vmx_secondary_exec_control = _vmx_secondary_exec_control;
+        vmx_tertiary_exec_control  = _vmx_tertiary_exec_control;
         vmx_ept_vpid_cap           = _vmx_ept_vpid_cap;
         vmx_vmexit_control         = _vmx_vmexit_control;
         vmx_vmentry_control        = _vmx_vmentry_control;
@@ -503,6 +538,9 @@  static int vmx_init_vmcs_config(bool bsp
             "Secondary Exec Control",
             vmx_secondary_exec_control, _vmx_secondary_exec_control);
         mismatch |= cap_check(
+            "Tertiary Exec Control",
+            vmx_tertiary_exec_control, _vmx_tertiary_exec_control);
+        mismatch |= cap_check(
             "VMExit Control",
             vmx_vmexit_control, _vmx_vmexit_control);
         mismatch |= cap_check(
@@ -1080,6 +1118,7 @@  static int construct_vmcs(struct vcpu *v
         v->arch.hvm.vmx.exec_control |= CPU_BASED_RDTSC_EXITING;
 
     v->arch.hvm.vmx.secondary_exec_control = vmx_secondary_exec_control;
+    v->arch.hvm.vmx.tertiary_exec_control  = vmx_tertiary_exec_control;
 
     /*
      * Disable features which we don't want active by default:
@@ -1134,6 +1173,10 @@  static int construct_vmcs(struct vcpu *v
         __vmwrite(SECONDARY_VM_EXEC_CONTROL,
                   v->arch.hvm.vmx.secondary_exec_control);
 
+    if ( cpu_has_vmx_tertiary_exec_control )
+        __vmwrite(TERTIARY_VM_EXEC_CONTROL,
+                  v->arch.hvm.vmx.tertiary_exec_control);
+
     /* MSR access bitmap. */
     if ( cpu_has_vmx_msr_bitmap )
     {
@@ -2068,10 +2111,12 @@  void vmcs_dump_vcpu(struct vcpu *v)
                vmr(HOST_PERF_GLOBAL_CTRL));
 
     printk("*** Control State ***\n");
-    printk("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
+    printk("PinBased=%08x CPUBased=%08x\n",
            vmr32(PIN_BASED_VM_EXEC_CONTROL),
-           vmr32(CPU_BASED_VM_EXEC_CONTROL),
-           vmr32(SECONDARY_VM_EXEC_CONTROL));
+           vmr32(CPU_BASED_VM_EXEC_CONTROL));
+    printk("SecondaryExec=%08x TertiaryExec=%08lx\n",
+           vmr32(SECONDARY_VM_EXEC_CONTROL),
+           vmr(TERTIARY_VM_EXEC_CONTROL));
     printk("EntryControls=%08x ExitControls=%08x\n", vmentry_ctl, vmexit_ctl);
     printk("ExceptionBitmap=%08x PFECmask=%08x PFECmatch=%08x\n",
            vmr32(EXCEPTION_BITMAP),
--- a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
+++ b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
@@ -114,6 +114,7 @@  struct vmx_vcpu {
     /* Cache of cpu execution control. */
     u32                  exec_control;
     u32                  secondary_exec_control;
+    uint64_t             tertiary_exec_control;
     u32                  exception_bitmap;
 
     uint64_t             shadow_gs;
@@ -196,6 +197,7 @@  void vmx_vmcs_reload(struct vcpu *v);
 #define CPU_BASED_RDTSC_EXITING               0x00001000U
 #define CPU_BASED_CR3_LOAD_EXITING            0x00008000U
 #define CPU_BASED_CR3_STORE_EXITING           0x00010000U
+#define CPU_BASED_ACTIVATE_TERTIARY_CONTROLS  0x00020000U
 #define CPU_BASED_CR8_LOAD_EXITING            0x00080000U
 #define CPU_BASED_CR8_STORE_EXITING           0x00100000U
 #define CPU_BASED_TPR_SHADOW                  0x00200000U
@@ -260,6 +262,13 @@  extern u32 vmx_vmentry_control;
 #define SECONDARY_EXEC_NOTIFY_VM_EXITING        0x80000000U
 extern u32 vmx_secondary_exec_control;
 
+#define TERTIARY_EXEC_LOADIWKEY_EXITING         BIT(0, UL)
+#define TERTIARY_EXEC_ENABLE_HLAT               BIT(1, UL)
+#define TERTIARY_EXEC_EPT_PAGING_WRITE          BIT(2, UL)
+#define TERTIARY_EXEC_GUEST_PAGING_VERIFY       BIT(3, UL)
+#define TERTIARY_EXEC_IPI_VIRT                  BIT(4, UL)
+extern uint64_t vmx_tertiary_exec_control;
+
 #define VMX_EPT_EXEC_ONLY_SUPPORTED                         0x00000001
 #define VMX_EPT_WALK_LENGTH_4_SUPPORTED                     0x00000040
 #define VMX_EPT_MEMORY_TYPE_UC                              0x00000100
@@ -295,6 +304,8 @@  extern u64 vmx_ept_vpid_cap;
     (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_MSR_BITMAP)
 #define cpu_has_vmx_secondary_exec_control \
     (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
+#define cpu_has_vmx_tertiary_exec_control \
+    (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS)
 #define cpu_has_vmx_ept \
     (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT)
 #define cpu_has_vmx_dt_exiting \
@@ -422,6 +433,7 @@  enum vmcs_field {
     VIRT_EXCEPTION_INFO             = 0x0000202a,
     XSS_EXIT_BITMAP                 = 0x0000202c,
     TSC_MULTIPLIER                  = 0x00002032,
+    TERTIARY_VM_EXEC_CONTROL        = 0x00002034,
     GUEST_PHYSICAL_ADDRESS          = 0x00002400,
     VMCS_LINK_POINTER               = 0x00002800,
     GUEST_IA32_DEBUGCTL             = 0x00002802,
--- a/xen/arch/x86/include/asm/msr-index.h
+++ b/xen/arch/x86/include/asm/msr-index.h
@@ -347,6 +347,7 @@ 
 #define MSR_IA32_VMX_TRUE_EXIT_CTLS             0x48f
 #define MSR_IA32_VMX_TRUE_ENTRY_CTLS            0x490
 #define MSR_IA32_VMX_VMFUNC                     0x491
+#define MSR_IA32_VMX_PROCBASED_CTLS3            0x492
 
 /* K7/K8 MSRs. Not complete. See the architecture manual for a more
    complete list. */
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -760,6 +760,12 @@  void vmx_update_secondary_exec_control(s
                   v->arch.hvm.vmx.secondary_exec_control);
 }
 
+void vmx_update_tertiary_exec_control(struct vcpu *v)
+{
+    __vmwrite(TERTIARY_VM_EXEC_CONTROL,
+              v->arch.hvm.vmx.tertiary_exec_control);
+}
+
 void vmx_update_exception_bitmap(struct vcpu *v)
 {
     u32 bitmap = unlikely(v->arch.hvm.vmx.vmx_realmode)
--- a/xen/arch/x86/include/asm/hvm/vmx/vmx.h
+++ b/xen/arch/x86/include/asm/hvm/vmx/vmx.h
@@ -81,6 +81,7 @@  void vmx_realmode(struct cpu_user_regs *
 void vmx_update_exception_bitmap(struct vcpu *v);
 void vmx_update_cpu_exec_control(struct vcpu *v);
 void vmx_update_secondary_exec_control(struct vcpu *v);
+void vmx_update_tertiary_exec_control(struct vcpu *v);
 
 #define POSTED_INTR_ON  0
 #define POSTED_INTR_SN  1