On Mon, Feb 05, 2018 at 11:02:27AM +1300, Patrick Wildt wrote:
> On Wed, Jan 31, 2018 at 05:12:03PM +0100, Patrick Wildt wrote:
> > Hi,
> > 
> > this diff allows us to load the Intel microcode much earlier.  So far
> > we load it after the CPUs have identified and then have to update the
> > CPU flags afterwards.  This is not good since we have to assume that
> > those updates can remove and add instructions and other features.  We
> > need to load it earlier.  The only other option is to have the boot-
> > blocks load the ucode for us.
> > 
> > One issue though is actually loading and passing the binaries that can
> > range from 2k to 90k of binary size.  As far as I know we don't use the
> > lower 16M of memory on amd64, which the bootblocks use as heap.  Thus
> > allocating a buffer for using alloc() should be "fine" if we make sure
> > that we read the ucode after we early enough.  kettenis@ tells me that
> > cpu_startup() is the earliest MD code which can use malloc(9), so that
> > is where we can copy the ucode from the bootloader to kernel land.
> > 
> > I have tested this with efiboot(8), more tests would be appreciated.
> > 
> > Thanks,
> > Patrick
> 
> Updated diff.  RAMDISK compiles and runs through make release without
> any further issues.
> 
> This diff also enables the debug printfs, so people testing this diff
> should see something happening in dmesg.  I will not commit that diff
> with the prints enabled.
> 
> Please report back.  Some more stuff should be seen when doing
> 
>       $ dmesg | grep ucode
> 
> Please not that you have to build and install the bootloader in addtion
> to installing a new kernel.
> 
> Thanks,
> Patrick
> 

I did a single test with sr crypto and didn't see any issues, fwiw.

-ml

> diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c
> index 8a779aa65eb..5ec7e7f6409 100644
> --- a/sys/arch/amd64/amd64/cpu.c
> +++ b/sys/arch/amd64/amd64/cpu.c
> @@ -406,21 +406,24 @@ cpu_attach(struct device *parent, struct device *self, 
> void *aux)
>               printf("(uniprocessor)\n");
>               ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY;
>               cpu_intr_init(ci);
> +#ifndef SMALL_KERNEL
> +             cpu_ucode_apply(ci);
> +#endif
>               identifycpu(ci);
>  #ifdef MTRR
>               mem_range_attach();
>  #endif /* MTRR */
>               cpu_init(ci);
>               cpu_init_mwait(sc);
> -#ifndef SMALL_KERNEL
> -             config_mountroot(NULL, cpu_ucode_attachhook);
> -#endif
>               break;
>  
>       case CPU_ROLE_BP:
>               printf("apid %d (boot processor)\n", caa->cpu_apicid);
>               ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY;
>               cpu_intr_init(ci);
> +#ifndef SMALL_KERNEL
> +             cpu_ucode_apply(ci);
> +#endif
>               identifycpu(ci);
>  #ifdef MTRR
>               mem_range_attach();
> @@ -438,9 +441,6 @@ cpu_attach(struct device *parent, struct device *self, 
> void *aux)
>               ioapic_bsp_id = caa->cpu_apicid;
>  #endif
>               cpu_init_mwait(sc);
> -#ifndef SMALL_KERNEL
> -             config_mountroot(NULL, cpu_ucode_attachhook);
> -#endif
>               break;
>  
>       case CPU_ROLE_AP:
> @@ -698,6 +698,7 @@ cpu_hatch(void *v)
>  
>       lapic_enable();
>       lapic_startclock();
> +     cpu_ucode_apply(ci);
>  
>       if ((ci->ci_flags & CPUF_IDENTIFIED) == 0) {
>               /*
> @@ -738,8 +739,6 @@ cpu_hatch(void *v)
>       lldt(0);
>  
>       cpu_init(ci);
> -     cpu_ucode_apply(ci);
> -     cpu_flags_update(ci);
>  #if NPVBUS > 0
>       pvbus_init_cpu();
>  #endif
> @@ -939,20 +938,3 @@ cpu_activate(struct device *self, int act)
>  
>       return (0);
>  }
> -
> -void
> -cpu_flags_update(struct cpu_info *ci)
> -{
> -     uint32_t dummy;
> -
> -     /* XXX this update is much later than we want it to be */
> -     if (cpuid_level >= 0x07) {
> -             CPUID_LEAF(0x7, 0, dummy, dummy, dummy,
> -                 ci->ci_feature_sefflags_edx);
> -     }
> -     if (!strcmp(cpu_vendor, "AuthenticAMD") &&
> -         ci->ci_pnfeatset >= 0x80000008) {
> -             CPUID(0x80000008, dummy, ci->ci_feature_amdspec_ebx,
> -                 dummy, dummy);
> -     }
> -}
> diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
> index 33d1d38395b..940716c174c 100644
> --- a/sys/arch/amd64/amd64/machdep.c
> +++ b/sys/arch/amd64/amd64/machdep.c
> @@ -241,6 +241,7 @@ bios_diskinfo_t   *bios_diskinfo;
>  bios_memmap_t        *bios_memmap;
>  u_int32_t    bios_cksumlen;
>  bios_efiinfo_t       *bios_efiinfo;
> +bios_ucode_t *bios_ucode;
>  
>  /*
>   * Size of memory segments, before any memory is stolen.
> @@ -308,6 +309,10 @@ cpu_startup(void)
>  
>       /* Safe for i/o port / memory space allocation to use malloc now. */
>       x86_bus_space_mallocok();
> +
> +#ifndef SMALL_KERNEL
> +     cpu_ucode_setup();
> +#endif
>  }
>  
>  /*
> @@ -1886,6 +1891,10 @@ getbootinfo(char *bootinfo, int bootinfo_size)
>                               docninit++;
>                       break;
>  
> +             case BOOTARG_UCODE:
> +                     bios_ucode = (bios_ucode_t *)q->ba_arg;
> +                     break;
> +
>               default:
>  #ifdef BOOTINFO_DEBUG
>                       printf(" unsupported arg (%d) %p", q->ba_type,
> diff --git a/sys/arch/amd64/amd64/ucode.c b/sys/arch/amd64/amd64/ucode.c
> index ceec53dafea..7b807125782 100644
> --- a/sys/arch/amd64/amd64/ucode.c
> +++ b/sys/arch/amd64/amd64/ucode.c
> @@ -19,12 +19,16 @@
>  #include <sys/param.h>
>  #include <sys/systm.h>
>  #include <sys/mutex.h>
> +#include <sys/malloc.h>
> +
> +#include <uvm/uvm_extern.h>
>  
>  #include <machine/cpu.h>
>  #include <machine/cpufunc.h>
>  #include <machine/specialreg.h>
> +#include <machine/biosvar.h>
>  
> -/* #define UCODE_DEBUG */
> +#define UCODE_DEBUG
>  #ifdef UCODE_DEBUG
>  #define DPRINTF(x)   do { if (cpu_ucode_debug > 0) printf x; } while (0)
>  #define DPRINTFN(n, x)       do { if (cpu_ucode_debug >= (n)) printf x; } 
> while (0)
> @@ -65,7 +69,7 @@ struct intel_ucode_ext_sig {
>  char *        cpu_ucode_data;
>  size_t        cpu_ucode_size;
>  
> -void  cpu_ucode_setup(struct cpu_info *);
> +void  cpu_ucode_setup(void);
>  void  cpu_ucode_apply(struct cpu_info *);
>  
>  /* Intel */
> @@ -81,32 +85,18 @@ struct intel_ucode_header *cpu_ucode_intel_applied;
>  struct mutex                  cpu_ucode_intel_mtx = 
> MUTEX_INITIALIZER(IPL_HIGH);
>  
>  void
> -cpu_ucode_attachhook(struct device *dv)
> +cpu_ucode_setup(void)
>  {
> -     struct cpu_info *ci = curcpu();
> -
> -     cpu_ucode_setup(ci);
> -     cpu_ucode_apply(ci);
> -     cpu_flags_update(ci);
> -}
> -
> -void
> -cpu_ucode_setup(struct cpu_info *ci)
> -{
> -     char name[128];
> -     u_char *ucode;
> -     size_t size;
> -
> -     snprintf(name, sizeof(name), "intel/%02x-%02x-%02x", ci->ci_family,
> -         ci->ci_model, (ci->ci_signature >> 0) & 0x0f);
> +     if (bios_ucode == NULL)
> +             return;
>  
> -     if (loadfirmware(name, &ucode, &size) != 0) {
> -             DPRINTF(("%s: no microcode found: %s\n", __func__, name));
> +     if (!bios_ucode->uc_addr || !bios_ucode->uc_size)
>               return;
> -     }
>  
> -     cpu_ucode_data = ucode;
> -     cpu_ucode_size = size;
> +     cpu_ucode_size = bios_ucode->uc_size;
> +     cpu_ucode_data = malloc(cpu_ucode_size, M_DEVBUF, M_WAITOK);
> +     memcpy(cpu_ucode_data, (void *)PMAP_DIRECT_MAP(bios_ucode->uc_addr),
> +         cpu_ucode_size);
>  }
>  
>  /*
> @@ -126,8 +116,10 @@ cpu_ucode_intel_apply(struct cpu_info *ci)
>       uint32_t old_rev, new_rev;
>       paddr_t data;
>  
> -     if (cpu_ucode_data == NULL || cpu_ucode_size == 0)
> +     if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
> +             DPRINTF(("%s: no microcode provided\n", __func__));
>               return;
> +     }
>  
>       /*
>        * Grab a mutex, because we are not allowed to run updates
> @@ -140,10 +132,14 @@ cpu_ucode_intel_apply(struct cpu_info *ci)
>       if (update == NULL)
>               update = cpu_ucode_intel_find(cpu_ucode_data,
>                   cpu_ucode_size, old_rev);
> -     if (update == NULL)
> +     if (update == NULL) {
> +             DPRINTF(("%s: no microcode update found\n", __func__));
>               goto out;
> -     if (update->update_revision == old_rev)
> +     }
> +     if (update->update_revision == old_rev) {
> +             DPRINTF(("%s: microcode already up-to-date\n", __func__));
>               goto out;
> +     }
>  
>       /* Apply microcode. */
>       data = (paddr_t)update;
> diff --git a/sys/arch/amd64/include/biosvar.h 
> b/sys/arch/amd64/include/biosvar.h
> index dcb59d766ca..9c7f3b5e7b4 100644
> --- a/sys/arch/amd64/include/biosvar.h
> +++ b/sys/arch/amd64/include/biosvar.h
> @@ -206,6 +206,12 @@ typedef struct _bios_efiinfo {
>       uint32_t        fb_reserved_mask;
>  } __packed bios_efiinfo_t;
>  
> +#define      BOOTARG_UCODE 12
> +typedef struct _bios_ucode {
> +     uint64_t        uc_addr;
> +     uint64_t        uc_size;
> +} __packed bios_ucode_t;
> +
>  #if defined(_KERNEL) || defined (_STANDALONE)
>  
>  #ifdef _LOCORE
> @@ -254,6 +260,7 @@ bios_diskinfo_t *bios_getdiskinfo(dev_t);
>  extern u_int bootapiver;
>  extern bios_memmap_t *bios_memmap;
>  extern bios_efiinfo_t *bios_efiinfo;
> +extern bios_ucode_t *bios_ucode;
>  
>  #endif /* _KERNEL */
>  #endif /* _LOCORE */
> diff --git a/sys/arch/amd64/include/cpufunc.h 
> b/sys/arch/amd64/include/cpufunc.h
> index a86ac711a80..67398c5f077 100644
> --- a/sys/arch/amd64/include/cpufunc.h
> +++ b/sys/arch/amd64/include/cpufunc.h
> @@ -314,9 +314,8 @@ breakpoint(void)
>  }
>  
>  void amd64_errata(struct cpu_info *);
> -void cpu_flags_update(struct cpu_info *);
> +void cpu_ucode_setup(void);
>  void cpu_ucode_apply(struct cpu_info *);
> -void cpu_ucode_attachhook(struct device *);
>  
>  #endif /* _KERNEL */
>  
> diff --git a/sys/arch/amd64/stand/boot/conf.c 
> b/sys/arch/amd64/stand/boot/conf.c
> index 6bb7271de00..b00fec88696 100644
> --- a/sys/arch/amd64/stand/boot/conf.c
> +++ b/sys/arch/amd64/stand/boot/conf.c
> @@ -40,7 +40,7 @@
>  #include <biosdev.h>
>  #include <dev/cons.h>
>  
> -const char version[] = "3.33";
> +const char version[] = "3.34";
>  int  debug = 1;
>  
>  
> diff --git a/sys/arch/amd64/stand/cdboot/conf.c 
> b/sys/arch/amd64/stand/cdboot/conf.c
> index 29088565aa8..acca472568a 100644
> --- a/sys/arch/amd64/stand/cdboot/conf.c
> +++ b/sys/arch/amd64/stand/cdboot/conf.c
> @@ -41,7 +41,7 @@
>  #include <biosdev.h>
>  #include <dev/cons.h>
>  
> -const char version[] = "3.28";
> +const char version[] = "3.29";
>  int  debug = 1;
>  
>  
> diff --git a/sys/arch/amd64/stand/efiboot/conf.c 
> b/sys/arch/amd64/stand/efiboot/conf.c
> index b91d7485dea..7c0e8361d6b 100644
> --- a/sys/arch/amd64/stand/efiboot/conf.c
> +++ b/sys/arch/amd64/stand/efiboot/conf.c
> @@ -39,7 +39,7 @@
>  #include "efidev.h"
>  #include "efipxe.h"
>  
> -const char version[] = "3.37";
> +const char version[] = "3.38";
>  
>  #ifdef EFI_DEBUG
>  int  debug = 0;
> diff --git a/sys/arch/amd64/stand/libsa/exec_i386.c 
> b/sys/arch/amd64/stand/libsa/exec_i386.c
> index eecefb2c2d8..335109aeab4 100644
> --- a/sys/arch/amd64/stand/libsa/exec_i386.c
> +++ b/sys/arch/amd64/stand/libsa/exec_i386.c
> @@ -33,8 +33,10 @@
>  #include <dev/cons.h>
>  #include <lib/libsa/loadfile.h>
>  #include <machine/biosvar.h>
> +#include <machine/specialreg.h>
>  #include <stand/boot/bootarg.h>
>  
> +#include "cmd.h"
>  #include "disk.h"
>  #include "libsa.h"
>  
> @@ -51,6 +53,9 @@
>  typedef void (*startfuncp)(int, int, int, int, int, int, int, int)
>      __attribute__ ((noreturn));
>  
> +void ucode_load(void);
> +extern struct cmd_state cmd;
> +
>  char *bootmac = NULL;
>  
>  void
> @@ -102,6 +107,8 @@ run_loadfile(u_long *marks, int howto)
>       bcopy(bootdev_dip->disklabel.d_uid, &bootduid.duid, sizeof(bootduid));
>       addbootarg(BOOTARG_BOOTDUID, sizeof(bootduid), &bootduid);
>  
> +     ucode_load();
> +
>  #ifdef SOFTRAID
>       if (bootdev_dip->sr_vol != NULL) {
>               bv = bootdev_dip->sr_vol;
> @@ -160,3 +167,54 @@ run_loadfile(u_long *marks, int howto)
>  #endif
>       /* not reached */
>  }
> +
> +void
> +ucode_load(void)
> +{
> +     uint32_t model, family, stepping;
> +     uint32_t dummy, signature;
> +     uint32_t vendor[4];
> +     bios_ucode_t uc;
> +     struct stat sb;
> +     char path[128];
> +     size_t buflen;
> +     char *buf;
> +     int fd;
> +
> +     CPUID(0, dummy, vendor[0], vendor[2], vendor[1]);
> +     vendor[3] = 0; /* NULL-terminate */
> +     if (strcmp((char *)vendor, "GenuineIntel") != 0)
> +             return;
> +
> +     CPUID(1, signature, dummy, dummy, dummy);
> +     family = (signature >> 8) & 0x0f;
> +     model = (signature >> 4) & 0x0f;
> +     if (family == 0x6 || family == 0xf) {
> +             family += (signature >> 20) & 0xff;
> +             model += ((signature >> 16) & 0x0f) << 4;
> +     }
> +     stepping = (signature >> 0) & 0x0f;
> +
> +     snprintf(path, sizeof(path), "%s:/etc/firmware/intel/%02x-%02x-%02x",
> +         cmd.bootdev, family, model, stepping);
> +
> +     fd = open(path, 0);
> +     if (fd == -1)
> +             return;
> +
> +     if (fstat(fd, &sb) == -1)
> +             return;
> +
> +     buflen = sb.st_size;
> +     if ((buf = alloc(buflen)) == NULL)
> +             return;
> +
> +     if (read(fd, buf, buflen) != buflen) {
> +             free(buf, buflen);
> +             return;
> +     }
> +
> +     uc.uc_addr = (uint64_t)buf;
> +     uc.uc_size = (uint64_t)buflen;
> +     addbootarg(BOOTARG_UCODE, sizeof(uc), &uc);
> +}
> diff --git a/sys/arch/amd64/stand/pxeboot/conf.c 
> b/sys/arch/amd64/stand/pxeboot/conf.c
> index 4e2484374c3..0e23f9f52c9 100644
> --- a/sys/arch/amd64/stand/pxeboot/conf.c
> +++ b/sys/arch/amd64/stand/pxeboot/conf.c
> @@ -43,7 +43,7 @@
>  #include "pxeboot.h"
>  #include "pxe_net.h"
>  
> -const char version[] = "3.28";
> +const char version[] = "3.29";
>  int  debug = 0;
>  
>  void (*sa_cleanup)(void) = pxe_shutdown;
> 

Reply via email to