diff mbox

x86/cpuid: fix dom0 crash on skylake machine

Message ID 574EA4F0.5030607@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Cooper June 1, 2016, 9:03 a.m. UTC
On 01/06/16 05:58, Luwei Kang wrote:
> CPUID.0XD.0X0.EAX is from machine value for dom0, and dom0 kernel will xsetbv
> with xfeatures_mask that is from CPUID.0XD.0X0.EAX, but handle_xsetbv has
> ingored XSTATE_PKRU with hardware protection fault emulation, so dom0 kernel
> will crash on skylake machine with PKRU support.
>
> Signed-off-by: Luwei Kang <luwei.kang@intel.com>
> ---
>  xen/arch/x86/traps.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
> index 1ef8401..5e72e44 100644
> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -1100,6 +1100,9 @@ void pv_cpuid(struct cpu_user_regs *regs)
>               */
>              if ( !is_control_domain(currd) && !is_hardware_domain(currd) )
>                  cpuid_count(leaf, subleaf, &tmp, &b, &tmp, &tmp);
> +
> +            /* PV is not supported by XSTATE_PKRU. */
> +            a &= ~XSTATE_PKRU;
>              break;
>          }
>  

While this does work, it undoes some of the work I started with my cpuid
improvements in 4.7

Does the attached patch also resolve your issue?

~Andrew

Comments

Jan Beulich June 1, 2016, 9:17 a.m. UTC | #1
>>> On 01.06.16 at 11:03, <andrew.cooper3@citrix.com> wrote:
> While this does work, it undoes some of the work I started with my cpuid
> improvements in 4.7
> 
> Does the attached patch also resolve your issue?

While that's much better than the original, I don't think it's quite
enough. The rest of the domain policy should be taken into account
(and I think I had suggested to do so during review of your CPUID
rework series), i.e. this can't be calculated once for every domain.
And then, as said in reply to the original patch, handle_xsetbv()'s
checking should be generalized from the special casing of PKRU (or
if we don't want that, then that special case would better get
removed for consistency reasons).

Jan
Huaitong Han June 1, 2016, 9:21 a.m. UTC | #2
Y, I think it works well, and more better.

to Luwei: you can test if the problem is solved. 

On Wed, 2016-06-01 at 10:03 +0100, Andrew Cooper wrote:
> On 01/06/16 05:58, Luwei Kang wrote:

> > CPUID.0XD.0X0.EAX is from machine value for dom0, and dom0 kernel will xsetbv

> > with xfeatures_mask that is from CPUID.0XD.0X0.EAX, but handle_xsetbv has

> > ingored XSTATE_PKRU with hardware protection fault emulation, so dom0 kernel

> > will crash on skylake machine with PKRU support.

> >

> > Signed-off-by: Luwei Kang <luwei.kang@intel.com>

> > ---

> >  xen/arch/x86/traps.c | 3 +++

> >  1 file changed, 3 insertions(+)

> >

> > diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c

> > index 1ef8401..5e72e44 100644

> > --- a/xen/arch/x86/traps.c

> > +++ b/xen/arch/x86/traps.c

> > @@ -1100,6 +1100,9 @@ void pv_cpuid(struct cpu_user_regs *regs)

> >               */

> >              if ( !is_control_domain(currd) && !is_hardware_domain(currd) )

> >                  cpuid_count(leaf, subleaf, &tmp, &b, &tmp, &tmp);

> > +

> > +            /* PV is not supported by XSTATE_PKRU. */

> > +            a &= ~XSTATE_PKRU;

> >              break;

> >          }

> >  

> 

> While this does work, it undoes some of the work I started with my cpuid

> improvements in 4.7

> 

> Does the attached patch also resolve your issue?

> 

> ~Andrew
Wei Liu June 1, 2016, 9:30 a.m. UTC | #3
On Wed, Jun 01, 2016 at 10:03:44AM +0100, Andrew Cooper wrote:
>  
>  static void __init calculate_hvm_featureset(void)
> @@ -179,7 +206,7 @@ static void __init calculate_hvm_featureset(void)
>              __clear_bit(X86_FEATURE_PCOMMIT, hvm_featureset);
>      }
>  
> -    sanitise_featureset(hvm_featureset);
> +    sanitise_featureset(hvm_featureset, & hvm_xfeature_mask);

Nit: extraneous space after "&".

Wei.
Andrew Cooper June 1, 2016, 9:45 a.m. UTC | #4
On 01/06/16 10:30, Wei Liu wrote:
> On Wed, Jun 01, 2016 at 10:03:44AM +0100, Andrew Cooper wrote:
>>  
>>  static void __init calculate_hvm_featureset(void)
>> @@ -179,7 +206,7 @@ static void __init calculate_hvm_featureset(void)
>>              __clear_bit(X86_FEATURE_PCOMMIT, hvm_featureset);
>>      }
>>  
>> -    sanitise_featureset(hvm_featureset);
>> +    sanitise_featureset(hvm_featureset, & hvm_xfeature_mask);
> Nit: extraneous space after "&".

Yeah - I noticed that and fixed it up after posting the email.

~Andrew
Luwei Kang June 1, 2016, 10:54 a.m. UTC | #5
Thank  you Andrew Cooper, this patch indeed resolve my issue and  two point need modify.

The code need  move ahead of "break;"
@@ -1101,6 +1101,9 @@ void pv_cpuid(struct cpu_user_regs *regs)
             if ( !is_control_domain(currd) && !is_hardware_domain(currd) )
                 cpuid_count(leaf, subleaf, &tmp, &b, &tmp, &tmp);
             break;
+
+            a &= (uint32_t)pv_xfeature_mask;
+            d &= (uint32_t)(pv_xfeature_mask >> 32);
         }

extraneous space after "&".
-    sanitise_featureset(hvm_featureset);
+    sanitise_featureset(hvm_featureset, & hvm_xfeature_mask);


-----Original Message-----
From: Andrew Cooper [mailto:andrew.cooper3@citrix.com] 
Sent: Wednesday, June 1, 2016 5:04 PM
To: Kang, Luwei <luwei.kang@intel.com>; xen-devel@lists.xen.org
Cc: jbeulich@suse.com; Han, Huaitong <huaitong.han@intel.com>; Wang, Yong Y <yong.y.wang@intel.com>
Subject: Re: [PATCH] x86/cpuid: fix dom0 crash on skylake machine

On 01/06/16 05:58, Luwei Kang wrote:
> CPUID.0XD.0X0.EAX is from machine value for dom0, and dom0 kernel will 
> xsetbv with xfeatures_mask that is from CPUID.0XD.0X0.EAX, but 
> handle_xsetbv has ingored XSTATE_PKRU with hardware protection fault 
> emulation, so dom0 kernel will crash on skylake machine with PKRU support.
>
> Signed-off-by: Luwei Kang <luwei.kang@intel.com>
> ---
>  xen/arch/x86/traps.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 
> 1ef8401..5e72e44 100644
> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -1100,6 +1100,9 @@ void pv_cpuid(struct cpu_user_regs *regs)
>               */
>              if ( !is_control_domain(currd) && !is_hardware_domain(currd) )
>                  cpuid_count(leaf, subleaf, &tmp, &b, &tmp, &tmp);
> +
> +            /* PV is not supported by XSTATE_PKRU. */
> +            a &= ~XSTATE_PKRU;
>              break;
>          }
>  

While this does work, it undoes some of the work I started with my cpuid improvements in 4.7

Does the attached patch also resolve your issue?

~Andrew
Andrew Cooper June 1, 2016, 10:57 a.m. UTC | #6
On 01/06/16 11:54, Kang, Luwei wrote:
> Thank  you Andrew Cooper, this patch indeed resolve my issue and  two point need modify.
>
> The code need  move ahead of "break;"
> @@ -1101,6 +1101,9 @@ void pv_cpuid(struct cpu_user_regs *regs)
>              if ( !is_control_domain(currd) && !is_hardware_domain(currd) )
>                  cpuid_count(leaf, subleaf, &tmp, &b, &tmp, &tmp);
>              break;
> +
> +            a &= (uint32_t)pv_xfeature_mask;
> +            d &= (uint32_t)(pv_xfeature_mask >> 32);
>          }

Ah of course.  That is quite a silly mistake on my behalf.

>
> extraneous space after "&".
> -    sanitise_featureset(hvm_featureset);
> +    sanitise_featureset(hvm_featureset, & hvm_xfeature_mask);

I had already spotted and fixed this.

I will collect all feedback and post a formal patch to the list.

~Andrew
diff mbox

Patch

From 3cbb2a63fe368ac185e483b9ef5a8504340a3702 Mon Sep 17 00:00:00 2001
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Wed, 1 Jun 2016 10:00:12 +0100
Subject: [PATCH] xen/x86: Clip guests view of xfeature_mask at the per-domain
 maximum

---
 xen/arch/x86/cpuid.c        | 33 ++++++++++++++++++++++++++++++---
 xen/arch/x86/hvm/hvm.c      |  3 +++
 xen/arch/x86/traps.c        |  3 +++
 xen/include/asm-x86/cpuid.h |  2 ++
 4 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
index e1e0e44..0a75d4a 100644
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -4,6 +4,7 @@ 
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/vmx/vmcs.h>
 #include <asm/processor.h>
+#include <asm/xstate.h>
 
 const uint32_t known_features[] = INIT_KNOWN_FEATURES;
 const uint32_t special_features[] = INIT_SPECIAL_FEATURES;
@@ -17,11 +18,14 @@  uint32_t __read_mostly raw_featureset[FSCAPINTS];
 uint32_t __read_mostly pv_featureset[FSCAPINTS];
 uint32_t __read_mostly hvm_featureset[FSCAPINTS];
 
-static void __init sanitise_featureset(uint32_t *fs)
+uint64_t __read_mostly pv_xfeature_mask, __read_mostly hvm_xfeature_mask;
+
+static void __init sanitise_featureset(uint32_t *fs, uint64_t *xfeature_mask)
 {
     /* for_each_set_bit() uses unsigned longs.  Extend with zeroes. */
     uint32_t disabled_features[
         ROUNDUP(FSCAPINTS, sizeof(unsigned long)/sizeof(uint32_t))] = {};
+    uint64_t mask = 0;
     unsigned int i;
 
     for ( i = 0; i < FSCAPINTS; ++i )
@@ -62,6 +66,29 @@  static void __init sanitise_featureset(uint32_t *fs)
      */
     fs[FEATURESET_e1d] = ((fs[FEATURESET_1d]  &  CPUID_COMMON_1D_FEATURES) |
                           (fs[FEATURESET_e1d] & ~CPUID_COMMON_1D_FEATURES));
+
+    /*
+     * Calculate the maximum applicable xfeature mask, based on the
+     * featureset.
+     */
+    if ( test_bit(X86_FEATURE_XSAVE, fs) )
+    {
+        mask = XSTATE_SSE | XSTATE_FP;
+
+        if ( test_bit(X86_FEATURE_AVX, fs) )
+            mask |= XSTATE_YMM;
+
+        if ( test_bit(X86_FEATURE_MPX, fs) )
+            mask |= XSTATE_BNDREGS | XSTATE_BNDCSR;
+
+        if ( test_bit(X86_FEATURE_PKU, fs) )
+            mask |= XSTATE_PKRU;
+
+        if ( test_bit(X86_FEATURE_LWP, fs) )
+            mask |= XSTATE_LWP;
+    }
+
+    *xfeature_mask = mask;
 }
 
 static void __init calculate_raw_featureset(void)
@@ -119,7 +146,7 @@  static void __init calculate_pv_featureset(void)
     __set_bit(X86_FEATURE_X2APIC, pv_featureset);
     __set_bit(X86_FEATURE_CMP_LEGACY, pv_featureset);
 
-    sanitise_featureset(pv_featureset);
+    sanitise_featureset(pv_featureset, &pv_xfeature_mask);
 }
 
 static void __init calculate_hvm_featureset(void)
@@ -179,7 +206,7 @@  static void __init calculate_hvm_featureset(void)
             __clear_bit(X86_FEATURE_PCOMMIT, hvm_featureset);
     }
 
-    sanitise_featureset(hvm_featureset);
+    sanitise_featureset(hvm_featureset, & hvm_xfeature_mask);
 }
 
 void __init calculate_featuresets(void)
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 5040a5c..8678da9 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3448,6 +3448,9 @@  void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
                 if ( (_eax + _ebx) > *ebx )
                     *ebx = _eax + _ebx;
             }
+
+            *eax &= (uint32_t)hvm_xfeature_mask;
+            *edx &= (uint32_t)(hvm_xfeature_mask >> 32);
         }
 
         if ( count == 1 )
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 1ef8401..81935b8 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1101,6 +1101,9 @@  void pv_cpuid(struct cpu_user_regs *regs)
             if ( !is_control_domain(currd) && !is_hardware_domain(currd) )
                 cpuid_count(leaf, subleaf, &tmp, &b, &tmp, &tmp);
             break;
+
+            a &= (uint32_t)pv_xfeature_mask;
+            d &= (uint32_t)(pv_xfeature_mask >> 32);
         }
 
         case 1:
diff --git a/xen/include/asm-x86/cpuid.h b/xen/include/asm-x86/cpuid.h
index 9a21c25..231c6d4 100644
--- a/xen/include/asm-x86/cpuid.h
+++ b/xen/include/asm-x86/cpuid.h
@@ -29,6 +29,8 @@  extern uint32_t raw_featureset[FSCAPINTS];
 extern uint32_t pv_featureset[FSCAPINTS];
 extern uint32_t hvm_featureset[FSCAPINTS];
 
+extern uint64_t pv_xfeature_mask, hvm_xfeature_mask;
+
 void calculate_featuresets(void);
 
 const uint32_t *lookup_deep_deps(uint32_t feature);
-- 
2.1.4