diff mbox series

x86/tsx: Cope with RTM_ALWAYS_ABORT vs RTM mismatch

Message ID 20240404104122.2870129-1-andrew.cooper3@citrix.com (mailing list archive)
State Superseded
Headers show
Series x86/tsx: Cope with RTM_ALWAYS_ABORT vs RTM mismatch | expand

Commit Message

Andrew Cooper April 4, 2024, 10:41 a.m. UTC
It turns out there is something wonky on some but not all CPUs with
MSR_TSX_FORCE_ABORT.  The presence of RTM_ALWAYS_ABORT causes Xen to think
it's safe to offer HLE/RTM to guests, but in this case, XBEGIN instructions
genuinely #UD.

Spot this case and try to back out as cleanly as we can.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>

In the meantime, I'll see if anyone at Intel knows what's going on.  Because
these parts are fully out of support now, it's very unlikely that we're going
to get a fix.
---
 xen/arch/x86/tsx.c | 55 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 45 insertions(+), 10 deletions(-)


base-commit: 6117179dd99958e4ef2687617d12c9b15bdbae24

Comments

Marek Marczykowski-Górecki April 4, 2024, 11:02 a.m. UTC | #1
On Thu, Apr 04, 2024 at 11:41:22AM +0100, Andrew Cooper wrote:
> It turns out there is something wonky on some but not all CPUs with
> MSR_TSX_FORCE_ABORT.  The presence of RTM_ALWAYS_ABORT causes Xen to think
> it's safe to offer HLE/RTM to guests, but in this case, XBEGIN instructions
> genuinely #UD.
> 
> Spot this case and try to back out as cleanly as we can.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Thanks, this makes the test exit with 0, and print just "Got #UD" now in
the "Testing RTM behaviour" section.

Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>

> ---
> CC: Jan Beulich <JBeulich@suse.com>
> CC: Roger Pau Monné <roger.pau@citrix.com>
> CC: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
> 
> In the meantime, I'll see if anyone at Intel knows what's going on.  Because
> these parts are fully out of support now, it's very unlikely that we're going
> to get a fix.
> ---
>  xen/arch/x86/tsx.c | 55 +++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 45 insertions(+), 10 deletions(-)
> 
> diff --git a/xen/arch/x86/tsx.c b/xen/arch/x86/tsx.c
> index 50d8059f23a9..41bb39d10074 100644
> --- a/xen/arch/x86/tsx.c
> +++ b/xen/arch/x86/tsx.c
> @@ -1,5 +1,6 @@
>  #include <xen/init.h>
>  #include <xen/param.h>
> +#include <asm/microcode.h>
>  #include <asm/msr.h>
>  
>  /*
> @@ -9,6 +10,7 @@
>   *  -1 => Default, altered to 0/1 (if unspecified) by:
>   *                 - TAA heuristics/settings for speculative safety
>   *                 - "TSX vs PCR3" select for TSX memory ordering safety
> + *  -2 => Implicit tsx=0 (from RTM_ALWAYS_ABORT vs RTM mismatch)
>   *  -3 => Implicit tsx=1 (feed-through from spec-ctrl=0)
>   *
>   * This is arranged such that the bottom bit encodes whether TSX is actually
> @@ -114,11 +116,50 @@ void tsx_init(void)
>  
>          if ( cpu_has_tsx_force_abort )
>          {
> +            uint64_t val;
> +
>              /*
> -             * On an early TSX-enable Skylake part subject to the memory
> +             * On an early TSX-enabled Skylake part subject to the memory
>               * ordering erratum, with at least the March 2019 microcode.
>               */
>  
> +            rdmsrl(MSR_TSX_FORCE_ABORT, val);
> +
> +            /*
> +             * At the time of writing (April 2024), it was discovered that
> +             * some parts (e.g. CoffeeLake 8th Gen, 06-9e-0a, ucode 0xf6)
> +             * advertise RTM_ALWAYS_ABORT, but XBEGIN instructions #UD.  Other
> +             * similar parts (e.g. KabyLake Xeon-E3, 06-9e-09, ucode 0xf8)
> +             * operate as expected.
> +             *
> +             * In this case:
> +             *  - RTM_ALWAYS_ABORT and MSR_TSX_FORCE_ABORT are enumerated.
> +             *  - XBEGIN instructions genuinely #UD.
> +             *  - MSR_TSX_FORCE_ABORT is write-discard and fails to hold its
> +             *    value.
> +             *  - HLE and RTM are not enumerated, despite
> +             *    MSR_TSX_FORCE_ABORT.TSX_CPUID_CLEAR being clear.
> +             *
> +             * Spot this case, and treat it as if no TSX is available at all.
> +             * This will prevent Xen from thinking it's safe to offer HLE/RTM
> +             * to VMs.
> +             */
> +            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
> +            {
> +                printk(XENLOG_ERR
> +                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",
> +                       boot_cpu_data.x86, boot_cpu_data.x86_model,
> +                       boot_cpu_data.x86_mask, this_cpu(cpu_sig).rev);
> +
> +                setup_clear_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT);
> +                setup_clear_cpu_cap(X86_FEATURE_TSX_FORCE_ABORT);
> +
> +                if ( opt_tsx < 0 )
> +                    opt_tsx = -2;
> +
> +                goto done_setup;
> +            }
> +
>              /*
>               * Probe for the June 2021 microcode which de-features TSX on
>               * client parts.  (Note - this is a subset of parts impacted by
> @@ -128,15 +169,8 @@ void tsx_init(void)
>               * read as zero if TSX_FORCE_ABORT.ENABLE_RTM has been set before
>               * we run.
>               */
> -            if ( !has_rtm_always_abort )
> -            {
> -                uint64_t val;
> -
> -                rdmsrl(MSR_TSX_FORCE_ABORT, val);
> -
> -                if ( val & TSX_ENABLE_RTM )
> -                    has_rtm_always_abort = true;
> -            }
> +            if ( val & TSX_ENABLE_RTM )
> +                has_rtm_always_abort = true;
>  
>              /*
>               * If no explicit tsx= option is provided, pick a default.
> @@ -191,6 +225,7 @@ void tsx_init(void)
>              setup_force_cpu_cap(X86_FEATURE_RTM);
>          }
>      }
> + done_setup:
>  
>      /*
>       * Note: MSR_TSX_CTRL is enumerated on TSX-enabled MDS_NO and later parts.
> 
> base-commit: 6117179dd99958e4ef2687617d12c9b15bdbae24
> -- 
> 2.30.2
>
Jan Beulich April 4, 2024, 12:45 p.m. UTC | #2
On 04.04.2024 12:41, Andrew Cooper wrote:
> @@ -9,6 +10,7 @@
>   *  -1 => Default, altered to 0/1 (if unspecified) by:
>   *                 - TAA heuristics/settings for speculative safety
>   *                 - "TSX vs PCR3" select for TSX memory ordering safety
> + *  -2 => Implicit tsx=0 (from RTM_ALWAYS_ABORT vs RTM mismatch)
>   *  -3 => Implicit tsx=1 (feed-through from spec-ctrl=0)
>   *
>   * This is arranged such that the bottom bit encodes whether TSX is actually
> @@ -114,11 +116,50 @@ void tsx_init(void)
>  
>          if ( cpu_has_tsx_force_abort )
>          {
> +            uint64_t val;
> +
>              /*
> -             * On an early TSX-enable Skylake part subject to the memory
> +             * On an early TSX-enabled Skylake part subject to the memory
>               * ordering erratum, with at least the March 2019 microcode.
>               */
>  
> +            rdmsrl(MSR_TSX_FORCE_ABORT, val);
> +
> +            /*
> +             * At the time of writing (April 2024), it was discovered that
> +             * some parts (e.g. CoffeeLake 8th Gen, 06-9e-0a, ucode 0xf6)
> +             * advertise RTM_ALWAYS_ABORT, but XBEGIN instructions #UD.  Other
> +             * similar parts (e.g. KabyLake Xeon-E3, 06-9e-09, ucode 0xf8)
> +             * operate as expected.
> +             *
> +             * In this case:
> +             *  - RTM_ALWAYS_ABORT and MSR_TSX_FORCE_ABORT are enumerated.
> +             *  - XBEGIN instructions genuinely #UD.
> +             *  - MSR_TSX_FORCE_ABORT is write-discard and fails to hold its
> +             *    value.
> +             *  - HLE and RTM are not enumerated, despite
> +             *    MSR_TSX_FORCE_ABORT.TSX_CPUID_CLEAR being clear.

Of these 4 items you use the first and last here. It took me some time to
figure that the middle two are (aiui) only informational, and that you
assume that first and last together are sufficient to uniquely identify
the problematic parts. Separating the two groups a little might be helpful.

For the write-discard property, how was that determined? Does it affect all
writable bits?

> +             * Spot this case, and treat it as if no TSX is available at all.
> +             * This will prevent Xen from thinking it's safe to offer HLE/RTM
> +             * to VMs.
> +             */
> +            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
> +            {
> +                printk(XENLOG_ERR
> +                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",

This isn't really firmware, is it? At least I wouldn't call microcode
(assuming that's where the bad behavior is rooted) firmware.

> +                       boot_cpu_data.x86, boot_cpu_data.x86_model,
> +                       boot_cpu_data.x86_mask, this_cpu(cpu_sig).rev);
> +
> +                setup_clear_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT);

Instead of the "goto" below, wouldn't it be better to also force
has_rtm_always_abort to false along with this, thus skipping the
setup_force_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT) further down? That would
leave things a little less awkward flow-wise, imo. The one thing not
becoming clear from the commentary above is whether cpu_has_tsx_ctrl might
be true, and hence RTM/HLE still becoming (wrongly) set, if done that way.

Jan

> +                setup_clear_cpu_cap(X86_FEATURE_TSX_FORCE_ABORT);
> +
> +                if ( opt_tsx < 0 )
> +                    opt_tsx = -2;
> +
> +                goto done_setup;
> +            }
> +
>              /*
>               * Probe for the June 2021 microcode which de-features TSX on
>               * client parts.  (Note - this is a subset of parts impacted by
> @@ -128,15 +169,8 @@ void tsx_init(void)
>               * read as zero if TSX_FORCE_ABORT.ENABLE_RTM has been set before
>               * we run.
>               */
> -            if ( !has_rtm_always_abort )
> -            {
> -                uint64_t val;
> -
> -                rdmsrl(MSR_TSX_FORCE_ABORT, val);
> -
> -                if ( val & TSX_ENABLE_RTM )
> -                    has_rtm_always_abort = true;
> -            }
> +            if ( val & TSX_ENABLE_RTM )
> +                has_rtm_always_abort = true;
>  
>              /*
>               * If no explicit tsx= option is provided, pick a default.
> @@ -191,6 +225,7 @@ void tsx_init(void)
>              setup_force_cpu_cap(X86_FEATURE_RTM);
>          }
>      }
> + done_setup:
>  
>      /*
>       * Note: MSR_TSX_CTRL is enumerated on TSX-enabled MDS_NO and later parts.
> 
> base-commit: 6117179dd99958e4ef2687617d12c9b15bdbae24
Andrew Cooper April 4, 2024, 1:22 p.m. UTC | #3
On 04/04/2024 1:45 pm, Jan Beulich wrote:
> On 04.04.2024 12:41, Andrew Cooper wrote:
>> @@ -9,6 +10,7 @@
>>   *  -1 => Default, altered to 0/1 (if unspecified) by:
>>   *                 - TAA heuristics/settings for speculative safety
>>   *                 - "TSX vs PCR3" select for TSX memory ordering safety
>> + *  -2 => Implicit tsx=0 (from RTM_ALWAYS_ABORT vs RTM mismatch)
>>   *  -3 => Implicit tsx=1 (feed-through from spec-ctrl=0)
>>   *
>>   * This is arranged such that the bottom bit encodes whether TSX is actually
>> @@ -114,11 +116,50 @@ void tsx_init(void)
>>  
>>          if ( cpu_has_tsx_force_abort )
>>          {
>> +            uint64_t val;
>> +
>>              /*
>> -             * On an early TSX-enable Skylake part subject to the memory
>> +             * On an early TSX-enabled Skylake part subject to the memory
>>               * ordering erratum, with at least the March 2019 microcode.
>>               */
>>  
>> +            rdmsrl(MSR_TSX_FORCE_ABORT, val);
>> +
>> +            /*
>> +             * At the time of writing (April 2024), it was discovered that
>> +             * some parts (e.g. CoffeeLake 8th Gen, 06-9e-0a, ucode 0xf6)
>> +             * advertise RTM_ALWAYS_ABORT, but XBEGIN instructions #UD.  Other
>> +             * similar parts (e.g. KabyLake Xeon-E3, 06-9e-09, ucode 0xf8)
>> +             * operate as expected.
>> +             *
>> +             * In this case:
>> +             *  - RTM_ALWAYS_ABORT and MSR_TSX_FORCE_ABORT are enumerated.
>> +             *  - XBEGIN instructions genuinely #UD.
>> +             *  - MSR_TSX_FORCE_ABORT is write-discard and fails to hold its
>> +             *    value.
>> +             *  - HLE and RTM are not enumerated, despite
>> +             *    MSR_TSX_FORCE_ABORT.TSX_CPUID_CLEAR being clear.
> Of these 4 items you use the first and last here. It took me some time to
> figure that the middle two are (aiui) only informational, and that you
> assume that first and last together are sufficient to uniquely identify
> the problematic parts. Separating the two groups a little might be helpful.

All 4 points are relevant to the if() expression.

>
> For the write-discard property, how was that determined? Does it affect all
> writable bits?

Marek kindly ran a debugging patch for me last night to try and figure
out what was going on.

Currently, Xen tries to set 0x2 (TSX_CPUID_CLEAR) and debugging showed
it being read back as 0.

I didn't check anything else, but I have a strong suspicion that I know
exactly what's going wrong here.

The property the if() condition is mainly looking for is !RTM &&
!(MSR_TFA.CPUID_CLEAR) because that's an illegal state in a

>
>> +             * Spot this case, and treat it as if no TSX is available at all.
>> +             * This will prevent Xen from thinking it's safe to offer HLE/RTM
>> +             * to VMs.
>> +             */
>> +            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
>> +            {
>> +                printk(XENLOG_ERR
>> +                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",
> This isn't really firmware, is it? At least I wouldn't call microcode
> (assuming that's where the bad behavior is rooted) firmware.

Microcode is absolutely part of the system firmware.

>
>> +                       boot_cpu_data.x86, boot_cpu_data.x86_model,
>> +                       boot_cpu_data.x86_mask, this_cpu(cpu_sig).rev);
>> +
>> +                setup_clear_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT);
> Instead of the "goto" below, wouldn't it be better to also force
> has_rtm_always_abort to false along with this, thus skipping the
> setup_force_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT) further down?

I considered that and dismissed it.  It is more fragile, in a case were
really do want to treat this case as if TSX genuinely doesn't exist.

>  That would
> leave things a little less awkward flow-wise, imo. The one thing not
> becoming clear from the commentary above is whether cpu_has_tsx_ctrl might
> be true, and hence RTM/HLE still becoming (wrongly) set, if done that way.

MSR_TSX_CTRL and MSR_TSX_FORCE_ABORT exist on disjoint sets of CPUs. 
(The split being MDS_NO).

This is discussed explicitly lower down in the function, beyond the if (
once ) block.

~Andrew
Jan Beulich April 4, 2024, 1:32 p.m. UTC | #4
On 04.04.2024 15:22, Andrew Cooper wrote:
> On 04/04/2024 1:45 pm, Jan Beulich wrote:
>> On 04.04.2024 12:41, Andrew Cooper wrote:
>>> @@ -9,6 +10,7 @@
>>>   *  -1 => Default, altered to 0/1 (if unspecified) by:
>>>   *                 - TAA heuristics/settings for speculative safety
>>>   *                 - "TSX vs PCR3" select for TSX memory ordering safety
>>> + *  -2 => Implicit tsx=0 (from RTM_ALWAYS_ABORT vs RTM mismatch)
>>>   *  -3 => Implicit tsx=1 (feed-through from spec-ctrl=0)
>>>   *
>>>   * This is arranged such that the bottom bit encodes whether TSX is actually
>>> @@ -114,11 +116,50 @@ void tsx_init(void)
>>>  
>>>          if ( cpu_has_tsx_force_abort )
>>>          {
>>> +            uint64_t val;
>>> +
>>>              /*
>>> -             * On an early TSX-enable Skylake part subject to the memory
>>> +             * On an early TSX-enabled Skylake part subject to the memory
>>>               * ordering erratum, with at least the March 2019 microcode.
>>>               */
>>>  
>>> +            rdmsrl(MSR_TSX_FORCE_ABORT, val);
>>> +
>>> +            /*
>>> +             * At the time of writing (April 2024), it was discovered that
>>> +             * some parts (e.g. CoffeeLake 8th Gen, 06-9e-0a, ucode 0xf6)
>>> +             * advertise RTM_ALWAYS_ABORT, but XBEGIN instructions #UD.  Other
>>> +             * similar parts (e.g. KabyLake Xeon-E3, 06-9e-09, ucode 0xf8)
>>> +             * operate as expected.
>>> +             *
>>> +             * In this case:
>>> +             *  - RTM_ALWAYS_ABORT and MSR_TSX_FORCE_ABORT are enumerated.
>>> +             *  - XBEGIN instructions genuinely #UD.
>>> +             *  - MSR_TSX_FORCE_ABORT is write-discard and fails to hold its
>>> +             *    value.
>>> +             *  - HLE and RTM are not enumerated, despite
>>> +             *    MSR_TSX_FORCE_ABORT.TSX_CPUID_CLEAR being clear.
>> Of these 4 items you use the first and last here. It took me some time to
>> figure that the middle two are (aiui) only informational, and that you
>> assume that first and last together are sufficient to uniquely identify
>> the problematic parts. Separating the two groups a little might be helpful.
> 
> All 4 points are relevant to the if() expression.

In which way? You don't probe XBEGIN to see whether you get back #UD. And
you also don't probe the MSR to see whether written bits are discarded.

>> For the write-discard property, how was that determined? Does it affect all
>> writable bits?
> 
> Marek kindly ran a debugging patch for me last night to try and figure
> out what was going on.
> 
> Currently, Xen tries to set 0x2 (TSX_CPUID_CLEAR) and debugging showed
> it being read back as 0.
> 
> I didn't check anything else, but I have a strong suspicion that I know
> exactly what's going wrong here.

Hmm, at the risk of upsetting you: Is a suspicion really enough for a
firm statement in a comment?

> The property the if() condition is mainly looking for is !RTM &&
> !(MSR_TFA.CPUID_CLEAR) because that's an illegal state in a
> 
>>
>>> +             * Spot this case, and treat it as if no TSX is available at all.
>>> +             * This will prevent Xen from thinking it's safe to offer HLE/RTM
>>> +             * to VMs.
>>> +             */
>>> +            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
>>> +            {
>>> +                printk(XENLOG_ERR
>>> +                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",
>> This isn't really firmware, is it? At least I wouldn't call microcode
>> (assuming that's where the bad behavior is rooted) firmware.
> 
> Microcode is absolutely part of the system firmware.

The ucode ahead of being loaded into CPUs is, sure. But once in the CPU
(and there may not be any loading at least in theory), it's not anymore.
It becomes part of the CPU then, albeit I still wouldn't call it "hardware".

Plus saying "firmware" suggests that firmware vendors could do anything
about the situation, when I don't think they can.

Jan
Andrew Cooper April 5, 2024, 1:01 p.m. UTC | #5
On 04/04/2024 2:32 pm, Jan Beulich wrote:
> On 04.04.2024 15:22, Andrew Cooper wrote:
>> On 04/04/2024 1:45 pm, Jan Beulich wrote:
>>> For the write-discard property, how was that determined? Does it affect all
>>> writable bits?
>> Marek kindly ran a debugging patch for me last night to try and figure
>> out what was going on.
>>
>> Currently, Xen tries to set 0x2 (TSX_CPUID_CLEAR) and debugging showed
>> it being read back as 0.
>>
>> I didn't check anything else, but I have a strong suspicion that I know
>> exactly what's going wrong here.
> Hmm, at the risk of upsetting you: Is a suspicion really enough for a
> firm statement in a comment?

The statement is all demonstrable properties.

The suspicion is about *why* we've ended up with the properties we have,
and is based on my involvement in the original planning for this.

>> The property the if() condition is mainly looking for is !RTM &&
>> !(MSR_TFA.CPUID_CLEAR) because that's an illegal state in a
>>
>>>> +             * Spot this case, and treat it as if no TSX is available at all.
>>>> +             * This will prevent Xen from thinking it's safe to offer HLE/RTM
>>>> +             * to VMs.
>>>> +             */
>>>> +            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
>>>> +            {
>>>> +                printk(XENLOG_ERR
>>>> +                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",
>>> This isn't really firmware, is it? At least I wouldn't call microcode
>>> (assuming that's where the bad behavior is rooted) firmware.
>> Microcode is absolutely part of the system firmware.
> The ucode ahead of being loaded into CPUs is, sure. But once in the CPU
> (and there may not be any loading at least in theory), it's not anymore.

You appear to have a very singular impression of what does and does not
constitute firmware.

If you can change Intel and AMD's mind on this matter, feel free to
submit a patch changing the wording here.

~Andrew
Jan Beulich April 5, 2024, 1:25 p.m. UTC | #6
On 05.04.2024 15:01, Andrew Cooper wrote:
> On 04/04/2024 2:32 pm, Jan Beulich wrote:
>> On 04.04.2024 15:22, Andrew Cooper wrote:
>>> On 04/04/2024 1:45 pm, Jan Beulich wrote:
>>>>> +             * Spot this case, and treat it as if no TSX is available at all.
>>>>> +             * This will prevent Xen from thinking it's safe to offer HLE/RTM
>>>>> +             * to VMs.
>>>>> +             */
>>>>> +            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
>>>>> +            {
>>>>> +                printk(XENLOG_ERR
>>>>> +                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",
>>>> This isn't really firmware, is it? At least I wouldn't call microcode
>>>> (assuming that's where the bad behavior is rooted) firmware.
>>> Microcode is absolutely part of the system firmware.
>> The ucode ahead of being loaded into CPUs is, sure. But once in the CPU
>> (and there may not be any loading at least in theory), it's not anymore.
> 
> You appear to have a very singular impression of what does and does not
> constitute firmware.

Not so singular, I would say: https://en.wikipedia.org/wiki/Firmware
The only mention of microcode there is for historical context, afaics.

Jan

> If you can change Intel and AMD's mind on this matter, feel free to
> submit a patch changing the wording here.
> 
> ~Andrew
diff mbox series

Patch

diff --git a/xen/arch/x86/tsx.c b/xen/arch/x86/tsx.c
index 50d8059f23a9..41bb39d10074 100644
--- a/xen/arch/x86/tsx.c
+++ b/xen/arch/x86/tsx.c
@@ -1,5 +1,6 @@ 
 #include <xen/init.h>
 #include <xen/param.h>
+#include <asm/microcode.h>
 #include <asm/msr.h>
 
 /*
@@ -9,6 +10,7 @@ 
  *  -1 => Default, altered to 0/1 (if unspecified) by:
  *                 - TAA heuristics/settings for speculative safety
  *                 - "TSX vs PCR3" select for TSX memory ordering safety
+ *  -2 => Implicit tsx=0 (from RTM_ALWAYS_ABORT vs RTM mismatch)
  *  -3 => Implicit tsx=1 (feed-through from spec-ctrl=0)
  *
  * This is arranged such that the bottom bit encodes whether TSX is actually
@@ -114,11 +116,50 @@  void tsx_init(void)
 
         if ( cpu_has_tsx_force_abort )
         {
+            uint64_t val;
+
             /*
-             * On an early TSX-enable Skylake part subject to the memory
+             * On an early TSX-enabled Skylake part subject to the memory
              * ordering erratum, with at least the March 2019 microcode.
              */
 
+            rdmsrl(MSR_TSX_FORCE_ABORT, val);
+
+            /*
+             * At the time of writing (April 2024), it was discovered that
+             * some parts (e.g. CoffeeLake 8th Gen, 06-9e-0a, ucode 0xf6)
+             * advertise RTM_ALWAYS_ABORT, but XBEGIN instructions #UD.  Other
+             * similar parts (e.g. KabyLake Xeon-E3, 06-9e-09, ucode 0xf8)
+             * operate as expected.
+             *
+             * In this case:
+             *  - RTM_ALWAYS_ABORT and MSR_TSX_FORCE_ABORT are enumerated.
+             *  - XBEGIN instructions genuinely #UD.
+             *  - MSR_TSX_FORCE_ABORT is write-discard and fails to hold its
+             *    value.
+             *  - HLE and RTM are not enumerated, despite
+             *    MSR_TSX_FORCE_ABORT.TSX_CPUID_CLEAR being clear.
+             *
+             * Spot this case, and treat it as if no TSX is available at all.
+             * This will prevent Xen from thinking it's safe to offer HLE/RTM
+             * to VMs.
+             */
+            if ( val == 0 && cpu_has_rtm_always_abort && !cpu_has_rtm )
+            {
+                printk(XENLOG_ERR
+                       "FIRMWARE BUG: CPU %02x-%02x-%02x, ucode 0x%08x: RTM_ALWAYS_ABORT vs RTM mismatch\n",
+                       boot_cpu_data.x86, boot_cpu_data.x86_model,
+                       boot_cpu_data.x86_mask, this_cpu(cpu_sig).rev);
+
+                setup_clear_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT);
+                setup_clear_cpu_cap(X86_FEATURE_TSX_FORCE_ABORT);
+
+                if ( opt_tsx < 0 )
+                    opt_tsx = -2;
+
+                goto done_setup;
+            }
+
             /*
              * Probe for the June 2021 microcode which de-features TSX on
              * client parts.  (Note - this is a subset of parts impacted by
@@ -128,15 +169,8 @@  void tsx_init(void)
              * read as zero if TSX_FORCE_ABORT.ENABLE_RTM has been set before
              * we run.
              */
-            if ( !has_rtm_always_abort )
-            {
-                uint64_t val;
-
-                rdmsrl(MSR_TSX_FORCE_ABORT, val);
-
-                if ( val & TSX_ENABLE_RTM )
-                    has_rtm_always_abort = true;
-            }
+            if ( val & TSX_ENABLE_RTM )
+                has_rtm_always_abort = true;
 
             /*
              * If no explicit tsx= option is provided, pick a default.
@@ -191,6 +225,7 @@  void tsx_init(void)
             setup_force_cpu_cap(X86_FEATURE_RTM);
         }
     }
+ done_setup:
 
     /*
      * Note: MSR_TSX_CTRL is enumerated on TSX-enabled MDS_NO and later parts.