diff mbox series

[for-4.13] x86/vlapic: allow setting APIC_SPIV_FOCUS_DISABLED in x2APIC mode

Message ID 20191120173920.8705-1-roger.pau@citrix.com (mailing list archive)
State Superseded
Headers show
Series [for-4.13] x86/vlapic: allow setting APIC_SPIV_FOCUS_DISABLED in x2APIC mode | expand

Commit Message

Roger Pau Monné Nov. 20, 2019, 5:39 p.m. UTC
Current code unconditionally prevents setting APIC_SPIV_FOCUS_DISABLED
regardless of the processor model, which is not correct according to
the specification.

Fix it by allowing setting APIC_SPIV_FOCUS_DISABLED based on the
domain cpuid policy.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Cc: Juergen Gross <jgross@suse.com>
---
 xen/arch/x86/hvm/vlapic.c | 9 +++++++++
 1 file changed, 9 insertions(+)

Comments

Roger Pau Monné Nov. 21, 2019, 9:17 a.m. UTC | #1
On Wed, Nov 20, 2019 at 06:39:20PM +0100, Roger Pau Monne wrote:
>      case APIC_SPIV:
>          if ( msr_content & ~(APIC_VECTOR_MASK | APIC_SPIV_APIC_ENABLED |
> +                             /*
> +                              * APIC_SPIV_FOCUS_DISABLED is not supported on

s/not supported/reserved/ would be better I think.

Roger.
Jan Beulich Nov. 21, 2019, 9:48 a.m. UTC | #2
On 20.11.2019 18:39, Roger Pau Monne wrote:
> Current code unconditionally prevents setting APIC_SPIV_FOCUS_DISABLED
> regardless of the processor model, which is not correct according to
> the specification.
> 
> Fix it by allowing setting APIC_SPIV_FOCUS_DISABLED based on the
> domain cpuid policy.

Would you mind adding half a sentence to clarify whether this is a
problem observed in practice, or simply found by code inspection?

> --- a/xen/arch/x86/hvm/vlapic.c
> +++ b/xen/arch/x86/hvm/vlapic.c
> @@ -977,6 +977,7 @@ int guest_wrmsr_x2apic(struct vcpu *v, uint32_t msr, uint64_t msr_content)
>  {
>      struct vlapic *vlapic = vcpu_vlapic(v);
>      uint32_t offset = (msr - MSR_X2APIC_FIRST) << 4;
> +    const struct cpuid_policy *cpuid = v->domain->arch.cpuid;

We commonly name such variables "cp".

> @@ -993,6 +994,14 @@ int guest_wrmsr_x2apic(struct vcpu *v, uint32_t msr, uint64_t msr_content)
>  
>      case APIC_SPIV:
>          if ( msr_content & ~(APIC_VECTOR_MASK | APIC_SPIV_APIC_ENABLED |
> +                             /*
> +                              * APIC_SPIV_FOCUS_DISABLED is not supported on
> +                              * Intel Pentium 4 and Xeon processors.
> +                              */
> +                             ((cpuid->x86_vendor != X86_VENDOR_INTEL ||
> +                               get_cpu_family(cpuid->basic.raw_fms, NULL,
> +                                              NULL) != 15) ?
> +                               APIC_SPIV_FOCUS_DISABLED : 0) |

Do we actually need this (virtual) family check? If I'm not mistaken
- physical family 0xf CPUs don't support x2APIC,
- in xAPIC mode, writing reserved bits wouldn't fault - such writes
  would simply be ignored.
Therefore I see no risk in always permitting the bit to get set
(like the corresponding xAPIC logic does, sadly by using a literal
number instead of APIC_SPIV_*). On the contrary, code seeing an
x2APIC might assume the flag to be settable regardless of family
(because implicitly it wouldn't expect to be on family 0xf).

If yes - "Xeon" is way too broad a statement here. Yes, Intel's doc
as well as old code elsewhere in Xen say so too, but since then the
name was used for a large range of family 6 server CPUs as well.

>                               (VLAPIC_VERSION & APIC_LVR_DIRECTED_EOI
>                                ? APIC_SPIV_DIRECTED_EOI : 0)) )
>              return X86EMUL_EXCEPTION;
> 

If you already take care of this family difference, wouldn't you
better address the other one (affecting the low 4 bits) as well
(at least in the xAPIC case)? (FAOD if the virtual family
dependency was dropped above, then I'd rather not see one
introduced for this case either.)

Jan
Roger Pau Monné Nov. 21, 2019, 10:05 a.m. UTC | #3
On Thu, Nov 21, 2019 at 10:48:16AM +0100, Jan Beulich wrote:
> On 20.11.2019 18:39, Roger Pau Monne wrote:
> > Current code unconditionally prevents setting APIC_SPIV_FOCUS_DISABLED
> > regardless of the processor model, which is not correct according to
> > the specification.
> > 
> > Fix it by allowing setting APIC_SPIV_FOCUS_DISABLED based on the
> > domain cpuid policy.
> 
> Would you mind adding half a sentence to clarify whether this is a
> problem observed in practice, or simply found by code inspection?

This was found by trying to boot the pvshim with x2APIC enabled, since
Xen will try to disable focus at init_bsp_APIC for the BSP. Note that
AFAICT this is not done for the APs, and setup_local_APIC will also
avoid setting the focus disabled bit.

I think the setting of the focus disable bit in init_bsp_APIC can be
removed, but that's a different issue.

> > --- a/xen/arch/x86/hvm/vlapic.c
> > +++ b/xen/arch/x86/hvm/vlapic.c
> > @@ -977,6 +977,7 @@ int guest_wrmsr_x2apic(struct vcpu *v, uint32_t msr, uint64_t msr_content)
> >  {
> >      struct vlapic *vlapic = vcpu_vlapic(v);
> >      uint32_t offset = (msr - MSR_X2APIC_FIRST) << 4;
> > +    const struct cpuid_policy *cpuid = v->domain->arch.cpuid;
> 
> We commonly name such variables "cp".

Ack, in any case this is going away.

> 
> > @@ -993,6 +994,14 @@ int guest_wrmsr_x2apic(struct vcpu *v, uint32_t msr, uint64_t msr_content)
> >  
> >      case APIC_SPIV:
> >          if ( msr_content & ~(APIC_VECTOR_MASK | APIC_SPIV_APIC_ENABLED |
> > +                             /*
> > +                              * APIC_SPIV_FOCUS_DISABLED is not supported on
> > +                              * Intel Pentium 4 and Xeon processors.
> > +                              */
> > +                             ((cpuid->x86_vendor != X86_VENDOR_INTEL ||
> > +                               get_cpu_family(cpuid->basic.raw_fms, NULL,
> > +                                              NULL) != 15) ?
> > +                               APIC_SPIV_FOCUS_DISABLED : 0) |
> 
> Do we actually need this (virtual) family check? If I'm not mistaken
> - physical family 0xf CPUs don't support x2APIC,

I assumed we exposed x2APIC support to all guests, regardless of
whether the underlying hardware supports it or not.

> - in xAPIC mode, writing reserved bits wouldn't fault - such writes
>   would simply be ignored.
> Therefore I see no risk in always permitting the bit to get set
> (like the corresponding xAPIC logic does, sadly by using a literal
> number instead of APIC_SPIV_*). On the contrary, code seeing an
> x2APIC might assume the flag to be settable regardless of family
> (because implicitly it wouldn't expect to be on family 0xf).

Right. TBH I had my doubts about this and I was also considering to
always allow setting the bit, at the end of day this is all
emulated. Since you agree I will drop the family dependence always
allow setting focus disabled.

Thanks, Roger.
diff mbox series

Patch

diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 9466258d6f..b318b4ed5c 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -977,6 +977,7 @@  int guest_wrmsr_x2apic(struct vcpu *v, uint32_t msr, uint64_t msr_content)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
     uint32_t offset = (msr - MSR_X2APIC_FIRST) << 4;
+    const struct cpuid_policy *cpuid = v->domain->arch.cpuid;
 
     /* The timer handling at least is unsafe outside of current context. */
     ASSERT(v == current);
@@ -993,6 +994,14 @@  int guest_wrmsr_x2apic(struct vcpu *v, uint32_t msr, uint64_t msr_content)
 
     case APIC_SPIV:
         if ( msr_content & ~(APIC_VECTOR_MASK | APIC_SPIV_APIC_ENABLED |
+                             /*
+                              * APIC_SPIV_FOCUS_DISABLED is not supported on
+                              * Intel Pentium 4 and Xeon processors.
+                              */
+                             ((cpuid->x86_vendor != X86_VENDOR_INTEL ||
+                               get_cpu_family(cpuid->basic.raw_fms, NULL,
+                                              NULL) != 15) ?
+                               APIC_SPIV_FOCUS_DISABLED : 0) |
                              (VLAPIC_VERSION & APIC_LVR_DIRECTED_EOI
                               ? APIC_SPIV_DIRECTED_EOI : 0)) )
             return X86EMUL_EXCEPTION;