Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode loading updates from Ingo Molnar: "Update documentation, improve robustness and fix a memory leak" * 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/microcode/intel: Improve microcode patches saving flow x86/microcode: Document the three loading methods x86/microcode/AMD: Free unneeded patch before exit from update_cache()
This commit is contained in:
commit
0098410dd6
|
@ -1,70 +0,0 @@
|
|||
Early load microcode
|
||||
====================
|
||||
By Fenghua Yu <fenghua.yu@intel.com>
|
||||
|
||||
Kernel can update microcode in early phase of boot time. Loading microcode early
|
||||
can fix CPU issues before they are observed during kernel boot time.
|
||||
|
||||
Microcode is stored in an initrd file. The microcode is read from the initrd
|
||||
file and loaded to CPUs during boot time.
|
||||
|
||||
The format of the combined initrd image is microcode in cpio format followed by
|
||||
the initrd image (maybe compressed). Kernel parses the combined initrd image
|
||||
during boot time. The microcode file in cpio name space is:
|
||||
on Intel: kernel/x86/microcode/GenuineIntel.bin
|
||||
on AMD : kernel/x86/microcode/AuthenticAMD.bin
|
||||
|
||||
During BSP boot (before SMP starts), if the kernel finds the microcode file in
|
||||
the initrd file, it parses the microcode and saves matching microcode in memory.
|
||||
If matching microcode is found, it will be uploaded in BSP and later on in all
|
||||
APs.
|
||||
|
||||
The cached microcode patch is applied when CPUs resume from a sleep state.
|
||||
|
||||
There are two legacy user space interfaces to load microcode, either through
|
||||
/dev/cpu/microcode or through /sys/devices/system/cpu/microcode/reload file
|
||||
in sysfs.
|
||||
|
||||
In addition to these two legacy methods, the early loading method described
|
||||
here is the third method with which microcode can be uploaded to a system's
|
||||
CPUs.
|
||||
|
||||
The following example script shows how to generate a new combined initrd file in
|
||||
/boot/initrd-3.5.0.ucode.img with original microcode microcode.bin and
|
||||
original initrd image /boot/initrd-3.5.0.img.
|
||||
|
||||
mkdir initrd
|
||||
cd initrd
|
||||
mkdir -p kernel/x86/microcode
|
||||
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. Only 64-bit is currently
|
||||
supported.
|
||||
|
||||
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.
|
|
@ -0,0 +1,137 @@
|
|||
The Linux Microcode Loader
|
||||
|
||||
Authors: Fenghua Yu <fenghua.yu@intel.com>
|
||||
Borislav Petkov <bp@suse.de>
|
||||
|
||||
The kernel has a x86 microcode loading facility which is supposed to
|
||||
provide microcode loading methods in the OS. Potential use cases are
|
||||
updating the microcode on platforms beyond the OEM End-Of-Life support,
|
||||
and updating the microcode on long-running systems without rebooting.
|
||||
|
||||
The loader supports three loading methods:
|
||||
|
||||
1. Early load microcode
|
||||
=======================
|
||||
|
||||
The kernel can update microcode very early during boot. Loading
|
||||
microcode early can fix CPU issues before they are observed during
|
||||
kernel boot time.
|
||||
|
||||
The microcode is stored in an initrd file. During boot, it is read from
|
||||
it and loaded into the CPU cores.
|
||||
|
||||
The format of the combined initrd image is microcode in (uncompressed)
|
||||
cpio format followed by the (possibly compressed) initrd image. The
|
||||
loader parses the combined initrd image during boot.
|
||||
|
||||
The microcode files in cpio name space are:
|
||||
|
||||
on Intel: kernel/x86/microcode/GenuineIntel.bin
|
||||
on AMD : kernel/x86/microcode/AuthenticAMD.bin
|
||||
|
||||
During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
|
||||
scans the microcode file in the initrd. If microcode matching the
|
||||
CPU is found, it will be applied in the BSP and later on in all APs
|
||||
(Application Processors).
|
||||
|
||||
The loader also saves the matching microcode for the CPU in memory.
|
||||
Thus, the cached microcode patch is applied when CPUs resume from a
|
||||
sleep state.
|
||||
|
||||
Here's a crude example how to prepare an initrd with microcode (this is
|
||||
normally done automatically by the distribution, when recreating the
|
||||
initrd, so you don't really have to do it yourself. It is documented
|
||||
here for future reference only).
|
||||
|
||||
---
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "You need to supply an initrd file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INITRD="$1"
|
||||
|
||||
DSTDIR=kernel/x86/microcode
|
||||
TMPDIR=/tmp/initrd
|
||||
|
||||
rm -rf $TMPDIR
|
||||
|
||||
mkdir $TMPDIR
|
||||
cd $TMPDIR
|
||||
mkdir -p $DSTDIR
|
||||
|
||||
if [ -d /lib/firmware/amd-ucode ]; then
|
||||
cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
|
||||
fi
|
||||
|
||||
if [ -d /lib/firmware/intel-ucode ]; then
|
||||
cat /lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin
|
||||
fi
|
||||
|
||||
find . | cpio -o -H newc >../ucode.cpio
|
||||
cd ..
|
||||
mv $INITRD $INITRD.orig
|
||||
cat ucode.cpio $INITRD.orig > $INITRD
|
||||
|
||||
rm -rf $TMPDIR
|
||||
---
|
||||
|
||||
The system needs to have the microcode packages installed into
|
||||
/lib/firmware or you need to fixup the paths above if yours are
|
||||
somewhere else and/or you've downloaded them directly from the processor
|
||||
vendor's site.
|
||||
|
||||
2. Late loading
|
||||
===============
|
||||
|
||||
There are two legacy user space interfaces to load microcode, either through
|
||||
/dev/cpu/microcode or through /sys/devices/system/cpu/microcode/reload file
|
||||
in sysfs.
|
||||
|
||||
The /dev/cpu/microcode method is deprecated because it needs a special
|
||||
userspace tool for that.
|
||||
|
||||
The easier method is simply installing the microcode packages your distro
|
||||
supplies and running:
|
||||
|
||||
# echo 1 > /sys/devices/system/cpu/microcode/reload
|
||||
|
||||
as root.
|
||||
|
||||
The loading mechanism looks for microcode blobs in
|
||||
/lib/firmware/{intel-ucode,amd-ucode}. The default distro installation
|
||||
packages already put them there.
|
||||
|
||||
3. Builtin microcode
|
||||
====================
|
||||
|
||||
The loader supports also loading of a builtin microcode supplied through
|
||||
the regular firmware builtin method CONFIG_FIRMWARE_IN_KERNEL. Only
|
||||
64-bit is currently supported.
|
||||
|
||||
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.
|
||||
|
||||
Needless to say, this method is not the most flexible one because it
|
||||
requires rebuilding the kernel each time updated microcode from the CPU
|
||||
vendor is available.
|
|
@ -400,9 +400,12 @@ static void update_cache(struct ucode_patch *new_patch)
|
|||
|
||||
list_for_each_entry(p, µcode_cache, plist) {
|
||||
if (p->equiv_cpu == new_patch->equiv_cpu) {
|
||||
if (p->patch_id >= new_patch->patch_id)
|
||||
if (p->patch_id >= new_patch->patch_id) {
|
||||
/* we already have the latest patch */
|
||||
kfree(new_patch->data);
|
||||
kfree(new_patch);
|
||||
return;
|
||||
}
|
||||
|
||||
list_replace(&p->plist, &new_patch->plist);
|
||||
kfree(p->data);
|
||||
|
|
|
@ -146,18 +146,18 @@ static bool microcode_matches(struct microcode_header_intel *mc_header,
|
|||
return false;
|
||||
}
|
||||
|
||||
static struct ucode_patch *__alloc_microcode_buf(void *data, unsigned int size)
|
||||
static struct ucode_patch *memdup_patch(void *data, unsigned int size)
|
||||
{
|
||||
struct ucode_patch *p;
|
||||
|
||||
p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL);
|
||||
if (!p)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return NULL;
|
||||
|
||||
p->data = kmemdup(data, size, GFP_KERNEL);
|
||||
if (!p->data) {
|
||||
kfree(p);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@ -183,8 +183,8 @@ static void save_microcode_patch(void *data, unsigned int size)
|
|||
if (mc_hdr->rev <= mc_saved_hdr->rev)
|
||||
continue;
|
||||
|
||||
p = __alloc_microcode_buf(data, size);
|
||||
if (IS_ERR(p))
|
||||
p = memdup_patch(data, size);
|
||||
if (!p)
|
||||
pr_err("Error allocating buffer %p\n", data);
|
||||
else
|
||||
list_replace(&iter->plist, &p->plist);
|
||||
|
@ -196,24 +196,25 @@ static void save_microcode_patch(void *data, unsigned int size)
|
|||
* newly found.
|
||||
*/
|
||||
if (!prev_found) {
|
||||
p = __alloc_microcode_buf(data, size);
|
||||
if (IS_ERR(p))
|
||||
p = memdup_patch(data, size);
|
||||
if (!p)
|
||||
pr_err("Error allocating buffer for %p\n", data);
|
||||
else
|
||||
list_add_tail(&p->plist, µcode_cache);
|
||||
}
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Save for early loading. On 32-bit, that needs to be a physical
|
||||
* address as the APs are running from physical addresses, before
|
||||
* paging has been enabled.
|
||||
*/
|
||||
if (p) {
|
||||
if (IS_ENABLED(CONFIG_X86_32))
|
||||
intel_ucode_patch = (struct microcode_intel *)__pa_nodebug(p->data);
|
||||
else
|
||||
intel_ucode_patch = p->data;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_X86_32))
|
||||
intel_ucode_patch = (struct microcode_intel *)__pa_nodebug(p->data);
|
||||
else
|
||||
intel_ucode_patch = p->data;
|
||||
}
|
||||
|
||||
static int microcode_sanity_check(void *mc, int print_err)
|
||||
|
|
Loading…
Reference in New Issue