diff mbox

[V7,3/3] x86/xsaves: ebx may return wrong value using CPUID eax=0xdh, ecx =1

Message ID 1459414657-7558-4-git-send-email-shuai.ruan@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shuai Ruan March 31, 2016, 8:57 a.m. UTC
From: Shuai Ruan <shuai.ruan@intel.com>

Refer to SDM 13.4.3 Extended Region of an XSAVE Area. The value return
by ecx[1] with cpuid function 0xdh and sub-fucntion i (i>1) indicates
the alignment of the state component i when the compacted format of the
extended region of an xsave area is used.

So when hvm/pv guest using CPUID eax=0xdh,ecx=1 to get the size of area
used for compacted format, we need to take alignment into consideration.

tools side is fixed by
"tools/libxc: Calculate xstate cpuid leaf from guest information"
by Andrew Cooper

Signed-off-by: Shuai Ruan <shuai.ruan@intel.com>
---
v2: Address comments by Jan:
1. take alignment into consideration in pv_cpuid.
2. fix coding style issues

 xen/arch/x86/hvm/hvm.c       |  6 +++++-
 xen/arch/x86/traps.c         | 12 ++++++++++++
 xen/arch/x86/xstate.c        |  2 +-
 xen/include/asm-x86/xstate.h |  1 +
 4 files changed, 19 insertions(+), 2 deletions(-)

Comments

Jan Beulich April 5, 2016, 8:31 a.m. UTC | #1
>>> On 31.03.16 at 10:57, <shuai.ruan@linux.intel.com> wrote:
> Refer to SDM 13.4.3 Extended Region of an XSAVE Area. The value return

No section numbers please - they tend to change.

> by ecx[1] with cpuid function 0xdh and sub-fucntion i (i>1) indicates

Either "0xd" or "0dh". And "function".

> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -1020,6 +1020,18 @@ void pv_cpuid(struct cpu_user_regs *regs)
>              a &= (boot_cpu_data.x86_capability[cpufeat_word(X86_FEATURE_XSAVEOPT)] &
>                    ~cpufeat_mask(X86_FEATURE_XSAVES));
>              b = c = d = 0;
> +            if ( cpu_has_xsavec )
> +            {
> +                b = XSTATE_AREA_MIN_SIZE;

Is this really correct namely when curr->arch.xcr0 == 0? If not, the
if() below should perhaps be combined with the if() above (and then
the same would apply to hvm_cpuid()).

> +                if ( curr->arch.xcr0 )
> +                    for( subleaf = 2; subleaf < 63; subleaf++ )
> +                        if ( (1ULL << subleaf) & curr->arch.xcr0 )

The first if() is redundant with this second one. If you really
mean to avoid the loop, then please also only check bits
2..62 in the first if().

Jan
Shuai Ruan April 6, 2016, 7:01 a.m. UTC | #2
On Tue, Apr 05, 2016 at 02:31:40AM -0600, Jan Beulich wrote:
> >>> On 31.03.16 at 10:57, <shuai.ruan@linux.intel.com> wrote:
> > Refer to SDM 13.4.3 Extended Region of an XSAVE Area. The value return
> 
> No section numbers please - they tend to change.
> 
> > by ecx[1] with cpuid function 0xdh and sub-fucntion i (i>1) indicates
> 
> Either "0xd" or "0dh". And "function".
> 
> > --- a/xen/arch/x86/traps.c
> > +++ b/xen/arch/x86/traps.c
> > @@ -1020,6 +1020,18 @@ void pv_cpuid(struct cpu_user_regs *regs)
> >              a &= (boot_cpu_data.x86_capability[cpufeat_word(X86_FEATURE_XSAVEOPT)] &
> >                    ~cpufeat_mask(X86_FEATURE_XSAVES));
> >              b = c = d = 0;
> > +            if ( cpu_has_xsavec )
> > +            {
> > +                b = XSTATE_AREA_MIN_SIZE;
> 
> Is this really correct namely when curr->arch.xcr0 == 0? If not, the
> if() below should perhaps be combined with the if() above (and then
> the same would apply to hvm_cpuid()).
> 
> > +                if ( curr->arch.xcr0 )
> > +                    for( subleaf = 2; subleaf < 63; subleaf++ )
> > +                        if ( (1ULL << subleaf) & curr->arch.xcr0 )
> 
> The first if() is redundant with this second one. If you really
> mean to avoid the loop, then please also only check bits
> 2..62 in the first if().
> 
Ok for all comments above.

Another question is whether we should add this in pv_cpuid() or not.
(which we have discussed in the previous thread).

Refer to SDM Volume 1 
"13.2 ENUMERATION OF CPU SUPPORT FOR XSAVE INSTRUCTIONS AND XSAVE-
SUPPORTED FEATURES"
— CPUID function 0DH, sub-function 1.
...
"EBX enumerates the size (in bytes) required by the XSAVES instruction
 for an XSAVE area containing all
 the state components corresponding to bits currently set in XCR0 |
 IA32_XSS."

From the descriptions above, EBX only be used when XSAVES is enabled.
So I think we should not deal with pv_cpuid() here. 
Any comments ?

> Jan
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
Jan Beulich April 7, 2016, 12:29 a.m. UTC | #3
>>> Shuai Ruan <shuai.ruan@linux.intel.com> 04/06/16 8:59 AM >>>
>Another question is whether we should add this in pv_cpuid() or not.
>(which we have discussed in the previous thread).
>
>Refer to SDM Volume 1 
>"13.2 ENUMERATION OF CPU SUPPORT FOR XSAVE INSTRUCTIONS AND XSAVE-
>SUPPORTED FEATURES"
>— CPUID function 0DH, sub-function 1.
>...
>"EBX enumerates the size (in bytes) required by the XSAVES instruction
 >for an XSAVE area containing all
 >the state components corresponding to bits currently set in XCR0 |
 >IA32_XSS."
>
>From the descriptions above, EBX only be used when XSAVES is enabled.
>So I think we should not deal with pv_cpuid() here. 

If it's mandated to be XSAVES only - yes. But why are you asking such a question?
It was you who proposed the change to pv_cpuid(), and it is you who should be
understanding the specifics of the various pieces of CPUID output related to XSAVE
better than me.

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 5aef3cb..c6cd4fb 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -4743,14 +4743,18 @@  void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
         }
         if ( count == 1 )
         {
-            if ( cpu_has_xsaves && cpu_has_vmx_xsaves )
+            if ( (cpu_has_xsaves && cpu_has_vmx_xsaves) || cpu_has_xsavec )
             {
                 *ebx = XSTATE_AREA_MIN_SIZE;
                 if ( v->arch.xcr0 | v->arch.hvm_vcpu.msr_xss )
                     for ( sub_leaf = 2; sub_leaf < 63; sub_leaf++ )
                         if ( (v->arch.xcr0 | v->arch.hvm_vcpu.msr_xss) &
                              (1ULL << sub_leaf) )
+                        {
+                            if ( test_bit(sub_leaf, &xstate_align) )
+                                *ebx = ROUNDUP(*ebx, 64);
                             *ebx += xstate_sizes[sub_leaf];
+                        }
             }
             else
                 *ebx = *ecx = *edx = 0;
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 6fbb1cf..8694da6 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1020,6 +1020,18 @@  void pv_cpuid(struct cpu_user_regs *regs)
             a &= (boot_cpu_data.x86_capability[cpufeat_word(X86_FEATURE_XSAVEOPT)] &
                   ~cpufeat_mask(X86_FEATURE_XSAVES));
             b = c = d = 0;
+            if ( cpu_has_xsavec )
+            {
+                b = XSTATE_AREA_MIN_SIZE;
+                if ( curr->arch.xcr0 )
+                    for( subleaf = 2; subleaf < 63; subleaf++ )
+                        if ( (1ULL << subleaf) & curr->arch.xcr0 )
+                        {
+                            if ( test_bit(subleaf, &xstate_align) )
+                                b = ROUNDUP(b, 64);
+                            b += xstate_sizes[subleaf];
+                        }
+            }
             break;
         }
         break;
diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c
index f4ea54d..850b778 100644
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -26,7 +26,7 @@  u64 __read_mostly xfeature_mask;
 
 static unsigned int *__read_mostly xstate_offsets;
 unsigned int *__read_mostly xstate_sizes;
-static u64 __read_mostly xstate_align;
+u64 __read_mostly xstate_align;
 static unsigned int __read_mostly xstate_features;
 
 static uint32_t __read_mostly mxcsr_mask = 0x0000ffbf;
diff --git a/xen/include/asm-x86/xstate.h b/xen/include/asm-x86/xstate.h
index 91d1c39..535443a 100644
--- a/xen/include/asm-x86/xstate.h
+++ b/xen/include/asm-x86/xstate.h
@@ -50,6 +50,7 @@ 
 #define XSTATE_ALIGN64 (1U << 1)
 
 extern u64 xfeature_mask;
+extern u64 xstate_align;
 extern unsigned int *xstate_sizes;
 
 /* extended state save area */