All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
@ 2022-12-08 13:26 Sergey Dyasli
  2022-12-08 13:26 ` [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU Sergey Dyasli
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Sergey Dyasli @ 2022-12-08 13:26 UTC (permalink / raw)
  To: xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné, Wei Liu, Sergey Dyasli

This is a preparatory step in order to do earlier microcode loading on
the boot CPU when the domain heap has not been initialized yet and
xmalloc still unavailable.

Add make_copy argument which will allow to load microcode directly from
the blob bypassing microcode_cache. Add const qualifiers where required.

Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 xen/arch/x86/cpu/microcode/amd.c     | 17 +++++++++++------
 xen/arch/x86/cpu/microcode/core.c    | 18 +++++++++---------
 xen/arch/x86/cpu/microcode/intel.c   | 17 +++++++++++------
 xen/arch/x86/cpu/microcode/private.h | 18 ++++++++++++------
 4 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c
index 8195707ee1..d4df3c4806 100644
--- a/xen/arch/x86/cpu/microcode/amd.c
+++ b/xen/arch/x86/cpu/microcode/amd.c
@@ -299,11 +299,11 @@ static int scan_equiv_cpu_table(const struct container_equiv_table *et)
     return -ESRCH;
 }
 
-static struct microcode_patch *cf_check cpu_request_microcode(
-    const void *buf, size_t size)
+static const struct microcode_patch *cf_check cpu_request_microcode(
+    const void *buf, size_t size, bool make_copy)
 {
     const struct microcode_patch *saved = NULL;
-    struct microcode_patch *patch = NULL;
+    const struct microcode_patch *patch = NULL;
     size_t saved_size = 0;
     int error = 0;
 
@@ -411,9 +411,14 @@ static struct microcode_patch *cf_check cpu_request_microcode(
 
     if ( saved )
     {
-        patch = xmemdup_bytes(saved, saved_size);
-        if ( !patch )
-            error = -ENOMEM;
+        if ( make_copy )
+        {
+            patch = xmemdup_bytes(saved, saved_size);
+            if ( !patch )
+                error = -ENOMEM;
+        }
+        else
+            patch = saved;
     }
 
     if ( error && !patch )
diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
index 452a7ca773..924a2bd7b5 100644
--- a/xen/arch/x86/cpu/microcode/core.c
+++ b/xen/arch/x86/cpu/microcode/core.c
@@ -99,7 +99,7 @@ static bool ucode_in_nmi = true;
 bool __read_mostly opt_ucode_allow_same;
 
 /* Protected by microcode_mutex */
-static struct microcode_patch *microcode_cache;
+static const struct microcode_patch *microcode_cache;
 
 void __init microcode_set_module(unsigned int idx)
 {
@@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
  * patch is found and an error occurs during the parsing process. Otherwise
  * return NULL.
  */
-static struct microcode_patch *parse_blob(const char *buf, size_t len)
+static const struct microcode_patch *parse_blob(const char *buf, size_t len)
 {
     alternative_vcall(ucode_ops.collect_cpu_info);
 
-    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
+    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
 }
 
-static void microcode_free_patch(struct microcode_patch *patch)
+static void microcode_free_patch(const struct microcode_patch *patch)
 {
-    xfree(patch);
+    xfree((void *)patch);
 }
 
 /* Return true if cache gets updated. Otherwise, return false */
-static bool microcode_update_cache(struct microcode_patch *patch)
+static bool microcode_update_cache(const struct microcode_patch *patch)
 {
     ASSERT(spin_is_locked(&microcode_mutex));
 
@@ -565,7 +565,7 @@ static long cf_check microcode_update_helper(void *data)
     int ret;
     struct ucode_buf *buffer = data;
     unsigned int cpu, updated;
-    struct microcode_patch *patch;
+    const struct microcode_patch *patch;
 
     /* cpu_online_map must not change during update */
     if ( !get_cpu_maps() )
@@ -648,7 +648,7 @@ static long cf_check microcode_update_helper(void *data)
      *   this requirement can be relaxed in the future. Right now, this is
      *   conservative and good.
      */
-    ret = stop_machine_run(do_microcode_update, patch, NR_CPUS);
+    ret = stop_machine_run(do_microcode_update, (void *)patch, NR_CPUS);
 
     updated = atomic_read(&cpu_updated);
     if ( updated > 0 )
@@ -738,7 +738,7 @@ static int __init early_microcode_update_cpu(void)
     int rc = 0;
     const void *data = NULL;
     size_t len;
-    struct microcode_patch *patch;
+    const struct microcode_patch *patch;
 
     if ( ucode_blob.size )
     {
diff --git a/xen/arch/x86/cpu/microcode/intel.c b/xen/arch/x86/cpu/microcode/intel.c
index f5ba6d76d7..017f37e43d 100644
--- a/xen/arch/x86/cpu/microcode/intel.c
+++ b/xen/arch/x86/cpu/microcode/intel.c
@@ -323,12 +323,12 @@ static int cf_check apply_microcode(const struct microcode_patch *patch)
     return 0;
 }
 
-static struct microcode_patch *cf_check cpu_request_microcode(
-    const void *buf, size_t size)
+static const struct microcode_patch *cf_check cpu_request_microcode(
+    const void *buf, size_t size, bool make_copy)
 {
     int error = 0;
     const struct microcode_patch *saved = NULL;
-    struct microcode_patch *patch = NULL;
+    const struct microcode_patch *patch = NULL;
 
     while ( size )
     {
@@ -364,10 +364,15 @@ static struct microcode_patch *cf_check cpu_request_microcode(
 
     if ( saved )
     {
-        patch = xmemdup_bytes(saved, get_totalsize(saved));
+        if ( make_copy )
+        {
+            patch = xmemdup_bytes(saved, get_totalsize(saved));
 
-        if ( !patch )
-            error = -ENOMEM;
+            if ( !patch )
+                error = -ENOMEM;
+        }
+        else
+            patch = saved;
     }
 
     if ( error && !patch )
diff --git a/xen/arch/x86/cpu/microcode/private.h b/xen/arch/x86/cpu/microcode/private.h
index c085a10268..98657d39c3 100644
--- a/xen/arch/x86/cpu/microcode/private.h
+++ b/xen/arch/x86/cpu/microcode/private.h
@@ -23,16 +23,22 @@ struct microcode_ops {
      * older that what is running in the CPU.  This is a feature, to better
      * cope with corner cases from buggy firmware.)
      *
-     * If one is found, allocate and return a struct microcode_patch
-     * encapsulating the appropriate microcode patch.  Does not alias the
-     * original buffer.  Must be suitable to be freed with a single xfree().
+     * If one is found, behaviour depends on the make_copy argument:
+     *
+     *     true: allocate and return a struct microcode_patch encapsulating
+     *           the appropriate microcode patch.  Does not alias the original
+     *           buffer.  Must be suitable to be freed with a single xfree().
+     *
+     *    false: return a pointer to the patch within the original buffer.
+     *           This is useful for early microcode loading when xmalloc might
+     *           not be available yet.
      *
      * If one is not found, (nothing matches the current CPU), return NULL.
      * Also may return ERR_PTR(-err), e.g. bad container, out of memory.
      */
-    struct microcode_patch *(*cpu_request_microcode)(const void *buf,
-                                                     size_t size);
-
+    const struct microcode_patch *(*cpu_request_microcode)(const void *buf,
+                                                           size_t size,
+                                                           bool make_copy);
     /*
      * Obtain microcode-relevant details for the current CPU.  Results in
      * per_cpu(cpu_sig).
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU
  2022-12-08 13:26 [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Sergey Dyasli
@ 2022-12-08 13:26 ` Sergey Dyasli
  2022-12-12 16:29   ` Jan Beulich
  2022-12-08 13:59 ` [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Andrew Cooper
  2022-12-12 15:26 ` Jan Beulich
  2 siblings, 1 reply; 10+ messages in thread
From: Sergey Dyasli @ 2022-12-08 13:26 UTC (permalink / raw)
  To: xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné, Wei Liu, Sergey Dyasli

Call early_microcode_init() straight after multiboot modules become
accessible. Modify it to load the ucode directly from the blob bypassing
populating microcode_cache because xmalloc is still not available at
that point during Xen boot.

Introduce early_microcode_init_cache() for populating microcode_cache.
It needs to find the new virtual address of the ucode blob because it
changes during boot, e.g. from 0x00000000010802fc to 0xffff83204dac52fc.

Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 xen/arch/x86/cpu/microcode/core.c    | 61 ++++++++++++++++++++++++----
 xen/arch/x86/include/asm/microcode.h |  6 ++-
 xen/arch/x86/include/asm/setup.h     |  3 --
 xen/arch/x86/setup.c                 | 10 +++--
 4 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
index 924a2bd7b5..b04b30ce5e 100644
--- a/xen/arch/x86/cpu/microcode/core.c
+++ b/xen/arch/x86/cpu/microcode/core.c
@@ -198,7 +198,7 @@ void __init microcode_scan_module(
         bootstrap_map(NULL);
     }
 }
-void __init microcode_grab_module(
+static void __init microcode_grab_module(
     unsigned long *module_map,
     const multiboot_info_t *mbi)
 {
@@ -733,9 +733,35 @@ int microcode_update_one(void)
 }
 
 /* BSP calls this function to parse ucode blob and then apply an update. */
-static int __init early_microcode_update_cpu(void)
+static int __init early_microcode_update_cache(const void *data, size_t len)
 {
     int rc = 0;
+    const struct microcode_patch *patch;
+
+    if ( !data )
+        return -ENOMEM;
+
+    patch = parse_blob(data, len);
+    if ( IS_ERR(patch) )
+    {
+        printk(XENLOG_WARNING "Parsing microcode blob error %ld\n",
+               PTR_ERR(patch));
+        return PTR_ERR(patch);
+    }
+
+    if ( !patch )
+        return -ENOENT;
+
+    spin_lock(&microcode_mutex);
+    rc = microcode_update_cache(patch);
+    spin_unlock(&microcode_mutex);
+    ASSERT(rc);
+
+    return rc;
+}
+
+static int __init early_microcode_update_cpu(void)
+{
     const void *data = NULL;
     size_t len;
     const struct microcode_patch *patch;
@@ -754,7 +780,9 @@ static int __init early_microcode_update_cpu(void)
     if ( !data )
         return -ENOMEM;
 
-    patch = parse_blob(data, len);
+    alternative_vcall(ucode_ops.collect_cpu_info);
+
+    patch = alternative_call(ucode_ops.cpu_request_microcode, data, len, false);
     if ( IS_ERR(patch) )
     {
         printk(XENLOG_WARNING "Parsing microcode blob error %ld\n",
@@ -765,15 +793,28 @@ static int __init early_microcode_update_cpu(void)
     if ( !patch )
         return -ENOENT;
 
-    spin_lock(&microcode_mutex);
-    rc = microcode_update_cache(patch);
-    spin_unlock(&microcode_mutex);
-    ASSERT(rc);
+    return microcode_update_cpu(patch);
+}
+
+int __init early_microcode_init_cache(unsigned long *module_map,
+                                      const multiboot_info_t *mbi)
+{
+    int rc = 0;
+
+    /* Need to rescan the modules because they might have been relocated */
+    microcode_grab_module(module_map, mbi);
+
+    if ( ucode_mod.mod_end )
+        rc = early_microcode_update_cache(bootstrap_map(&ucode_mod),
+                                          ucode_mod.mod_end);
+    else if ( ucode_blob.size )
+        rc = early_microcode_update_cache(ucode_blob.data, ucode_blob.size);
 
-    return microcode_update_one();
+    return rc;
 }
 
-int __init early_microcode_init(void)
+int __init early_microcode_init(unsigned long *module_map,
+                                const multiboot_info_t *mbi)
 {
     const struct cpuinfo_x86 *c = &boot_cpu_data;
     int rc = 0;
@@ -797,6 +838,8 @@ int __init early_microcode_init(void)
         return -ENODEV;
     }
 
+    microcode_grab_module(module_map, mbi);
+
     alternative_vcall(ucode_ops.collect_cpu_info);
 
     if ( ucode_mod.mod_end || ucode_blob.size )
diff --git a/xen/arch/x86/include/asm/microcode.h b/xen/arch/x86/include/asm/microcode.h
index 3b0234e9fa..c5f9897535 100644
--- a/xen/arch/x86/include/asm/microcode.h
+++ b/xen/arch/x86/include/asm/microcode.h
@@ -3,6 +3,7 @@
 
 #include <xen/types.h>
 #include <xen/percpu.h>
+#include <xen/multiboot.h>
 
 #include <public/xen.h>
 
@@ -21,7 +22,10 @@ DECLARE_PER_CPU(struct cpu_signature, cpu_sig);
 
 void microcode_set_module(unsigned int idx);
 int microcode_update(XEN_GUEST_HANDLE(const_void), unsigned long len);
-int early_microcode_init(void);
+int early_microcode_init(unsigned long *module_map,
+                         const multiboot_info_t *mbi);
+int early_microcode_init_cache(unsigned long *module_map,
+                               const multiboot_info_t *mbi);
 int microcode_update_one(void);
 
 #endif /* ASM_X86__MICROCODE_H */
diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h
index 21037b7f31..82ee51c2dc 100644
--- a/xen/arch/x86/include/asm/setup.h
+++ b/xen/arch/x86/include/asm/setup.h
@@ -45,9 +45,6 @@ void *bootstrap_map(const module_t *mod);
 
 int xen_in_range(unsigned long mfn);
 
-void microcode_grab_module(
-    unsigned long *, const multiboot_info_t *);
-
 extern uint8_t kbd_shift_flags;
 
 #ifdef NDEBUG
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index e05189f649..9955e1e6fa 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1178,6 +1178,12 @@ void __init noreturn __start_xen(unsigned long mbi_p)
         mod[i].reserved = 0;
     }
 
+    /*
+     * TODO: load ucode earlier once multiboot modules become accessible
+     * at an earlier stage.
+     */
+    early_microcode_init(module_map, mbi);
+
     if ( xen_phys_start )
     {
         relocated = true;
@@ -1774,11 +1780,9 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 
     init_IRQ();
 
-    microcode_grab_module(module_map, mbi);
-
     timer_init();
 
-    early_microcode_init();
+    early_microcode_init_cache(module_map, mbi);
 
     tsx_init(); /* Needs microcode.  May change HLE/RTM feature bits. */
 
-- 
2.17.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-08 13:26 [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Sergey Dyasli
  2022-12-08 13:26 ` [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU Sergey Dyasli
@ 2022-12-08 13:59 ` Andrew Cooper
  2022-12-08 15:34   ` Jan Beulich
  2022-12-12 15:26 ` Jan Beulich
  2 siblings, 1 reply; 10+ messages in thread
From: Andrew Cooper @ 2022-12-08 13:59 UTC (permalink / raw)
  To: Sergey Dyasli, xen-devel; +Cc: Jan Beulich, Roger Pau Monne, Wei Liu

On 08/12/2022 13:26, Sergey Dyasli wrote:
> diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
> index 452a7ca773..924a2bd7b5 100644
> --- a/xen/arch/x86/cpu/microcode/core.c
> +++ b/xen/arch/x86/cpu/microcode/core.c
> @@ -99,7 +99,7 @@ static bool ucode_in_nmi = true;
>  bool __read_mostly opt_ucode_allow_same;
>  
>  /* Protected by microcode_mutex */
> -static struct microcode_patch *microcode_cache;
> +static const struct microcode_patch *microcode_cache;
>  
>  void __init microcode_set_module(unsigned int idx)
>  {
> @@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
>   * patch is found and an error occurs during the parsing process. Otherwise
>   * return NULL.
>   */
> -static struct microcode_patch *parse_blob(const char *buf, size_t len)
> +static const struct microcode_patch *parse_blob(const char *buf, size_t len)
>  {
>      alternative_vcall(ucode_ops.collect_cpu_info);
>  
> -    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
> +    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
>  }
>  
> -static void microcode_free_patch(struct microcode_patch *patch)
> +static void microcode_free_patch(const struct microcode_patch *patch)
>  {
> -    xfree(patch);
> +    xfree((void *)patch);

This hunk demonstrates why the hook wants to return a non-const
pointer.  Keeping it non-const will shrink this patch quite a bit.

Given that make_copy=false is a special case for the BSP, it can cope
with knowing that it shouldn't mutate the pointer it gets given back.


I do have a plan for the future to reduce the complexity here, but it
depends on getting a few more details out of AMD first.  (All of this
mess is because their ucode doesn't have an embedded length field.)

In the short term, handing the BSP a non-const pointer to a const buffer
for early loading is going to be a lesser evil than in the common case
giving the caller a const pointer that they're expected to call xfree() on.

If this is the only issue, then I'm happy to adjust on commit.

~Andrew

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-08 13:59 ` [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Andrew Cooper
@ 2022-12-08 15:34   ` Jan Beulich
  2022-12-12 14:27     ` Sergey Dyasli
  0 siblings, 1 reply; 10+ messages in thread
From: Jan Beulich @ 2022-12-08 15:34 UTC (permalink / raw)
  To: Andrew Cooper, Sergey Dyasli; +Cc: Roger Pau Monne, Wei Liu, xen-devel

On 08.12.2022 14:59, Andrew Cooper wrote:
> On 08/12/2022 13:26, Sergey Dyasli wrote:
>> @@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
>>   * patch is found and an error occurs during the parsing process. Otherwise
>>   * return NULL.
>>   */
>> -static struct microcode_patch *parse_blob(const char *buf, size_t len)
>> +static const struct microcode_patch *parse_blob(const char *buf, size_t len)
>>  {
>>      alternative_vcall(ucode_ops.collect_cpu_info);
>>  
>> -    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
>> +    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
>>  }
>>  
>> -static void microcode_free_patch(struct microcode_patch *patch)
>> +static void microcode_free_patch(const struct microcode_patch *patch)
>>  {
>> -    xfree(patch);
>> +    xfree((void *)patch);
> 
> This hunk demonstrates why the hook wants to return a non-const
> pointer.  Keeping it non-const will shrink this patch quite a bit.

Alternatively it demonstrates why xfree() should take const void *,
just like e.g. unmap_domain_page() or vunmap() already do. We've
talked about this before, and the argument hasn't changed: Neither
unmapping nor freeing really alters the contents of the pointed to
area from the perspective of the caller, as the contents simply
disappears altogether.

Jan


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-08 15:34   ` Jan Beulich
@ 2022-12-12 14:27     ` Sergey Dyasli
  2022-12-12 14:59       ` Jan Beulich
  0 siblings, 1 reply; 10+ messages in thread
From: Sergey Dyasli @ 2022-12-12 14:27 UTC (permalink / raw)
  To: Jan Beulich, Andrew Cooper; +Cc: Roger Pau Monne, Wei Liu, xen-devel

On Thu, Dec 8, 2022 at 3:34 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 08.12.2022 14:59, Andrew Cooper wrote:
> > On 08/12/2022 13:26, Sergey Dyasli wrote:
> >> @@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
> >>   * patch is found and an error occurs during the parsing process. Otherwise
> >>   * return NULL.
> >>   */
> >> -static struct microcode_patch *parse_blob(const char *buf, size_t len)
> >> +static const struct microcode_patch *parse_blob(const char *buf, size_t len)
> >>  {
> >>      alternative_vcall(ucode_ops.collect_cpu_info);
> >>
> >> -    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
> >> +    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
> >>  }
> >>
> >> -static void microcode_free_patch(struct microcode_patch *patch)
> >> +static void microcode_free_patch(const struct microcode_patch *patch)
> >>  {
> >> -    xfree(patch);
> >> +    xfree((void *)patch);
> >
> > This hunk demonstrates why the hook wants to return a non-const
> > pointer.  Keeping it non-const will shrink this patch quite a bit.
>
> Alternatively it demonstrates why xfree() should take const void *,
> just like e.g. unmap_domain_page() or vunmap() already do. We've
> talked about this before, and the argument hasn't changed: Neither
> unmapping nor freeing really alters the contents of the pointed to
> area from the perspective of the caller, as the contents simply
> disappears altogether.

Despite my love of const, const correctness in C is quite a pain. I've
tried to make xfree() take a const pointer but then issues began with
add/strip_padding() functions and I couldn't overcome those without
further (void *) casts which just takes the problem to a different
layer.

I think I'll have to go with Andrew's suggestion and continue to return
non-const pointers from cpu_request_microcode(). This will include
a cast though:

    patch = (struct microcode_patch *)saved;

Sergey


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-12 14:27     ` Sergey Dyasli
@ 2022-12-12 14:59       ` Jan Beulich
  2022-12-12 15:18         ` Andrew Cooper
  0 siblings, 1 reply; 10+ messages in thread
From: Jan Beulich @ 2022-12-12 14:59 UTC (permalink / raw)
  To: Sergey Dyasli; +Cc: Roger Pau Monne, Wei Liu, xen-devel, Andrew Cooper

On 12.12.2022 15:27, Sergey Dyasli wrote:
> On Thu, Dec 8, 2022 at 3:34 PM Jan Beulich <jbeulich@suse.com> wrote:
>> On 08.12.2022 14:59, Andrew Cooper wrote:
>>> On 08/12/2022 13:26, Sergey Dyasli wrote:
>>>> @@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
>>>>   * patch is found and an error occurs during the parsing process. Otherwise
>>>>   * return NULL.
>>>>   */
>>>> -static struct microcode_patch *parse_blob(const char *buf, size_t len)
>>>> +static const struct microcode_patch *parse_blob(const char *buf, size_t len)
>>>>  {
>>>>      alternative_vcall(ucode_ops.collect_cpu_info);
>>>>
>>>> -    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
>>>> +    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
>>>>  }
>>>>
>>>> -static void microcode_free_patch(struct microcode_patch *patch)
>>>> +static void microcode_free_patch(const struct microcode_patch *patch)
>>>>  {
>>>> -    xfree(patch);
>>>> +    xfree((void *)patch);
>>>
>>> This hunk demonstrates why the hook wants to return a non-const
>>> pointer.  Keeping it non-const will shrink this patch quite a bit.
>>
>> Alternatively it demonstrates why xfree() should take const void *,
>> just like e.g. unmap_domain_page() or vunmap() already do. We've
>> talked about this before, and the argument hasn't changed: Neither
>> unmapping nor freeing really alters the contents of the pointed to
>> area from the perspective of the caller, as the contents simply
>> disappears altogether.
> 
> Despite my love of const, const correctness in C is quite a pain. I've
> tried to make xfree() take a const pointer but then issues began with
> add/strip_padding() functions and I couldn't overcome those without
> further (void *) casts which just takes the problem to a different
> layer.

There is exactly one such cast needed according to my attempt, and that's
in an internal (static) helper function. See below (and feel free to use).

Jan

mm: make a couple of freeing functions take const void*

freeing functions, from the perspective of their callers, don't alter
contents of the freed block; the block simply disappears. Plus it is not
uncommon that some piece of memory is allocated, filled, and henceforth
supposed to only be read from. In such cases, with the parameters of the
freeing functions not being pointer-to-const, callers have to either
omit the use of const where it would be indicated or add risky casts.

The goal being to make xfree() fit the intended pattern, alter other
functions at the same time to limit the number of casts needed to just
one. strip_padding() necessarily has to have a such a cast, as it's
effectively strchr()- or memchr()-like: Input may be pointer-to-const,
bot for its output to also be usable when the input isn't, const needs
to be cast away. Note that the risk with such a cast is quite a bit
lower when it's an internal (static) function wich is affected.

Signed-off-by: Jan Beulich <jbeulich@suse.com>

--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2231,7 +2231,7 @@ void *alloc_xenheap_pages(unsigned int o
 }
 
 
-void free_xenheap_pages(void *v, unsigned int order)
+void free_xenheap_pages(const void *v, unsigned int order)
 {
     ASSERT_ALLOC_CONTEXT();
 
@@ -2279,7 +2279,7 @@ void *alloc_xenheap_pages(unsigned int o
     return page_to_virt(pg);
 }
 
-void free_xenheap_pages(void *v, unsigned int order)
+void free_xenheap_pages(const void *v, unsigned int order)
 {
     struct page_info *pg;
     unsigned int i;
--- a/xen/common/xmalloc_tlsf.c
+++ b/xen/common/xmalloc_tlsf.c
@@ -453,7 +453,7 @@ void *xmem_pool_alloc(unsigned long size
     return NULL;
 }
 
-void xmem_pool_free(void *ptr, struct xmem_pool *pool)
+void xmem_pool_free(const void *ptr, struct xmem_pool *pool)
 {
     struct bhdr *b, *tmp_b;
     int fl = 0, sl = 0;
@@ -563,7 +563,7 @@ static void tlsf_init(void)
  * xmalloc()
  */
 
-static void *strip_padding(void *p)
+static void *strip_padding(const void *p)
 {
     const struct bhdr *b = p - BHDR_OVERHEAD;
 
@@ -574,7 +574,7 @@ static void *strip_padding(void *p)
         ASSERT(!(b->size & FREE_BLOCK));
     }
 
-    return p;
+    return (void *)p;
 }
 
 static void *add_padding(void *p, unsigned long align)
@@ -699,7 +699,7 @@ void *_xrealloc(void *ptr, unsigned long
     return p;
 }
 
-void xfree(void *p)
+void xfree(const void *p)
 {
     ASSERT_ALLOC_CONTEXT();
 
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -73,7 +73,7 @@ void end_boot_allocator(void);
 void init_xenheap_pages(paddr_t ps, paddr_t pe);
 void xenheap_max_mfn(unsigned long mfn);
 void *alloc_xenheap_pages(unsigned int order, unsigned int memflags);
-void free_xenheap_pages(void *v, unsigned int order);
+void free_xenheap_pages(const void *v, unsigned int order);
 bool scrub_free_pages(void);
 #define alloc_xenheap_page() (alloc_xenheap_pages(0,0))
 #define free_xenheap_page(v) (free_xenheap_pages(v,0))
--- a/xen/include/xen/xmalloc.h
+++ b/xen/include/xen/xmalloc.h
@@ -63,7 +63,7 @@
     })
 
 /* Free any of the above. */
-extern void xfree(void *);
+extern void xfree(const void *);
 
 /* Free an allocation, and zero the pointer to it. */
 #define XFREE(p) do { \
@@ -148,7 +148,7 @@ int xmem_pool_maxalloc(struct xmem_pool
  * @ptr: address of memory to be freed
  * @mem_pool: pool to free from
  */
-void xmem_pool_free(void *ptr, struct xmem_pool *pool);
+void xmem_pool_free(const void *ptr, struct xmem_pool *pool);
 
 /**
  * xmem_pool_get_used_size - get memory currently used by given pool



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-12 14:59       ` Jan Beulich
@ 2022-12-12 15:18         ` Andrew Cooper
  2022-12-12 16:04           ` Jan Beulich
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Cooper @ 2022-12-12 15:18 UTC (permalink / raw)
  To: Jan Beulich, Sergey Dyasli; +Cc: Roger Pau Monne, Wei Liu, xen-devel

On 12/12/2022 14:59, Jan Beulich wrote:
> On 12.12.2022 15:27, Sergey Dyasli wrote:
>> On Thu, Dec 8, 2022 at 3:34 PM Jan Beulich <jbeulich@suse.com> wrote:
>>> On 08.12.2022 14:59, Andrew Cooper wrote:
>>>> On 08/12/2022 13:26, Sergey Dyasli wrote:
>>>>> @@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
>>>>>   * patch is found and an error occurs during the parsing process. Otherwise
>>>>>   * return NULL.
>>>>>   */
>>>>> -static struct microcode_patch *parse_blob(const char *buf, size_t len)
>>>>> +static const struct microcode_patch *parse_blob(const char *buf, size_t len)
>>>>>  {
>>>>>      alternative_vcall(ucode_ops.collect_cpu_info);
>>>>>
>>>>> -    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
>>>>> +    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
>>>>>  }
>>>>>
>>>>> -static void microcode_free_patch(struct microcode_patch *patch)
>>>>> +static void microcode_free_patch(const struct microcode_patch *patch)
>>>>>  {
>>>>> -    xfree(patch);
>>>>> +    xfree((void *)patch);
>>>> This hunk demonstrates why the hook wants to return a non-const
>>>> pointer.  Keeping it non-const will shrink this patch quite a bit.
>>> Alternatively it demonstrates why xfree() should take const void *,
>>> just like e.g. unmap_domain_page() or vunmap() already do. We've
>>> talked about this before, and the argument hasn't changed: Neither
>>> unmapping nor freeing really alters the contents of the pointed to
>>> area from the perspective of the caller, as the contents simply
>>> disappears altogether.
>> Despite my love of const, const correctness in C is quite a pain. I've
>> tried to make xfree() take a const pointer but then issues began with
>> add/strip_padding() functions and I couldn't overcome those without
>> further (void *) casts which just takes the problem to a different
>> layer.
> There is exactly one such cast needed according to my attempt, and that's
> in an internal (static) helper function. See below (and feel free to use).
>
> Jan
>
> mm: make a couple of freeing functions take const void*
>
> freeing functions, from the perspective of their callers, don't alter
> contents of the freed block; the block simply disappears. Plus it is not
> uncommon that some piece of memory is allocated, filled, and henceforth
> supposed to only be read from. In such cases, with the parameters of the
> freeing functions not being pointer-to-const, callers have to either
> omit the use of const where it would be indicated or add risky casts.
>
> The goal being to make xfree() fit the intended pattern, alter other
> functions at the same time to limit the number of casts needed to just
> one. strip_padding() necessarily has to have a such a cast, as it's
> effectively strchr()- or memchr()-like: Input may be pointer-to-const,
> bot for its output to also be usable when the input isn't, const needs
> to be cast away. Note that the risk with such a cast is quite a bit
> lower when it's an internal (static) function wich is affected.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

If you can persuade the C standards committee that your interpretation
of how to use const is more correct than theirs, and get them to change
free() to take const void, then we can continue discussing this patch.

Until then, there's a damn good reason why free() takes a non-const
pointer (nothing handed out by a memory allocator can ever be const, and
it is never acceptable to free via a const alias), and contorted
arguments about how its "technically fine" are missing the point.

~Andrew

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-08 13:26 [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Sergey Dyasli
  2022-12-08 13:26 ` [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU Sergey Dyasli
  2022-12-08 13:59 ` [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Andrew Cooper
@ 2022-12-12 15:26 ` Jan Beulich
  2 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2022-12-12 15:26 UTC (permalink / raw)
  To: Sergey Dyasli; +Cc: Andrew Cooper, Roger Pau Monné, Wei Liu, xen-devel

On 08.12.2022 14:26, Sergey Dyasli wrote:
> @@ -648,7 +648,7 @@ static long cf_check microcode_update_helper(void *data)
>       *   this requirement can be relaxed in the future. Right now, this is
>       *   conservative and good.
>       */
> -    ret = stop_machine_run(do_microcode_update, patch, NR_CPUS);
> +    ret = stop_machine_run(do_microcode_update, (void *)patch, NR_CPUS);

Just as a remark - callback function arguments like this one also would
be nice to be allowed to be pointer-to-const, but I guess we'd need to
introduce some trickery to allow such despite the lack of function
templates (and even if we had such, also to limit duplication of binary
code).

Jan


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation
  2022-12-12 15:18         ` Andrew Cooper
@ 2022-12-12 16:04           ` Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2022-12-12 16:04 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Roger Pau Monne, Wei Liu, xen-devel, Sergey Dyasli

On 12.12.2022 16:18, Andrew Cooper wrote:
> On 12/12/2022 14:59, Jan Beulich wrote:
>> On 12.12.2022 15:27, Sergey Dyasli wrote:
>>> On Thu, Dec 8, 2022 at 3:34 PM Jan Beulich <jbeulich@suse.com> wrote:
>>>> On 08.12.2022 14:59, Andrew Cooper wrote:
>>>>> On 08/12/2022 13:26, Sergey Dyasli wrote:
>>>>>> @@ -240,20 +240,20 @@ static const struct microcode_patch *nmi_patch = ZERO_BLOCK_PTR;
>>>>>>   * patch is found and an error occurs during the parsing process. Otherwise
>>>>>>   * return NULL.
>>>>>>   */
>>>>>> -static struct microcode_patch *parse_blob(const char *buf, size_t len)
>>>>>> +static const struct microcode_patch *parse_blob(const char *buf, size_t len)
>>>>>>  {
>>>>>>      alternative_vcall(ucode_ops.collect_cpu_info);
>>>>>>
>>>>>> -    return alternative_call(ucode_ops.cpu_request_microcode, buf, len);
>>>>>> +    return alternative_call(ucode_ops.cpu_request_microcode, buf, len, true);
>>>>>>  }
>>>>>>
>>>>>> -static void microcode_free_patch(struct microcode_patch *patch)
>>>>>> +static void microcode_free_patch(const struct microcode_patch *patch)
>>>>>>  {
>>>>>> -    xfree(patch);
>>>>>> +    xfree((void *)patch);
>>>>> This hunk demonstrates why the hook wants to return a non-const
>>>>> pointer.  Keeping it non-const will shrink this patch quite a bit.
>>>> Alternatively it demonstrates why xfree() should take const void *,
>>>> just like e.g. unmap_domain_page() or vunmap() already do. We've
>>>> talked about this before, and the argument hasn't changed: Neither
>>>> unmapping nor freeing really alters the contents of the pointed to
>>>> area from the perspective of the caller, as the contents simply
>>>> disappears altogether.
>>> Despite my love of const, const correctness in C is quite a pain. I've
>>> tried to make xfree() take a const pointer but then issues began with
>>> add/strip_padding() functions and I couldn't overcome those without
>>> further (void *) casts which just takes the problem to a different
>>> layer.
>> There is exactly one such cast needed according to my attempt, and that's
>> in an internal (static) helper function. See below (and feel free to use).
>>
>> Jan
>>
>> mm: make a couple of freeing functions take const void*
>>
>> freeing functions, from the perspective of their callers, don't alter
>> contents of the freed block; the block simply disappears. Plus it is not
>> uncommon that some piece of memory is allocated, filled, and henceforth
>> supposed to only be read from. In such cases, with the parameters of the
>> freeing functions not being pointer-to-const, callers have to either
>> omit the use of const where it would be indicated or add risky casts.
>>
>> The goal being to make xfree() fit the intended pattern, alter other
>> functions at the same time to limit the number of casts needed to just
>> one. strip_padding() necessarily has to have a such a cast, as it's
>> effectively strchr()- or memchr()-like: Input may be pointer-to-const,
>> bot for its output to also be usable when the input isn't, const needs
>> to be cast away. Note that the risk with such a cast is quite a bit
>> lower when it's an internal (static) function wich is affected.
>>
>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> If you can persuade the C standards committee that your interpretation
> of how to use const is more correct than theirs, and get them to change
> free() to take const void, then we can continue discussing this patch.
> 
> Until then, there's a damn good reason why free() takes a non-const
> pointer (nothing handed out by a memory allocator can ever be const, and
> it is never acceptable to free via a const alias), and contorted
> arguments about how its "technically fine" are missing the point.

"damn good" and "never acceptable" are strong statements, which will want
accompanying by actual technical content. It's not like I've invented
this "interpretation". But when I saw it elsewhere (I don't recall which
project(s) this was) I found it very reasonable, and hence I picked it up
to at least consider for stuff I'm working on.

Jan


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU
  2022-12-08 13:26 ` [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU Sergey Dyasli
@ 2022-12-12 16:29   ` Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2022-12-12 16:29 UTC (permalink / raw)
  To: Sergey Dyasli; +Cc: Andrew Cooper, Roger Pau Monné, Wei Liu, xen-devel

On 08.12.2022 14:26, Sergey Dyasli wrote:
> --- a/xen/arch/x86/cpu/microcode/core.c
> +++ b/xen/arch/x86/cpu/microcode/core.c
> @@ -198,7 +198,7 @@ void __init microcode_scan_module(
>          bootstrap_map(NULL);
>      }
>  }
> -void __init microcode_grab_module(
> +static void __init microcode_grab_module(

May I ask that you take the opportunity and add the missing blank line
between the two functions?

> @@ -733,9 +733,35 @@ int microcode_update_one(void)
>  }
>  
>  /* BSP calls this function to parse ucode blob and then apply an update. */
> -static int __init early_microcode_update_cpu(void)

I think the comment wants to stay with its function. In fact I think you
simply want to move down ...

> +static int __init early_microcode_update_cache(const void *data, size_t len)
>  {

... this function, which strictly is a helper of early_microcode_init_cache()
(and, being a static helper, could imo do with having a shorter name).

> @@ -754,7 +780,9 @@ static int __init early_microcode_update_cpu(void)
>      if ( !data )
>          return -ENOMEM;
>  
> -    patch = parse_blob(data, len);
> +    alternative_vcall(ucode_ops.collect_cpu_info);
> +
> +    patch = alternative_call(ucode_ops.cpu_request_microcode, data, len, false);

I realize early_microcode_init() also uses alternative_vcall(), but I
doubt that of the two altcalls here are useful to have - they merely
bloat the binary afaict. Looking at Andrew's 8f473f92e531 ("x86/ucode:
Use altcall, and __initconst_cf_clobber") I also don't see any clear
justification - the __initconst_cf_clobber alone is sufficient for the
stated purpose, I think (as far as __init functions are concerned, of
course).

> @@ -765,15 +793,28 @@ static int __init early_microcode_update_cpu(void)
>      if ( !patch )
>          return -ENOENT;
>  
> -    spin_lock(&microcode_mutex);
> -    rc = microcode_update_cache(patch);
> -    spin_unlock(&microcode_mutex);
> -    ASSERT(rc);
> +    return microcode_update_cpu(patch);
> +}
> +
> +int __init early_microcode_init_cache(unsigned long *module_map,
> +                                      const multiboot_info_t *mbi)
> +{
> +    int rc = 0;
> +
> +    /* Need to rescan the modules because they might have been relocated */
> +    microcode_grab_module(module_map, mbi);

I'm afraid the function isn't safe to call twice; the only safe case looks
to be when "ucode=scan" is in use.

> --- a/xen/arch/x86/include/asm/microcode.h
> +++ b/xen/arch/x86/include/asm/microcode.h
> @@ -3,6 +3,7 @@
>  
>  #include <xen/types.h>
>  #include <xen/percpu.h>
> +#include <xen/multiboot.h>

I think dependencies like this are moving us in the wrong direction, wrt
our header dependencies nightmare. Could I talk you into adding a prereq
patch giving a proper tag to the struct which is typedef-ed to
multiboot_info_t, such that a forward declaration of that struct would
suffice ...

> @@ -21,7 +22,10 @@ DECLARE_PER_CPU(struct cpu_signature, cpu_sig);
>  
>  void microcode_set_module(unsigned int idx);
>  int microcode_update(XEN_GUEST_HANDLE(const_void), unsigned long len);
> -int early_microcode_init(void);
> +int early_microcode_init(unsigned long *module_map,
> +                         const multiboot_info_t *mbi);
> +int early_microcode_init_cache(unsigned long *module_map,
> +                               const multiboot_info_t *mbi);

... ahead of the two uses here?

Jan


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-12-12 16:29 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-08 13:26 [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Sergey Dyasli
2022-12-08 13:26 ` [PATCH 2/2] x86/ucode: load microcode earlier on boot CPU Sergey Dyasli
2022-12-12 16:29   ` Jan Beulich
2022-12-08 13:59 ` [PATCH 1/2] x86/ucode: allow cpu_request_microcode() to skip memory allocation Andrew Cooper
2022-12-08 15:34   ` Jan Beulich
2022-12-12 14:27     ` Sergey Dyasli
2022-12-12 14:59       ` Jan Beulich
2022-12-12 15:18         ` Andrew Cooper
2022-12-12 16:04           ` Jan Beulich
2022-12-12 15:26 ` Jan Beulich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.