[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v2 4/4] x86/microcode: Support builtin CPU microcode



On 18.12.2019 02:32, Eslam Elnikety wrote:
> Xen relies on boot modules to perform early microcode updates. This commit 
> adds
> another mode, namely "builtin" via the BUILTIN_UCODE config parameter. If set,
> the Xen image itself will contain the microcode updates. Upon boot, Xen
> inspects its image for microcode blobs and performs the update.
> 
> A Xen image with builtin microcode will, by default, attempt the microcode
> update. Disabling the builtin microcode update can be done via the Xen command
> line parameter 'ucode=no-builtin'. Moreover, the microcode provided via other
> options (such as 'ucode=<integer>|scan' or 'ucode=<filename>' config when
> booting via EFI) takes precedence over the builtin one.
> 
> Signed-off-by: Eslam Elnikety <elnikety@xxxxxxxxxx>
> 
> ---
> Changes in v2:
> - Allow for ucode=<integer>|scan,{no-}builtin and detail the model. Reflect
>   those changes onto microcode.c and docs/misc/xen-command-line.pandoc
> - Add documentation to the existing docs/admin-guide/microcode-loading.rst
> - Build on Patches 1--3 to avoid xmalloc/memcpy for the builtin microcode
> - Work configuration in order to specify the individual microcode blobs to use
>   for the builtin microcode, and rework the microcode/Makefile accordingly
> ---
>  docs/admin-guide/microcode-loading.rst | 31 +++++++++++++++
>  docs/misc/xen-command-line.pandoc      | 10 ++++-
>  xen/arch/x86/Kconfig                   | 30 +++++++++++++++
>  xen/arch/x86/Makefile                  |  1 +
>  xen/arch/x86/microcode.c               | 52 ++++++++++++++++++++++++++
>  xen/arch/x86/microcode/Makefile        | 46 +++++++++++++++++++++++
>  xen/arch/x86/xen.lds.S                 | 12 ++++++
>  7 files changed, 180 insertions(+), 2 deletions(-)
>  create mode 100644 xen/arch/x86/microcode/Makefile
> 
> diff --git a/docs/admin-guide/microcode-loading.rst 
> b/docs/admin-guide/microcode-loading.rst
> index e83cadd2c2..989e8d446b 100644
> --- a/docs/admin-guide/microcode-loading.rst
> +++ b/docs/admin-guide/microcode-loading.rst
> @@ -104,6 +104,37 @@ The ``ucode=scan`` command line option will cause Xen to 
> search through all
>  modules to find any CPIO archives, and search the archive for the applicable
>  file.  Xen will stop searching at the first match.
>  
> +Loading microcode built within the Xen image

I think either s/within/into/ or e.g. s/built/contained/.

> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Xen can bundle microcode updates within its image. This support is 
> conditional
> +on the build configuration BUILTIN_UCODE being enabled. Builtin microcode is
> +useful to ensure that, by default, a minimum microcode patch level will be
> +applied to the underlying CPU.
> +
> +To use microcode updates available on the build system as builtin,
> +use BUILTIN_UCODE_DIR to refer to the directory containing the firmware 
> updates
> +and specify the individual microcode patches via either BUILTIN_UCODE_AMD or
> +BUILTIN_UCODE_INTEL for AMD microcode or INTEL microcode, respectively. For
> +instance, the configuration below is suitable for a build system which has a
> +``/lib/firmware/`` directory which, in turn, includes the individual 
> microcode
> +patches ``amd-ucode/microcode_amd_fam15h.bin``, ``intel-ucode/06-3a-09``, and
> +``intel-ucode/06-2f-02``.
> +
> +  CONFIG_BUILTIN_UCODE=y
> +  CONFIG_BUILTIN_UCODE_DIR="/lib/firmware/"
> +  CONFIG_BUILTIN_UCODE_AMD="amd-ucode/microcode_amd_fam15h.bin"
> +  CONFIG_BUILTIN_UCODE_INTEL="intel-ucode/06-3a-09 intel-ucode/06-2f-02"

Rather than a blank as separator, the more conventional one on
Unix and alike would be : I think. Of course ideally there wouldn't
be any restriction at all on the characters usable here for file
names.

> --- a/xen/arch/x86/Kconfig
> +++ b/xen/arch/x86/Kconfig
> @@ -218,6 +218,36 @@ config MEM_SHARING
>       bool "Xen memory sharing support" if EXPERT = "y"
>       depends on HVM
>  
> +config BUILTIN_UCODE
> +     bool "Support for Builtin Microcode"
> +     ---help---
> +       Include the CPU microcode update in the Xen image itself. With this
> +       support, Xen can update the CPU microcode upon boot using the builtin
> +       microcode, with no need for an additional microcode boot modules.
> +
> +       If unsure, say N.

I continue to be unconvinced that this separate option is needed.
Albeit compared to the v1 approach I will agree that handling
would become more complicated without.

> +config BUILTIN_UCODE_DIR
> +     string "Directory containing microcode updates"
> +     default "/lib/firmware/"
> +     depends on BUILTIN_UCODE
> +     ---help---
> +       The directory containing the microcode blobs.
> +
> +config BUILTIN_UCODE_AMD
> +     string "AMD microcode updates"
> +     default ""
> +     depends on BUILTIN_UCODE
> +     ---help---
> +       AMD builtin microcode; space-sparated, relative to BUILTIN_UCODE_DIR.
> +
> +config BUILTIN_UCODE_INTEL
> +     string "INTEL microcode updates"
> +     default ""
> +     depends on BUILTIN_UCODE
> +     ---help---
> +       INTEL builtin microcode; space-sparated, relative to 
> BUILTIN_UCODE_DIR.

I don't think Intel is commonly spelled all uppercase.

I further think you want to mention further constraints (beyond
the separator to use): DIR would probably better be an absolute
path, it's ambiguous (right here, i.e. without looking at the
implementation) whether a trailing slash needs including), the
individual blobs may include paths, and it's ambiguous again
what them having a leading slash would mean (I think it would be
better if it was "absolute or relative to BUILTIN_UCODE_DIR").

Also a spelling nit: "separated".

> --- a/xen/arch/x86/microcode.c
> +++ b/xen/arch/x86/microcode.c
> @@ -97,6 +97,14 @@ static struct ucode_mod_blob __initdata ucode_blob;
>   */
>  static bool_t __initdata ucode_scan;
>  
> +#ifdef CONFIG_BUILTIN_UCODE
> +/* builtin is the default when BUILTIN_UCODE is set */
> +static bool __initdata ucode_builtin = true;
> +
> +extern const char __builtin_intel_ucode_start[], __builtin_intel_ucode_end[];
> +extern const char __builtin_amd_ucode_start[], __builtin_amd_ucode_end[];

While we do use plain char elsewhere for similar purposes, I think
this is bad practice. It would better be unsigned char or uint8_t.

> @@ -208,6 +220,40 @@ void __init microcode_grab_module(
>          ucode_mod = mod[ucode_mod_idx];
>      else if ( ucode_scan )
>          microcode_scan_module(module_map, mbi);
> +
> +#ifdef CONFIG_BUILTIN_UCODE
> +    /*
> +     * Do not use the builtin microcode if:
> +     * (a) builtin has been explicitly turned off (e.g., ucode=no-builtin)
> +     * (b) a microcode module has been specified or a scan is successful
> +     */
> +    if ( !ucode_builtin || ucode_mod.mod_end || ucode_blob.size )
> +    {
> +        ucode_builtin = false;
> +        return;
> +    }
> +
> +    /* Set ucode_start/_end to the proper blob */
> +    if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
> +    {
> +        ucode_blob.size = __builtin_amd_ucode_end - 
> __builtin_amd_ucode_start;
> +        ucode_blob.data = __builtin_amd_ucode_start;
> +    }
> +    else if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
> +    {
> +        ucode_blob.size = __builtin_intel_ucode_end -
> +                          __builtin_intel_ucode_start;
> +        ucode_blob.data = __builtin_intel_ucode_start;
> +    }
> +    else
> +        return;

"switch ( boot_cpu_data.x86_vendor )" please.

> +    if ( !ucode_blob.size )
> +    {
> +        printk("No builtin ucode for the CPU vendor.\n");

Please either omit "for the CPU vendor" or name the vendor. In any
event please omit the full stop.

> @@ -701,7 +747,13 @@ static int __init microcode_init(void)
>       */
>      if ( ucode_blob.size )
>      {
> +#ifdef CONFIG_BUILTIN_UCODE
> +        /* No need to destroy module mappings if builtin was used */
> +        if ( !ucode_builtin )
> +            bootstrap_map(NULL);
> +#else
>          bootstrap_map(NULL);
> +#endif

First of all - is there no ucode unrelated side effect of this
invocation? I.e. can it safely be skipped? If yes, then I think
you want to get away without #ifdef here, by having a suitably
placed

#define ucode_builtin false

somewhere up the file.

> --- /dev/null
> +++ b/xen/arch/x86/microcode/Makefile
> @@ -0,0 +1,46 @@
> +# Copyright (C) 2019 Amazon.com, Inc. or its affiliates.
> +# Author: Eslam Elnikety <elnikety@xxxxxxxxxx>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +
> +# Remove quotes and excess spaces from configuration strings
> +UCODE_DIR=$(strip $(subst $\",,$(CONFIG_BUILTIN_UCODE_DIR)))
> +UCODE_AMD=$(strip $(subst $\",,$(CONFIG_BUILTIN_UCODE_AMD)))
> +UCODE_INTEL=$(strip $(subst $\",,$(CONFIG_BUILTIN_UCODE_INTEL)))
> +
> +# AMD and INTEL microcode blobs. Use 'wildcard' to filter for existing blobs.
> +amd-blobs := $(wildcard $(addprefix $(UCODE_DIR),$(UCODE_AMD)))
> +intel-blobs := $(wildcard $(addprefix $(UCODE_DIR),$(UCODE_INTEL)))
> +
> +ifneq ($(amd-blobs),)
> +obj-y += ucode_amd.o
> +endif
> +
> +ifneq ($(intel-blobs),)
> +obj-y += ucode_intel.o
> +endif
> +
> +ifeq ($(amd-blobs)$(intel-blobs),)
> +obj-y += ucode_dummy.o
> +endif
> +
> +ucode_amd.o: Makefile $(amd-blobs)
> +     cat $(amd-blobs) > $@.bin
> +     $(OBJCOPY) -I binary -O elf64-x86-64 -B i386:x86-64 --rename-section 
> .data=.builtin_amd_ucode,alloc,load,readonly,data,contents $@.bin $@
> +     rm -f $@.bin
> +
> +ucode_intel.o: Makefile $(intel-blobs)
> +     cat $(intel-blobs) > $@.bin
> +     $(OBJCOPY) -I binary -O elf64-x86-64 -B i386:x86-64 --rename-section 
> .data=.builtin_intel_ucode,alloc,load,readonly,data,contents $@.bin $@
> +     rm -f $@.bin

This can be had with a pattern rule (with the vendor being the stem)
and hence without duplication, I think.

Also - is simply concatenating the blobs reliable enough? There's no
build time diagnostic that the result would actually be understood
at runtime.

> +ucode_dummy.o: Makefile
> +     $(CC) $(CFLAGS) -c -x c /dev/null -o $@;

Since the commit message doesn't explain why this is needed, I
have to ask (I guess we somewhere have a dependency on $(obj-y)
not being empty). _If_ it is needed, I don't see why you need
ifeq() around its use. In fact you could have

obj-y := ucode-dummy.o

right at the top of the file.

Furthermore I don't really understand why you need this in the
first place. While cat won't do what you want with an empty
argument list, can't you simply prepend / append /dev/null?

> --- a/xen/arch/x86/xen.lds.S
> +++ b/xen/arch/x86/xen.lds.S
> @@ -265,6 +265,18 @@ SECTIONS
>         *(SORT(.data.vpci.*))
>         __end_vpci_array = .;
>  #endif
> +
> +#if defined(CONFIG_BUILTIN_UCODE)
> +       . = ALIGN(POINTER_ALIGN);

Why (same further down)? The alignment of both vendors' header
structures is just 4 afaict.

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.