On Wed, Jan 31, 2018 at 09:46:52AM -0800, Mike Larkin 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
> >
>
> I like the idea. We should probably make sure it works with sr crypto also,
> I can check that later today unless someone beats me to it.
That would be nice!
> After that, I'll review the diff more carefully. Are you looking for oks yet,
> or is this just being passed around for comments at this time?
I can start collecting OKs I guess. :) I have no other changes pending
for this, so as long as there is no negative feedback I intend to commit
this at some point. Before doing that, I want to collect a bit of feed-
back and test results.
> Thanks!
No, thank you and Philip for the hard work during the last few weeks!
Patrick
> -ml
>
> > diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c
> > index 8a779aa65eb..cb1b50947ba 100644
> > --- a/sys/arch/amd64/amd64/cpu.c
> > +++ b/sys/arch/amd64/amd64/cpu.c
> > @@ -406,21 +406,20 @@ 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);
> > + cpu_ucode_apply(ci);
> > 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);
> > + cpu_ucode_apply(ci);
> > identifycpu(ci);
> > #ifdef MTRR
> > mem_range_attach();
> > @@ -438,9 +437,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 +694,7 @@ cpu_hatch(void *v)
> >
> > lapic_enable();
> > lapic_startclock();
> > + cpu_ucode_apply(ci);
> >
> > if ((ci->ci_flags & CPUF_IDENTIFIED) == 0) {
> > /*
> > @@ -738,8 +735,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 +934,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..d3320282998 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,7 @@ cpu_startup(void)
> >
> > /* Safe for i/o port / memory space allocation to use malloc now. */
> > x86_bus_space_mallocok();
> > + cpu_ucode_setup();
> > }
> >
> > /*
> > @@ -1886,6 +1888,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..908e40f96ba 100644
> > --- a/sys/arch/amd64/amd64/ucode.c
> > +++ b/sys/arch/amd64/amd64/ucode.c
> > @@ -19,10 +19,14 @@
> > #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 */
> > #ifdef UCODE_DEBUG
> > @@ -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);
> > }
> >
> > /*
> > 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;
> >
>