Skip to content

Commit

Permalink
Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/sc…
Browse files Browse the repository at this point in the history
…m/linux/kernel/git/tip/tip

Pull x86 microcode updates from Ingo Molnar:
 "The biggest change in this cycle was the separation of the microcode
  loading mechanism from the initrd code plus the support of built-in
  microcode images.

  There were also lots cleanups and general restructuring (by Borislav
  Petkov)"

* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
  x86/microcode/intel: Drop orig_sum from ext signature checksum
  x86/microcode/intel: Improve microcode sanity-checking error messages
  x86/microcode/intel: Merge two consecutive if-statements
  x86/microcode/intel: Get rid of DWSIZE
  x86/microcode/intel: Change checksum variables to u32
  x86/microcode: Use kmemdup() rather than duplicating its implementation
  x86/microcode: Remove unnecessary paravirt_enabled check
  x86/microcode: Document builtin microcode loading method
  x86/microcode/AMD: Issue microcode updated message later
  x86/microcode/intel: Cleanup get_matching_model_microcode()
  x86/microcode/intel: Remove unused arg of get_matching_model_microcode()
  x86/microcode/intel: Rename mc_saved_in_initrd
  x86/microcode/intel: Use *wrmsrl variants
  x86/microcode/intel: Cleanup apply_microcode_intel()
  x86/microcode/intel: Move the BUG_ON up and turn it into WARN_ON
  x86/microcode/intel: Rename mc_intel variable to mc
  x86/microcode/intel: Rename mc_saved_count to num_saved
  x86/microcode/intel: Rename local variables of type struct mc_saved_data
  x86/microcode/AMD: Drop redundant printk prefix
  x86/microcode: Issue update message only once
  ...
  • Loading branch information
torvalds committed Mar 15, 2016
2 parents ecc026b + 4ace2e7 commit 9cf8d63
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 203 deletions.
25 changes: 25 additions & 0 deletions Documentation/x86/early-microcode.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,28 @@ cp ../microcode.bin kernel/x86/microcode/GenuineIntel.bin (or AuthenticAMD.bin)
find . | cpio -o -H newc >../ucode.cpio
cd ..
cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img

Builtin microcode
=================

We can also load builtin microcode supplied through the regular firmware
builtin method CONFIG_FIRMWARE_IN_KERNEL. Here's an example:

CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin"
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"

This basically means, you have the following tree structure locally:

/lib/firmware/
|-- amd-ucode
...
| |-- microcode_amd_fam15h.bin
...
|-- intel-ucode
...
| |-- 06-3a-09
...

so that the build system can find those files and integrate them into
the final kernel image. The early loader finds them and applies them.
27 changes: 14 additions & 13 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1163,22 +1163,23 @@ config MICROCODE
bool "CPU microcode loading support"
default y
depends on CPU_SUP_AMD || CPU_SUP_INTEL
depends on BLK_DEV_INITRD
select FW_LOADER
---help---

If you say Y here, you will be able to update the microcode on
certain Intel and AMD processors. The Intel support is for the
IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4,
Xeon etc. The AMD support is for families 0x10 and later. You will
obviously need the actual microcode binary data itself which is not
shipped with the Linux kernel.

This option selects the general module only, you need to select
at least one vendor specific module as well.

To compile this driver as a module, choose M here: the module
will be called microcode.
Intel and AMD processors. The Intel support is for the IA32 family,
e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, Xeon etc. The
AMD support is for families 0x10 and later. You will obviously need
the actual microcode binary data itself which is not shipped with
the Linux kernel.

The preferred method to load microcode from a detached initrd is described
in Documentation/x86/early-microcode.txt. For that you need to enable
CONFIG_BLK_DEV_INITRD in order for the loader to be able to scan the
initrd for microcode blobs.

In addition, you can build-in the microcode into the kernel. For that you
need to enable FIRMWARE_IN_KERNEL and add the vendor-supplied microcode
to the CONFIG_EXTRA_FIRMWARE config option.

config MICROCODE_INTEL
bool "Intel microcode loading support"
Expand Down
26 changes: 26 additions & 0 deletions arch/x86/include/asm/microcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <asm/cpu.h>
#include <linux/earlycpio.h>
#include <linux/initrd.h>

#define native_rdmsr(msr, val1, val2) \
do { \
Expand Down Expand Up @@ -143,4 +144,29 @@ static inline void reload_early_microcode(void) { }
static inline bool
get_builtin_firmware(struct cpio_data *cd, const char *name) { return false; }
#endif

static inline unsigned long get_initrd_start(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
return initrd_start;
#else
return 0;
#endif
}

static inline unsigned long get_initrd_start_addr(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
#ifdef CONFIG_X86_32
unsigned long *initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);

return (unsigned long)__pa_nodebug(*initrd_start_p);
#else
return get_initrd_start();
#endif
#else /* CONFIG_BLK_DEV_INITRD */
return 0;
#endif
}

#endif /* _ASM_X86_MICROCODE_H */
1 change: 0 additions & 1 deletion arch/x86/include/asm/microcode_intel.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ struct extended_sigtable {
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
#define DWSIZE (sizeof(u32))

#define get_totalsize(mc) \
(((struct microcode_intel *)mc)->hdr.datasize ? \
Expand Down
15 changes: 6 additions & 9 deletions arch/x86/kernel/cpu/microcode/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,10 +431,6 @@ int __init save_microcode_in_initrd_amd(void)
else
container = cont_va;

if (ucode_new_rev)
pr_info("microcode: updated early to new patch_level=0x%08x\n",
ucode_new_rev);

eax = cpuid_eax(0x00000001);
eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);

Expand Down Expand Up @@ -469,8 +465,7 @@ void reload_ucode_amd(void)
if (mc && rev < mc->hdr.patch_id) {
if (!__apply_microcode_amd(mc)) {
ucode_new_rev = mc->hdr.patch_id;
pr_info("microcode: reload patch_level=0x%08x\n",
ucode_new_rev);
pr_info("reload patch_level=0x%08x\n", ucode_new_rev);
}
}
}
Expand Down Expand Up @@ -793,15 +788,13 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
return -EINVAL;
}

patch->data = kzalloc(patch_size, GFP_KERNEL);
patch->data = kmemdup(fw + SECTION_HDR_SIZE, patch_size, GFP_KERNEL);
if (!patch->data) {
pr_err("Patch data allocation failure.\n");
kfree(patch);
return -EINVAL;
}

/* All looks ok, copy patch... */
memcpy(patch->data, fw + SECTION_HDR_SIZE, patch_size);
INIT_LIST_HEAD(&patch->plist);
patch->patch_id = mc_hdr->patch_id;
patch->equiv_cpu = proc_id;
Expand Down Expand Up @@ -957,6 +950,10 @@ struct microcode_ops * __init init_amd_microcode(void)
return NULL;
}

if (ucode_new_rev)
pr_info_once("microcode updated early to new patch_level=0x%08x\n",
ucode_new_rev);

return &microcode_amd_ops;
}

Expand Down
19 changes: 6 additions & 13 deletions arch/x86/kernel/cpu/microcode/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,8 @@
#define MICROCODE_VERSION "2.01"

static struct microcode_ops *microcode_ops;

static bool dis_ucode_ldr;

static int __init disable_loader(char *str)
{
dis_ucode_ldr = true;
return 1;
}
__setup("dis_ucode_ldr", disable_loader);

/*
* Synchronization.
*
Expand Down Expand Up @@ -81,15 +73,16 @@ struct cpu_info_ctx {

static bool __init check_loader_disabled_bsp(void)
{
static const char *__dis_opt_str = "dis_ucode_ldr";

#ifdef CONFIG_X86_32
const char *cmdline = (const char *)__pa_nodebug(boot_command_line);
const char *opt = "dis_ucode_ldr";
const char *option = (const char *)__pa_nodebug(opt);
const char *option = (const char *)__pa_nodebug(__dis_opt_str);
bool *res = (bool *)__pa_nodebug(&dis_ucode_ldr);

#else /* CONFIG_X86_64 */
const char *cmdline = boot_command_line;
const char *option = "dis_ucode_ldr";
const char *option = __dis_opt_str;
bool *res = &dis_ucode_ldr;
#endif

Expand Down Expand Up @@ -479,7 +472,7 @@ static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
enum ucode_state ustate;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

if (uci && uci->valid)
if (uci->valid)
return UCODE_OK;

if (collect_cpu_info(cpu))
Expand Down Expand Up @@ -630,7 +623,7 @@ int __init microcode_init(void)
struct cpuinfo_x86 *c = &boot_cpu_data;
int error;

if (paravirt_enabled() || dis_ucode_ldr)
if (dis_ucode_ldr)
return -EINVAL;

if (c->x86_vendor == X86_VENDOR_INTEL)
Expand Down
Loading

0 comments on commit 9cf8d63

Please sign in to comment.