diff mbox

[kvm-unit-test,1/2] nVMX x86: APIC virtual controls must be unset if "Use TPR shadow" is unset

Message ID d5a2a34a-b06a-46b9-0090-a3c419973945@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Krish Sadhukhan June 29, 2018, 7:07 p.m. UTC
According to section "Checks on VMX Controls" in Intel SDM vol 3C, the

following check needs to be enforced on vmentry of L2 guests:

     If the "use TPR shadow" VM-execution control is 0, the following
     VM-execution controls must also be 0: "virtualize x2APIC mode",
     "APIC-register virtualization" and "virtual-interrupt delivery".

This unit-test validates the above vmentry check.

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
---
  x86/vmx_tests.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
  1 file changed, 106 insertions(+), 2 deletions(-)

Comments

Jim Mattson July 9, 2018, 5:31 p.m. UTC | #1
Hi Krish,

I think this would be more succint as two loops: an outer loop that
tested "use TPR shadow" values and an inner loop that tested
combinations of the other three controls. But this looks fine to me as
it is.

Reviewed-by: Jim Mattson <jmattson@google.com>

On Fri, Jun 29, 2018 at 12:07 PM, Krish Sadhukhan
<krish.sadhukhan@oracle.com> wrote:
> According to section "Checks on VMX Controls" in Intel SDM vol 3C, the
>
> following check needs to be enforced on vmentry of L2 guests:
>
>     If the "use TPR shadow" VM-execution control is 0, the following
>     VM-execution controls must also be 0: "virtualize x2APIC mode",
>     "APIC-register virtualization" and "virtual-interrupt delivery".
>
> This unit-test validates the above vmentry check.
>
> Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
> Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
> ---
>  x86/vmx_tests.c | 108
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 106 insertions(+), 2 deletions(-)
>
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index 38f10f4..64be48f 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -3580,6 +3580,111 @@ static void test_apic_access_addr(void)
>                                  "virtualize APIC-accesses", true, false);
>  }
>  +/*
> + * If the "use TPR shadow" VM-execution control is 0, the following
> + * VM-execution controls must also be 0:
> + *     - virtualize x2APIC mode
> + *     - APIC-register virtualization
> + *     - virtual-interrupt delivery
> + */
> +static void test_apic_virtual_ctls(void)
> +{
> +       u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0);
> +       u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1);
> +       u32 primary = saved_primary;
> +       u32 secondary = saved_secondary;
> +       bool cpu_has_virt_x2apic = 0;
> +       bool cpu_has_apic_reg_virt = 0;
> +       bool cpu_has_vintd = 0;
> +
> +       if (!((ctrl_cpu_rev[0].clr & (CPU_SECONDARY | CPU_TPR_SHADOW)) ==
> +           (CPU_SECONDARY | CPU_TPR_SHADOW)))
> +               return;
> +
> +       if ((ctrl_cpu_rev[1].clr & CPU_VIRT_X2APIC) == CPU_VIRT_X2APIC)
> +               cpu_has_virt_x2apic = 1;
> +       if ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) == CPU_APIC_REG_VIRT)
> +               cpu_has_apic_reg_virt = 1;
> +       if ((ctrl_cpu_rev[1].clr & CPU_VINTD) == CPU_VINTD)
> +               cpu_has_vintd = 1;
> +
> +       primary |= CPU_SECONDARY;
> +       vmcs_write(CPU_EXEC_CTRL0, primary & ~CPU_TPR_SHADOW);
> +
> +       if (cpu_has_virt_x2apic) {
> +               secondary &= ~(CPU_APIC_REG_VIRT | CPU_VINTD);
> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VIRT_X2APIC);
> +               report_prefix_pushf("Use TPR shadow disabled; virtualize
> x2APIC mode enabled");
> +               test_vmx_controls(false, false);
> +               report_prefix_pop();
> +
> +               if (cpu_has_apic_reg_virt) {
> +                       vmcs_write(CPU_EXEC_CTRL1, secondary |
> +                           CPU_APIC_REG_VIRT);
> +                       report_prefix_pushf("Use TPR shadow disabled;
> virtualize x2APIC mode enabled; APIC-register virtualization enabled");
> +                       test_vmx_controls(false, false);
> +                       report_prefix_pop();
> +               }
> +
> +               if (cpu_has_vintd) {
> +                       secondary &= ~CPU_APIC_REG_VIRT;
> +                       vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
> +                       report_prefix_pushf("Use TPR shadow disabled;
> virtualize x2APIC mode enabled; virtual-interrupt delivery enabled");
> +                       test_vmx_controls(false, false);
> +                       report_prefix_pop();
> +               }
> +       }
> +
> +       if (cpu_has_apic_reg_virt) {
> +               secondary &= ~(~CPU_VIRT_X2APIC | CPU_VINTD);
> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_APIC_REG_VIRT);
> +               report_prefix_pushf("Use TPR shadow disabled; APIC-register
> virtualization enabled");
> +               test_vmx_controls(false, false);
> +               report_prefix_pop();
> +
> +               if (cpu_has_vintd) {
> +                       secondary &= ~CPU_VIRT_X2APIC;
> +                       vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
> +                       report_prefix_pushf("Use TPR shadow disabled;
> APIC-register virtualization enabled; virtual-interrupt delivery enabled");
> +                       test_vmx_controls(false, false);
> +                       report_prefix_pop();
> +               }
> +       }
> +
> +       if (cpu_has_vintd) {
> +               secondary &= ~(~CPU_VIRT_X2APIC | CPU_APIC_REG_VIRT);
> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
> +               report_prefix_pushf("Use TPR shadow disabled;
> virtual-interrupt delivery enabled");
> +               test_vmx_controls(false, false);
> +               report_prefix_pop();
> +       }
> +
> +       if (cpu_has_virt_x2apic && cpu_has_apic_reg_virt &&
> +           cpu_has_vintd) {
> +
> +               vmcs_write(CPU_EXEC_CTRL1, secondary | (CPU_VIRT_X2APIC |
> +                   CPU_APIC_REG_VIRT | CPU_VINTD));
> +               report_prefix_pushf("Use TPR shadow disabled; virtualize
> x2APIC mode enabled; APIC-register virtualization enabled; virtual-interrupt
> delivery enabled");
> +               test_vmx_controls(false, false);
> +               report_prefix_pop();
> +
> +               vmcs_write(CPU_EXEC_CTRL0, primary | CPU_TPR_SHADOW);
> +               report_prefix_pushf("Use TPR shadow enabled; virtualize
> x2APIC mode enabled; APIC-register virtualization enabled; virtual-interrupt
> delivery enabled");
> +               test_vmx_controls(true, false);
> +               report_prefix_pop();
> +       }
> +
> +       vmcs_write(CPU_EXEC_CTRL0, saved_primary);
> +       vmcs_write(CPU_EXEC_CTRL1, saved_secondary);
> +}
> +
> +static void test_apic_ctls(void)
> +{
> +       test_apic_virt_addr();
> +       test_apic_access_addr();
> +       test_apic_virtual_ctls();
> +}
> +
>  static void set_vtpr(unsigned vtpr)
>  {
>         *(u32 *)phys_to_virt(vmcs_read(APIC_VIRT_ADDR) + APIC_TASKPRI) =
> vtpr;
> @@ -3846,8 +3951,7 @@ static void vmx_controls_test(void)
>         test_cr3_targets();
>         test_io_bitmaps();
>         test_msr_bitmap();
> -       test_apic_virt_addr();
> -       test_apic_access_addr();
> +       test_apic_ctls();
>         test_tpr_threshold();
>         test_nmi_ctrls();
>  }
> --
> 2.9.5
>
Krish Sadhukhan July 10, 2018, 11:28 p.m. UTC | #2
It becomes difficult to create the inner loop as the other three 
controls need to be tested individually, in pairs and then all together. 
But the outer loop makes sense. In fact, after your feedback, I realized 
that I hadn't run all the tests with "use TPR shadow" set. So I have 
created an outer loop (sort of) that runs twice - once with "use TPR 
shadow" unset and then with "use TPR shadow" set.

I will send out the revised version.

Thanks,
Krish

On 07/09/2018 10:31 AM, Jim Mattson wrote:
> Hi Krish,
>
> I think this would be more succint as two loops: an outer loop that
> tested "use TPR shadow" values and an inner loop that tested
> combinations of the other three controls. But this looks fine to me as
> it is.
>
> Reviewed-by: Jim Mattson <jmattson@google.com>
>
> On Fri, Jun 29, 2018 at 12:07 PM, Krish Sadhukhan
> <krish.sadhukhan@oracle.com> wrote:
>> According to section "Checks on VMX Controls" in Intel SDM vol 3C, the
>>
>> following check needs to be enforced on vmentry of L2 guests:
>>
>>      If the "use TPR shadow" VM-execution control is 0, the following
>>      VM-execution controls must also be 0: "virtualize x2APIC mode",
>>      "APIC-register virtualization" and "virtual-interrupt delivery".
>>
>> This unit-test validates the above vmentry check.
>>
>> Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
>> Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
>> ---
>>   x86/vmx_tests.c | 108
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 106 insertions(+), 2 deletions(-)
>>
>> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
>> index 38f10f4..64be48f 100644
>> --- a/x86/vmx_tests.c
>> +++ b/x86/vmx_tests.c
>> @@ -3580,6 +3580,111 @@ static void test_apic_access_addr(void)
>>                                   "virtualize APIC-accesses", true, false);
>>   }
>>   +/*
>> + * If the "use TPR shadow" VM-execution control is 0, the following
>> + * VM-execution controls must also be 0:
>> + *     - virtualize x2APIC mode
>> + *     - APIC-register virtualization
>> + *     - virtual-interrupt delivery
>> + */
>> +static void test_apic_virtual_ctls(void)
>> +{
>> +       u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0);
>> +       u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1);
>> +       u32 primary = saved_primary;
>> +       u32 secondary = saved_secondary;
>> +       bool cpu_has_virt_x2apic = 0;
>> +       bool cpu_has_apic_reg_virt = 0;
>> +       bool cpu_has_vintd = 0;
>> +
>> +       if (!((ctrl_cpu_rev[0].clr & (CPU_SECONDARY | CPU_TPR_SHADOW)) ==
>> +           (CPU_SECONDARY | CPU_TPR_SHADOW)))
>> +               return;
>> +
>> +       if ((ctrl_cpu_rev[1].clr & CPU_VIRT_X2APIC) == CPU_VIRT_X2APIC)
>> +               cpu_has_virt_x2apic = 1;
>> +       if ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) == CPU_APIC_REG_VIRT)
>> +               cpu_has_apic_reg_virt = 1;
>> +       if ((ctrl_cpu_rev[1].clr & CPU_VINTD) == CPU_VINTD)
>> +               cpu_has_vintd = 1;
>> +
>> +       primary |= CPU_SECONDARY;
>> +       vmcs_write(CPU_EXEC_CTRL0, primary & ~CPU_TPR_SHADOW);
>> +
>> +       if (cpu_has_virt_x2apic) {
>> +               secondary &= ~(CPU_APIC_REG_VIRT | CPU_VINTD);
>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VIRT_X2APIC);
>> +               report_prefix_pushf("Use TPR shadow disabled; virtualize
>> x2APIC mode enabled");
>> +               test_vmx_controls(false, false);
>> +               report_prefix_pop();
>> +
>> +               if (cpu_has_apic_reg_virt) {
>> +                       vmcs_write(CPU_EXEC_CTRL1, secondary |
>> +                           CPU_APIC_REG_VIRT);
>> +                       report_prefix_pushf("Use TPR shadow disabled;
>> virtualize x2APIC mode enabled; APIC-register virtualization enabled");
>> +                       test_vmx_controls(false, false);
>> +                       report_prefix_pop();
>> +               }
>> +
>> +               if (cpu_has_vintd) {
>> +                       secondary &= ~CPU_APIC_REG_VIRT;
>> +                       vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
>> +                       report_prefix_pushf("Use TPR shadow disabled;
>> virtualize x2APIC mode enabled; virtual-interrupt delivery enabled");
>> +                       test_vmx_controls(false, false);
>> +                       report_prefix_pop();
>> +               }
>> +       }
>> +
>> +       if (cpu_has_apic_reg_virt) {
>> +               secondary &= ~(~CPU_VIRT_X2APIC | CPU_VINTD);
>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_APIC_REG_VIRT);
>> +               report_prefix_pushf("Use TPR shadow disabled; APIC-register
>> virtualization enabled");
>> +               test_vmx_controls(false, false);
>> +               report_prefix_pop();
>> +
>> +               if (cpu_has_vintd) {
>> +                       secondary &= ~CPU_VIRT_X2APIC;
>> +                       vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
>> +                       report_prefix_pushf("Use TPR shadow disabled;
>> APIC-register virtualization enabled; virtual-interrupt delivery enabled");
>> +                       test_vmx_controls(false, false);
>> +                       report_prefix_pop();
>> +               }
>> +       }
>> +
>> +       if (cpu_has_vintd) {
>> +               secondary &= ~(~CPU_VIRT_X2APIC | CPU_APIC_REG_VIRT);
>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
>> +               report_prefix_pushf("Use TPR shadow disabled;
>> virtual-interrupt delivery enabled");
>> +               test_vmx_controls(false, false);
>> +               report_prefix_pop();
>> +       }
>> +
>> +       if (cpu_has_virt_x2apic && cpu_has_apic_reg_virt &&
>> +           cpu_has_vintd) {
>> +
>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | (CPU_VIRT_X2APIC |
>> +                   CPU_APIC_REG_VIRT | CPU_VINTD));
>> +               report_prefix_pushf("Use TPR shadow disabled; virtualize
>> x2APIC mode enabled; APIC-register virtualization enabled; virtual-interrupt
>> delivery enabled");
>> +               test_vmx_controls(false, false);
>> +               report_prefix_pop();
>> +
>> +               vmcs_write(CPU_EXEC_CTRL0, primary | CPU_TPR_SHADOW);
>> +               report_prefix_pushf("Use TPR shadow enabled; virtualize
>> x2APIC mode enabled; APIC-register virtualization enabled; virtual-interrupt
>> delivery enabled");
>> +               test_vmx_controls(true, false);
>> +               report_prefix_pop();
>> +       }
>> +
>> +       vmcs_write(CPU_EXEC_CTRL0, saved_primary);
>> +       vmcs_write(CPU_EXEC_CTRL1, saved_secondary);
>> +}
>> +
>> +static void test_apic_ctls(void)
>> +{
>> +       test_apic_virt_addr();
>> +       test_apic_access_addr();
>> +       test_apic_virtual_ctls();
>> +}
>> +
>>   static void set_vtpr(unsigned vtpr)
>>   {
>>          *(u32 *)phys_to_virt(vmcs_read(APIC_VIRT_ADDR) + APIC_TASKPRI) =
>> vtpr;
>> @@ -3846,8 +3951,7 @@ static void vmx_controls_test(void)
>>          test_cr3_targets();
>>          test_io_bitmaps();
>>          test_msr_bitmap();
>> -       test_apic_virt_addr();
>> -       test_apic_access_addr();
>> +       test_apic_ctls();
>>          test_tpr_threshold();
>>          test_nmi_ctrls();
>>   }
>> --
>> 2.9.5
>>
Jim Mattson July 10, 2018, 11:40 p.m. UTC | #3
The inner loop just needs to run from 0 to 7, covering all possible
combinations of the three bits. If an unsupported bit would be set,
skip that loop iteration.

On Tue, Jul 10, 2018 at 4:28 PM, Krish Sadhukhan
<krish.sadhukhan@oracle.com> wrote:
> It becomes difficult to create the inner loop as the other three controls
> need to be tested individually, in pairs and then all together. But the
> outer loop makes sense. In fact, after your feedback, I realized that I
> hadn't run all the tests with "use TPR shadow" set. So I have created an
> outer loop (sort of) that runs twice - once with "use TPR shadow" unset and
> then with "use TPR shadow" set.
>
> I will send out the revised version.
>
> Thanks,
> Krish
>
>
> On 07/09/2018 10:31 AM, Jim Mattson wrote:
>>
>> Hi Krish,
>>
>> I think this would be more succint as two loops: an outer loop that
>> tested "use TPR shadow" values and an inner loop that tested
>> combinations of the other three controls. But this looks fine to me as
>> it is.
>>
>> Reviewed-by: Jim Mattson <jmattson@google.com>
>>
>> On Fri, Jun 29, 2018 at 12:07 PM, Krish Sadhukhan
>> <krish.sadhukhan@oracle.com> wrote:
>>>
>>> According to section "Checks on VMX Controls" in Intel SDM vol 3C, the
>>>
>>> following check needs to be enforced on vmentry of L2 guests:
>>>
>>>      If the "use TPR shadow" VM-execution control is 0, the following
>>>      VM-execution controls must also be 0: "virtualize x2APIC mode",
>>>      "APIC-register virtualization" and "virtual-interrupt delivery".
>>>
>>> This unit-test validates the above vmentry check.
>>>
>>> Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
>>> Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
>>> ---
>>>   x86/vmx_tests.c | 108
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>>   1 file changed, 106 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
>>> index 38f10f4..64be48f 100644
>>> --- a/x86/vmx_tests.c
>>> +++ b/x86/vmx_tests.c
>>> @@ -3580,6 +3580,111 @@ static void test_apic_access_addr(void)
>>>                                   "virtualize APIC-accesses", true,
>>> false);
>>>   }
>>>   +/*
>>> + * If the "use TPR shadow" VM-execution control is 0, the following
>>> + * VM-execution controls must also be 0:
>>> + *     - virtualize x2APIC mode
>>> + *     - APIC-register virtualization
>>> + *     - virtual-interrupt delivery
>>> + */
>>> +static void test_apic_virtual_ctls(void)
>>> +{
>>> +       u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0);
>>> +       u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1);
>>> +       u32 primary = saved_primary;
>>> +       u32 secondary = saved_secondary;
>>> +       bool cpu_has_virt_x2apic = 0;
>>> +       bool cpu_has_apic_reg_virt = 0;
>>> +       bool cpu_has_vintd = 0;
>>> +
>>> +       if (!((ctrl_cpu_rev[0].clr & (CPU_SECONDARY | CPU_TPR_SHADOW)) ==
>>> +           (CPU_SECONDARY | CPU_TPR_SHADOW)))
>>> +               return;
>>> +
>>> +       if ((ctrl_cpu_rev[1].clr & CPU_VIRT_X2APIC) == CPU_VIRT_X2APIC)
>>> +               cpu_has_virt_x2apic = 1;
>>> +       if ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) ==
>>> CPU_APIC_REG_VIRT)
>>> +               cpu_has_apic_reg_virt = 1;
>>> +       if ((ctrl_cpu_rev[1].clr & CPU_VINTD) == CPU_VINTD)
>>> +               cpu_has_vintd = 1;
>>> +
>>> +       primary |= CPU_SECONDARY;
>>> +       vmcs_write(CPU_EXEC_CTRL0, primary & ~CPU_TPR_SHADOW);
>>> +
>>> +       if (cpu_has_virt_x2apic) {
>>> +               secondary &= ~(CPU_APIC_REG_VIRT | CPU_VINTD);
>>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VIRT_X2APIC);
>>> +               report_prefix_pushf("Use TPR shadow disabled; virtualize
>>> x2APIC mode enabled");
>>> +               test_vmx_controls(false, false);
>>> +               report_prefix_pop();
>>> +
>>> +               if (cpu_has_apic_reg_virt) {
>>> +                       vmcs_write(CPU_EXEC_CTRL1, secondary |
>>> +                           CPU_APIC_REG_VIRT);
>>> +                       report_prefix_pushf("Use TPR shadow disabled;
>>> virtualize x2APIC mode enabled; APIC-register virtualization enabled");
>>> +                       test_vmx_controls(false, false);
>>> +                       report_prefix_pop();
>>> +               }
>>> +
>>> +               if (cpu_has_vintd) {
>>> +                       secondary &= ~CPU_APIC_REG_VIRT;
>>> +                       vmcs_write(CPU_EXEC_CTRL1, secondary |
>>> CPU_VINTD);
>>> +                       report_prefix_pushf("Use TPR shadow disabled;
>>> virtualize x2APIC mode enabled; virtual-interrupt delivery enabled");
>>> +                       test_vmx_controls(false, false);
>>> +                       report_prefix_pop();
>>> +               }
>>> +       }
>>> +
>>> +       if (cpu_has_apic_reg_virt) {
>>> +               secondary &= ~(~CPU_VIRT_X2APIC | CPU_VINTD);
>>> +               vmcs_write(CPU_EXEC_CTRL1, secondary |
>>> CPU_APIC_REG_VIRT);
>>> +               report_prefix_pushf("Use TPR shadow disabled;
>>> APIC-register
>>> virtualization enabled");
>>> +               test_vmx_controls(false, false);
>>> +               report_prefix_pop();
>>> +
>>> +               if (cpu_has_vintd) {
>>> +                       secondary &= ~CPU_VIRT_X2APIC;
>>> +                       vmcs_write(CPU_EXEC_CTRL1, secondary |
>>> CPU_VINTD);
>>> +                       report_prefix_pushf("Use TPR shadow disabled;
>>> APIC-register virtualization enabled; virtual-interrupt delivery
>>> enabled");
>>> +                       test_vmx_controls(false, false);
>>> +                       report_prefix_pop();
>>> +               }
>>> +       }
>>> +
>>> +       if (cpu_has_vintd) {
>>> +               secondary &= ~(~CPU_VIRT_X2APIC | CPU_APIC_REG_VIRT);
>>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
>>> +               report_prefix_pushf("Use TPR shadow disabled;
>>> virtual-interrupt delivery enabled");
>>> +               test_vmx_controls(false, false);
>>> +               report_prefix_pop();
>>> +       }
>>> +
>>> +       if (cpu_has_virt_x2apic && cpu_has_apic_reg_virt &&
>>> +           cpu_has_vintd) {
>>> +
>>> +               vmcs_write(CPU_EXEC_CTRL1, secondary | (CPU_VIRT_X2APIC |
>>> +                   CPU_APIC_REG_VIRT | CPU_VINTD));
>>> +               report_prefix_pushf("Use TPR shadow disabled; virtualize
>>> x2APIC mode enabled; APIC-register virtualization enabled;
>>> virtual-interrupt
>>> delivery enabled");
>>> +               test_vmx_controls(false, false);
>>> +               report_prefix_pop();
>>> +
>>> +               vmcs_write(CPU_EXEC_CTRL0, primary | CPU_TPR_SHADOW);
>>> +               report_prefix_pushf("Use TPR shadow enabled; virtualize
>>> x2APIC mode enabled; APIC-register virtualization enabled;
>>> virtual-interrupt
>>> delivery enabled");
>>> +               test_vmx_controls(true, false);
>>> +               report_prefix_pop();
>>> +       }
>>> +
>>> +       vmcs_write(CPU_EXEC_CTRL0, saved_primary);
>>> +       vmcs_write(CPU_EXEC_CTRL1, saved_secondary);
>>> +}
>>> +
>>> +static void test_apic_ctls(void)
>>> +{
>>> +       test_apic_virt_addr();
>>> +       test_apic_access_addr();
>>> +       test_apic_virtual_ctls();
>>> +}
>>> +
>>>   static void set_vtpr(unsigned vtpr)
>>>   {
>>>          *(u32 *)phys_to_virt(vmcs_read(APIC_VIRT_ADDR) + APIC_TASKPRI) =
>>> vtpr;
>>> @@ -3846,8 +3951,7 @@ static void vmx_controls_test(void)
>>>          test_cr3_targets();
>>>          test_io_bitmaps();
>>>          test_msr_bitmap();
>>> -       test_apic_virt_addr();
>>> -       test_apic_access_addr();
>>> +       test_apic_ctls();
>>>          test_tpr_threshold();
>>>          test_nmi_ctrls();
>>>   }
>>> --
>>> 2.9.5
>>>
>
diff mbox

Patch

diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 38f10f4..64be48f 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -3580,6 +3580,111 @@  static void test_apic_access_addr(void)
  				 "virtualize APIC-accesses", true, false);
  }
  
+/*
+ * If the "use TPR shadow" VM-execution control is 0, the following
+ * VM-execution controls must also be 0:
+ * 	- virtualize x2APIC mode
+ *	- APIC-register virtualization
+ *	- virtual-interrupt delivery
+ */
+static void test_apic_virtual_ctls(void)
+{
+	u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0);
+	u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1);
+	u32 primary = saved_primary;
+	u32 secondary = saved_secondary;
+	bool cpu_has_virt_x2apic = 0;
+	bool cpu_has_apic_reg_virt = 0;
+	bool cpu_has_vintd = 0;
+
+	if (!((ctrl_cpu_rev[0].clr & (CPU_SECONDARY | CPU_TPR_SHADOW)) ==
+	    (CPU_SECONDARY | CPU_TPR_SHADOW)))
+		return;
+
+	if ((ctrl_cpu_rev[1].clr & CPU_VIRT_X2APIC) == CPU_VIRT_X2APIC)
+		cpu_has_virt_x2apic = 1;
+	if ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) == CPU_APIC_REG_VIRT)
+		cpu_has_apic_reg_virt = 1;
+	if ((ctrl_cpu_rev[1].clr & CPU_VINTD) == CPU_VINTD)
+		cpu_has_vintd = 1;
+
+	primary |= CPU_SECONDARY;
+	vmcs_write(CPU_EXEC_CTRL0, primary & ~CPU_TPR_SHADOW);
+
+	if (cpu_has_virt_x2apic) {
+		secondary &= ~(CPU_APIC_REG_VIRT | CPU_VINTD);
+		vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VIRT_X2APIC);
+		report_prefix_pushf("Use TPR shadow disabled; virtualize x2APIC mode enabled");
+		test_vmx_controls(false, false);
+		report_prefix_pop();
+
+		if (cpu_has_apic_reg_virt) {
+			vmcs_write(CPU_EXEC_CTRL1, secondary |
+			    CPU_APIC_REG_VIRT);
+			report_prefix_pushf("Use TPR shadow disabled; virtualize x2APIC mode enabled; APIC-register virtualization enabled");
+			test_vmx_controls(false, false);
+			report_prefix_pop();
+		}
+
+		if (cpu_has_vintd) {
+			secondary &= ~CPU_APIC_REG_VIRT;
+			vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
+			report_prefix_pushf("Use TPR shadow disabled; virtualize x2APIC mode enabled; virtual-interrupt delivery enabled");
+			test_vmx_controls(false, false);
+			report_prefix_pop();
+		}
+	}
+
+	if (cpu_has_apic_reg_virt) {
+		secondary &= ~(~CPU_VIRT_X2APIC | CPU_VINTD);
+		vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_APIC_REG_VIRT);
+		report_prefix_pushf("Use TPR shadow disabled; APIC-register virtualization enabled");
+		test_vmx_controls(false, false);
+		report_prefix_pop();
+
+		if (cpu_has_vintd) {
+			secondary &= ~CPU_VIRT_X2APIC;
+			vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
+			report_prefix_pushf("Use TPR shadow disabled; APIC-register virtualization enabled; virtual-interrupt delivery enabled");
+			test_vmx_controls(false, false);
+			report_prefix_pop();
+		}
+	}
+
+	if (cpu_has_vintd) {
+		secondary &= ~(~CPU_VIRT_X2APIC | CPU_APIC_REG_VIRT);
+		vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD);
+		report_prefix_pushf("Use TPR shadow disabled; virtual-interrupt delivery enabled");
+		test_vmx_controls(false, false);
+		report_prefix_pop();
+	}
+
+	if (cpu_has_virt_x2apic && cpu_has_apic_reg_virt &&
+	    cpu_has_vintd) {
+
+		vmcs_write(CPU_EXEC_CTRL1, secondary | (CPU_VIRT_X2APIC |
+		    CPU_APIC_REG_VIRT | CPU_VINTD));
+		report_prefix_pushf("Use TPR shadow disabled; virtualize x2APIC mode enabled; APIC-register virtualization enabled; virtual-interrupt delivery enabled");
+		test_vmx_controls(false, false);
+		report_prefix_pop();
+
+		vmcs_write(CPU_EXEC_CTRL0, primary | CPU_TPR_SHADOW);
+		report_prefix_pushf("Use TPR shadow enabled; virtualize x2APIC mode enabled; APIC-register virtualization enabled; virtual-interrupt delivery enabled");
+		test_vmx_controls(true, false);
+		report_prefix_pop();
+	}
+
+	vmcs_write(CPU_EXEC_CTRL0, saved_primary);
+	vmcs_write(CPU_EXEC_CTRL1, saved_secondary);
+}
+
+static void test_apic_ctls(void)
+{
+	test_apic_virt_addr();
+	test_apic_access_addr();
+	test_apic_virtual_ctls();
+}
+
  static void set_vtpr(unsigned vtpr)
  {
  	*(u32 *)phys_to_virt(vmcs_read(APIC_VIRT_ADDR) + APIC_TASKPRI) = vtpr;
@@ -3846,8 +3951,7 @@  static void vmx_controls_test(void)
  	test_cr3_targets();
  	test_io_bitmaps();
  	test_msr_bitmap();
-	test_apic_virt_addr();
-	test_apic_access_addr();
+	test_apic_ctls();
  	test_tpr_threshold();
  	test_nmi_ctrls();
  }