diff mbox series

[2/5] x86: Refactor microcode_update() hypercall with flags field

Message ID 20240405121128.260493-3-fouad.hilly@cloud.com (mailing list archive)
State Superseded
Headers show
Series x86/xen-ucode: Introduce --force option | expand

Commit Message

Fouad Hilly April 5, 2024, 12:11 p.m. UTC
Refactor microcode_update() hypercall by adding flags field.
Introduce XENPF_microcode_update2 hypercall to handle flags field.

Signed-off-by: Fouad Hilly <fouad.hilly@cloud.com>
---
 xen/arch/x86/cpu/microcode/core.c    | 12 +++++++++---
 xen/arch/x86/include/asm/microcode.h |  2 +-
 xen/arch/x86/platform_hypercall.c    | 12 +++++++++++-
 xen/include/public/platform.h        |  8 ++++++++
 4 files changed, 29 insertions(+), 5 deletions(-)

Comments

Jan Beulich April 8, 2024, 9:16 a.m. UTC | #1
On 05.04.2024 14:11, Fouad Hilly wrote:
> @@ -708,11 +712,13 @@ static long cf_check microcode_update_helper(void *data)
>      return ret;
>  }
>  
> -int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
> +int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags)
>  {
>      int ret;
>      struct ucode_buf *buffer;
>  
> +    ucode_force_flag = (flags == XENPF_UCODE_FLAG_FORCE_SET)? 1: 0;

No need for ?: when the lhs has type bool.

But - do we really need to resort to parameter passing via static variables
here? If it's unavoidable, its setting needs to move inside a locked region
(with that region covering everything up to all consumption of the value).

Further, to avoid the same issue again when another flag wants adding, you
want to check that all other bits in the flags field are clear.

> --- a/xen/arch/x86/include/asm/microcode.h
> +++ b/xen/arch/x86/include/asm/microcode.h
> @@ -22,7 +22,7 @@ struct cpu_signature {
>  DECLARE_PER_CPU(struct cpu_signature, cpu_sig);
>  
>  void microcode_set_module(unsigned int idx);
> -int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len);
> +int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags);

Nit: Too long line.

> --- a/xen/include/public/platform.h
> +++ b/xen/include/public/platform.h
> @@ -99,6 +99,10 @@ struct xenpf_microcode_update {
>      /* IN variables. */
>      XEN_GUEST_HANDLE(const_void) data;/* Pointer to microcode data */
>      uint32_t length;                  /* Length of microcode data. */
> +    uint32_t flags;                   /* Flags to be passed with ucode. */
> +/* Force to skip microcode version check when set */
> +#define XENPF_UCODE_FLAG_FORCE_NOT_SET 0
> +#define XENPF_UCODE_FLAG_FORCE_SET     1
>  };

The safety of this growing of an existing stable ABI struct wants at least
briefly mentioning in the description.

> @@ -624,6 +628,10 @@ struct xenpf_ucode_revision {
>  typedef struct xenpf_ucode_revision xenpf_ucode_revision_t;
>  DEFINE_XEN_GUEST_HANDLE(xenpf_ucode_revision_t);
>  
> +/* Hypercall to microcode_update with flags */
> +#define XENPF_microcode_update2    66
> +
> +

No double blank lines please.

Jan
Fouad Hilly April 23, 2024, 2:53 p.m. UTC | #2
On Mon, Apr 8, 2024 at 10:16 AM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 05.04.2024 14:11, Fouad Hilly wrote:
> > @@ -708,11 +712,13 @@ static long cf_check microcode_update_helper(void *data)
> >      return ret;
> >  }
> >
> > -int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
> > +int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags)
> >  {
> >      int ret;
> >      struct ucode_buf *buffer;
> >
> > +    ucode_force_flag = (flags == XENPF_UCODE_FLAG_FORCE_SET)? 1: 0;
>
> No need for ?: when the lhs has type bool.
>
> But - do we really need to resort to parameter passing via static variables
> here? If it's unavoidable, its setting needs to move inside a locked region
> (with that region covering everything up to all consumption of the value).
There are many function calls and checks of the firmware between
microcode_update() and the actual update, which makes static variable
the viable option.
In V2 I broke it down between the actual update_flags (static) and
force_flag (local to firmware update function), I understand that
might not be enough, I will look into further improvement for
microcode_update flags in V3.
>
> Further, to avoid the same issue again when another flag wants adding, you
> want to check that all other bits in the flags field are clear.
The above check is checking all bits in the flags field. Are you
referring to flag per bit where multiple flags can be set
simultaneously?
>
> > --- a/xen/arch/x86/include/asm/microcode.h
> > +++ b/xen/arch/x86/include/asm/microcode.h
> > @@ -22,7 +22,7 @@ struct cpu_signature {
> >  DECLARE_PER_CPU(struct cpu_signature, cpu_sig);
> >
> >  void microcode_set_module(unsigned int idx);
> > -int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len);
> > +int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags);
>
> Nit: Too long line.
>
> > --- a/xen/include/public/platform.h
> > +++ b/xen/include/public/platform.h
> > @@ -99,6 +99,10 @@ struct xenpf_microcode_update {
> >      /* IN variables. */
> >      XEN_GUEST_HANDLE(const_void) data;/* Pointer to microcode data */
> >      uint32_t length;                  /* Length of microcode data. */
> > +    uint32_t flags;                   /* Flags to be passed with ucode. */
> > +/* Force to skip microcode version check when set */
> > +#define XENPF_UCODE_FLAG_FORCE_NOT_SET 0
> > +#define XENPF_UCODE_FLAG_FORCE_SET     1
> >  };
>
> The safety of this growing of an existing stable ABI struct wants at least
> briefly mentioning in the description.
>
> > @@ -624,6 +628,10 @@ struct xenpf_ucode_revision {
> >  typedef struct xenpf_ucode_revision xenpf_ucode_revision_t;
> >  DEFINE_XEN_GUEST_HANDLE(xenpf_ucode_revision_t);
> >
> > +/* Hypercall to microcode_update with flags */
> > +#define XENPF_microcode_update2    66
> > +
> > +
>
> No double blank lines please.
>
> Jan

Thanks,

Fouad
Jan Beulich April 23, 2024, 4:10 p.m. UTC | #3
On 23.04.2024 16:53, Fouad Hilly wrote:
> On Mon, Apr 8, 2024 at 10:16 AM Jan Beulich <jbeulich@suse.com> wrote:
>> On 05.04.2024 14:11, Fouad Hilly wrote:
>>> @@ -708,11 +712,13 @@ static long cf_check microcode_update_helper(void *data)
>>>      return ret;
>>>  }
>>>
>>> -int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
>>> +int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags)
>>>  {
>>>      int ret;
>>>      struct ucode_buf *buffer;
>>>
>>> +    ucode_force_flag = (flags == XENPF_UCODE_FLAG_FORCE_SET)? 1: 0;
>>
>> No need for ?: when the lhs has type bool.
>>
>> But - do we really need to resort to parameter passing via static variables
>> here? If it's unavoidable, its setting needs to move inside a locked region
>> (with that region covering everything up to all consumption of the value).
> There are many function calls and checks of the firmware between
> microcode_update() and the actual update, which makes static variable
> the viable option.
> In V2 I broke it down between the actual update_flags (static) and
> force_flag (local to firmware update function), I understand that
> might not be enough, I will look into further improvement for
> microcode_update flags in V3.
>>
>> Further, to avoid the same issue again when another flag wants adding, you
>> want to check that all other bits in the flags field are clear.
> The above check is checking all bits in the flags field. Are you
> referring to flag per bit where multiple flags can be set
> simultaneously?

No. What you do is treat a flags value of, say, 2 the same as a flags
value of 0. That's wrong when considering that the value 2 may gain a
meaning going forward. At this point you want to refuse flags values
other than 0 or 1.

Jan
diff mbox series

Patch

diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
index 1c9f66ea8a0f..f987b2bd632d 100644
--- a/xen/arch/x86/cpu/microcode/core.c
+++ b/xen/arch/x86/cpu/microcode/core.c
@@ -40,6 +40,8 @@ 
 #include <asm/processor.h>
 #include <asm/setup.h>
 
+#include <public/platform.h>
+
 #include "private.h"
 
 /*
@@ -100,6 +102,8 @@  static bool ucode_in_nmi = true;
 
 bool __read_mostly opt_ucode_allow_same;
 
+bool ucode_force_flag;
+
 /* Protected by microcode_mutex */
 static struct microcode_patch *microcode_cache;
 
@@ -633,12 +637,12 @@  static long cf_check microcode_update_helper(void *data)
                                   microcode_cache);
 
         if ( result != NEW_UCODE &&
-             !(opt_ucode_allow_same && result == SAME_UCODE) )
+             !((opt_ucode_allow_same || ucode_force_flag) && result == SAME_UCODE) )
         {
             spin_unlock(&microcode_mutex);
             printk(XENLOG_WARNING
                    "microcode: couldn't find any newer%s revision in the provided blob!\n",
-                   opt_ucode_allow_same ? " (or the same)" : "");
+                   (opt_ucode_allow_same || ucode_force_flag) ? " (or the same)" : "");
             microcode_free_patch(patch);
             ret = -ENOENT;
 
@@ -708,11 +712,13 @@  static long cf_check microcode_update_helper(void *data)
     return ret;
 }
 
-int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
+int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags)
 {
     int ret;
     struct ucode_buf *buffer;
 
+    ucode_force_flag = (flags == XENPF_UCODE_FLAG_FORCE_SET)? 1: 0;
+
     if ( len != (uint32_t)len )
         return -E2BIG;
 
diff --git a/xen/arch/x86/include/asm/microcode.h b/xen/arch/x86/include/asm/microcode.h
index 8f59b20b0289..bcba356b4134 100644
--- a/xen/arch/x86/include/asm/microcode.h
+++ b/xen/arch/x86/include/asm/microcode.h
@@ -22,7 +22,7 @@  struct cpu_signature {
 DECLARE_PER_CPU(struct cpu_signature, cpu_sig);
 
 void microcode_set_module(unsigned int idx);
-int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len);
+int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len, unsigned int flags);
 int early_microcode_init(unsigned long *module_map,
                          const struct multiboot_info *mbi);
 int microcode_init_cache(unsigned long *module_map,
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index 95467b88ab64..3b29ede8b316 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -311,7 +311,17 @@  ret_t do_platform_op(
 
         guest_from_compat_handle(data, op->u.microcode.data);
 
-        ret = microcode_update(data, op->u.microcode.length);
+        ret = microcode_update(data, op->u.microcode.length, 0);
+        break;
+    }
+
+    case XENPF_microcode_update2:
+    {
+        XEN_GUEST_HANDLE(const_void) data;
+
+        guest_from_compat_handle(data, op->u.microcode.data);
+
+        ret = microcode_update(data, op->u.microcode.length, op->u.microcode.flags);
         break;
     }
 
diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h
index 15777b541690..31e59ba3d07b 100644
--- a/xen/include/public/platform.h
+++ b/xen/include/public/platform.h
@@ -99,6 +99,10 @@  struct xenpf_microcode_update {
     /* IN variables. */
     XEN_GUEST_HANDLE(const_void) data;/* Pointer to microcode data */
     uint32_t length;                  /* Length of microcode data. */
+    uint32_t flags;                   /* Flags to be passed with ucode. */
+/* Force to skip microcode version check when set */
+#define XENPF_UCODE_FLAG_FORCE_NOT_SET 0
+#define XENPF_UCODE_FLAG_FORCE_SET     1
 };
 typedef struct xenpf_microcode_update xenpf_microcode_update_t;
 DEFINE_XEN_GUEST_HANDLE(xenpf_microcode_update_t);
@@ -624,6 +628,10 @@  struct xenpf_ucode_revision {
 typedef struct xenpf_ucode_revision xenpf_ucode_revision_t;
 DEFINE_XEN_GUEST_HANDLE(xenpf_ucode_revision_t);
 
+/* Hypercall to microcode_update with flags */
+#define XENPF_microcode_update2    66
+
+
 /*
  * ` enum neg_errnoval
  * ` HYPERVISOR_platform_op(const struct xen_platform_op*);