2012-08-18 08:29:58

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 00/11] x86/microcode: Early load microcode

From: Fenghua Yu <[email protected]>

The problem in current microcode loading method is that we load a microcode way,
way too late; ideally we should load it before turning paging on. This may only
be practical on 32 bits since we can't get to 64-bit mode without paging on,
but we should still do it as early as at all possible.

Similarly, we should load the microcode update as early as possible during AP
bringup and when processors are brought back online after hotplug or S3/S4.

In order to do that, the microcode patch needs to be permanently present in
kernel memory. Each individual patch is fairly small, so that is OK, but the
entire blob with support for each CPU is too big. Since only CPU's with same
model can be in the same platform, we store microcode with the same model as
BSP. Later on AP's can upload microcode from the saved microcodep patches.

Note, however, that Linux users have gotten used to being able to install a
microcode patch in the field without having a reboot; we support that model too.

Fenghua Yu (11):
Documentation/x86: Early load microcode
x86/lib/cpio.c: Find cpio data by its file name
x86/microcode_intel.h: Define functions and macros for early load
ucode
x86/microcode_core_early.c: Define interfaces for early load ucode
x86/microcode_intel_lib.c: Early update ucode on Intel's CPU
x86/microcode_intel_early.c: Early update ucode on Intel's CPU
x86/head_32.S: Early update ucode in 32-bit
x86/head64.c: Early update ucode in 64-bit
x86/smpboot.c: Early update ucode on AP
x86/mm/init.c: Copy ucode from initrd image to memory
x86/Kconfig: Configurations to enable/disable the feature

Documentation/x86/earlyucode.txt | 43 +++
arch/x86/Kconfig | 22 ++
arch/x86/include/asm/cpio.h | 10 +
arch/x86/include/asm/microcode.h | 23 ++
arch/x86/include/asm/microcode_intel.h | 103 +++++++
arch/x86/kernel/Makefile | 3 +
arch/x86/kernel/head64.c | 6 +
arch/x86/kernel/head_32.S | 6 +
arch/x86/kernel/microcode_core.c | 7 +-
arch/x86/kernel/microcode_core_early.c | 74 +++++
arch/x86/kernel/microcode_intel.c | 185 +------------
arch/x86/kernel/microcode_intel_early.c | 482 +++++++++++++++++++++++++++++++
arch/x86/kernel/microcode_intel_lib.c | 163 +++++++++++
arch/x86/kernel/smpboot.c | 7 +
arch/x86/lib/Makefile | 2 +
arch/x86/lib/cpio.c | 179 ++++++++++++
arch/x86/mm/init.c | 10 +
17 files changed, 1144 insertions(+), 181 deletions(-)
create mode 100644 Documentation/x86/earlyucode.txt
create mode 100644 arch/x86/include/asm/cpio.h
create mode 100644 arch/x86/include/asm/microcode_intel.h
create mode 100644 arch/x86/kernel/microcode_core_early.c
create mode 100644 arch/x86/kernel/microcode_intel_early.c
create mode 100644 arch/x86/kernel/microcode_intel_lib.c
create mode 100644 arch/x86/lib/cpio.c

--
1.7.2


2012-08-18 08:31:36

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 03/11] x86/microcode_intel.h: Define functions and macros for early load ucode

From: Fenghua Yu <[email protected]>

Define some functions and macros that will be used in early load ucode. Some of
them are moved from microcode_intel.c driver in order to be called in early
boot phase before module can be called.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/include/asm/microcode_intel.h | 103 ++++++++++++++++++
arch/x86/kernel/Makefile | 3 +
arch/x86/kernel/microcode_core.c | 7 +-
arch/x86/kernel/microcode_intel.c | 185 ++------------------------------
4 files changed, 117 insertions(+), 181 deletions(-)
create mode 100644 arch/x86/include/asm/microcode_intel.h

diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h
new file mode 100644
index 0000000..392d893
--- /dev/null
+++ b/arch/x86/include/asm/microcode_intel.h
@@ -0,0 +1,103 @@
+#ifndef _ASM_X86_MICROCODE_INTEL_H
+#define _ASM_X86_MICROCODE_INTEL_H
+
+#include <asm/microcode.h>
+
+struct microcode_header_intel {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode_intel {
+ struct microcode_header_intel hdr;
+ unsigned int bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
+};
+
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE (2000)
+#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
+#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.totalsize ? \
+ ((struct microcode_intel *)mc)->hdr.totalsize : \
+ DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+ (((struct microcode_intel *)mc)->hdr.datasize ? \
+ ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+ (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+extern int
+get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev);
+extern int microcode_sanity_check(void *mc, int print_err);
+
+#ifdef CONFIG_MICROCODE_INTEL_EARLY
+extern enum ucode_state
+get_matching_model_microcode(int cpu, void *data, size_t size,
+ struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd,
+ enum system_states system_state);
+extern enum ucode_state
+generic_load_microcode_early(int cpu, struct microcode_intel **mc_saved_p,
+ unsigned int mc_saved_count,
+ struct ucode_cpu_info *uci);
+extern void __init
+load_ucode_intel_bsp(char *real_mode_data);
+extern void __init load_ucode_intel_ap(void);
+#else
+static inline enum ucode_state
+get_matching_model_microcode(int cpu, void *data, size_t size,
+ struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd,
+ enum system_states system_state)
+{
+ return UCODE_ERROR;
+}
+enum ucode_state
+generic_load_microcode_early(int cpu, struct microcode_intel **mc_saved_p,
+ unsigned int mc_saved_count,
+ struct ucode_cpu_info *uci)
+{
+ return UCODE_ERROR;
+}
+void __init
+load_ucode_intel_bsp(char *real_mode_data)
+{
+}
+__init void
+load_ucode_intel_ap(struct ucode_cpu_info *uci,
+ struct mc_saved_data *mc_saved_data)
+{
+}
+#endif
+
+#endif /* _ASM_X86_MICROCODE_INTEL_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 8215e56..cd67adf 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -89,6 +89,9 @@ obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o

obj-$(CONFIG_PCSPKR_PLATFORM) += pcspeaker.o

+obj-$(CONFIG_MICROCODE_EARLY) += microcode_core_early.o
+obj-$(CONFIG_MICROCODE_INTEL_EARLY) += microcode_intel_early.o
+obj-$(CONFIG_MICROCODE_INTEL_LIB) += microcode_intel_lib.o
microcode-y := microcode_core.o
microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index 4873e62..a14b2ff 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -362,10 +362,7 @@ static struct attribute_group mc_attr_group = {

static void microcode_fini_cpu(int cpu)
{
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
microcode_ops->microcode_fini_cpu(cpu);
- uci->valid = 0;
}

static enum ucode_state microcode_resume_cpu(int cpu)
@@ -384,6 +381,10 @@ static enum ucode_state microcode_resume_cpu(int cpu)
static enum ucode_state microcode_init_cpu(int cpu)
{
enum ucode_state ustate;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (uci && uci->valid)
+ return UCODE_OK;

if (collect_cpu_info(cpu))
return UCODE_ERROR;
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 0327e2b..f8c7c97 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -79,7 +79,7 @@
#include <linux/module.h>
#include <linux/vmalloc.h>

-#include <asm/microcode.h>
+#include <asm/microcode_intel.h>
#include <asm/processor.h>
#include <asm/msr.h>

@@ -87,59 +87,6 @@ MODULE_DESCRIPTION("Microcode Update Driver");
MODULE_AUTHOR("Tigran Aivazian <[email protected]>");
MODULE_LICENSE("GPL");

-struct microcode_header_intel {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int datasize;
- unsigned int totalsize;
- unsigned int reserved[3];
-};
-
-struct microcode_intel {
- struct microcode_header_intel hdr;
- unsigned int bits[0];
-};
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
- unsigned int sig;
- unsigned int pf;
- unsigned int cksum;
-};
-
-struct extended_sigtable {
- unsigned int count;
- unsigned int cksum;
- unsigned int reserved[3];
- struct extended_signature sigs[0];
-};
-
-#define DEFAULT_UCODE_DATASIZE (2000)
-#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
-#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.totalsize ? \
- ((struct microcode_intel *)mc)->hdr.totalsize : \
- DEFAULT_UCODE_TOTALSIZE)
-
-#define get_datasize(mc) \
- (((struct microcode_intel *)mc)->hdr.datasize ? \
- ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
- (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
{
struct cpuinfo_x86 *c = &cpu_data(cpu_num);
@@ -162,128 +109,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
return 0;
}

-static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
-{
- return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
-}
-
-static inline int
-update_match_revision(struct microcode_header_intel *mc_header, int rev)
-{
- return (mc_header->rev <= rev) ? 0 : 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
- unsigned long total_size, data_size, ext_table_size;
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header = NULL;
- int sum, orig_sum, ext_sigcount = 0, i;
- struct extended_signature *ext_sig;
-
- total_size = get_totalsize(mc_header);
- data_size = get_datasize(mc_header);
-
- if (data_size + MC_HEADER_SIZE > total_size) {
- pr_err("error! Bad data size in microcode data file\n");
- return -EINVAL;
- }
-
- if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
- pr_err("error! Unknown microcode update format\n");
- return -EINVAL;
- }
- ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
- if (ext_table_size) {
- if ((ext_table_size < EXT_HEADER_SIZE)
- || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
- pr_err("error! Small exttable size in microcode data file\n");
- return -EINVAL;
- }
- ext_header = mc + MC_HEADER_SIZE + data_size;
- if (ext_table_size != exttable_size(ext_header)) {
- pr_err("error! Bad exttable size in microcode data file\n");
- return -EFAULT;
- }
- ext_sigcount = ext_header->count;
- }
-
- /* check extended table checksum */
- if (ext_table_size) {
- int ext_table_sum = 0;
- int *ext_tablep = (int *)ext_header;
-
- i = ext_table_size / DWSIZE;
- while (i--)
- ext_table_sum += ext_tablep[i];
- if (ext_table_sum) {
- pr_warning("aborting, bad extended signature table checksum\n");
- return -EINVAL;
- }
- }
-
- /* calculate the checksum */
- orig_sum = 0;
- i = (MC_HEADER_SIZE + data_size) / DWSIZE;
- while (i--)
- orig_sum += ((int *)mc)[i];
- if (orig_sum) {
- pr_err("aborting, bad checksum\n");
- return -EINVAL;
- }
- if (!ext_table_size)
- return 0;
- /* check extended signature checksum */
- for (i = 0; i < ext_sigcount; i++) {
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
- EXT_SIGNATURE_SIZE * i;
- sum = orig_sum
- - (mc_header->sig + mc_header->pf + mc_header->cksum)
- + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
- if (sum) {
- pr_err("aborting, bad checksum\n");
- return -EINVAL;
- }
- }
- return 0;
-}
-
-/*
- * return 0 - no update found
- * return 1 - found update
- */
-static int
-get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
-{
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header;
- unsigned long total_size = get_totalsize(mc_header);
- int ext_sigcount, i;
- struct extended_signature *ext_sig;
-
- if (!update_match_revision(mc_header, rev))
- return 0;
-
- if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
- return 1;
-
- /* Look for ext. headers: */
- if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
- return 0;
-
- ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
- ext_sigcount = ext_header->count;
- ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
-
- for (i = 0; i < ext_sigcount; i++) {
- if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
- return 1;
- ext_sig++;
- }
- return 0;
-}
-
-static int apply_microcode(int cpu)
+int apply_microcode(int cpu)
{
struct microcode_intel *mc_intel;
struct ucode_cpu_info *uci;
@@ -338,6 +164,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
unsigned int leftover = size;
enum ucode_state state = UCODE_OK;
unsigned int curr_mc_size = 0;
+ unsigned int csig, cpf;

while (leftover) {
struct microcode_header_intel mc_header;
@@ -362,11 +189,13 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
}

if (get_ucode_data(mc, ucode_ptr, mc_size) ||
- microcode_sanity_check(mc) < 0) {
+ microcode_sanity_check(mc, 1) < 0) {
break;
}

- if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+ csig = uci->cpu_sig.sig;
+ cpf = uci->cpu_sig.pf;
+ if (get_matching_microcode(csig, cpf, mc, new_rev)) {
vfree(new_mc);
new_rev = mc_header.rev;
new_mc = mc;
--
1.7.2

2012-08-18 08:31:38

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 09/11] x86/smpboot.c: Early update ucode on AP

From: Fenghua Yu <[email protected]>

This updates ucode on AP. At this point, BSP should store some valid ucode
patches in memory if it finds the ucode patches in initrd. AP searches the
stored ucode and uploads the ucode.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/kernel/smpboot.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 7c5a8c3..c72e230 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -76,6 +76,7 @@
#include <asm/i8259.h>

#include <asm/realmode.h>
+#include <asm/microcode.h>

/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };
@@ -239,6 +240,12 @@ notrace static void __cpuinit start_secondary(void *unused)
* most necessary things.
*/
cpu_init();
+ /*
+ * Load microcode on this cpu if a valid microcode is available.
+ * This is early microcode loading procedure.
+ */
+ load_ucode_ap();
+
x86_cpuinit.early_percpu_clock_init();
preempt_disable();
smp_callin();
--
1.7.2

2012-08-18 08:31:46

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 08/11] x86/head64.c: Early update ucode in 64-bit

From: Fenghua Yu <[email protected]>

This updates ucode in 64-bit mode. Paging and virtual address are working now.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/kernel/head64.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 037df57..a512f56 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -25,6 +25,7 @@
#include <asm/kdebug.h>
#include <asm/e820.h>
#include <asm/bios_ebda.h>
+#include <asm/microcode.h>

static void __init zap_identity_mappings(void)
{
@@ -73,6 +74,11 @@ void __init x86_64_start_kernel(char * real_mode_data)
/* clear bss before set_intr_gate with early_idt_handler */
clear_bss();

+ /*
+ * Load microcode early on BSP.
+ */
+ load_ucode_bsp(real_mode_data);
+
/* Make NULL pointers segfault */
zap_identity_mappings();

--
1.7.2

2012-08-18 08:31:52

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 10/11] x86/mm/init.c: Copy ucode from initrd image to memory

From: Fenghua Yu <[email protected]>

Before initrd image is freed, copy valid ucode patches from initrd image
to kernel virtual memory. The saved ucode will be used to update AP in resume.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/mm/init.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index e0e6990..58ceb82 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -16,6 +16,7 @@
#include <asm/tlb.h>
#include <asm/proto.h>
#include <asm/dma.h> /* for MAX_DMA_PFN */
+#include <asm/microcode.h>

unsigned long __initdata pgt_buf_start;
unsigned long __meminitdata pgt_buf_end;
@@ -387,6 +388,15 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
+#ifdef CONFIG_MICROCODE_EARLY
+ /*
+ * Remember, initrd memory may contain microcode or other useful things.
+ * Before we lose initrd mem, we need to find a place to hold them
+ * now that normal virtual memory is enabled.
+ */
+ save_microcode_in_initrd(&mc_saved_data, mc_saved_in_initrd);
+#endif
+
/*
* end could be not aligned, and We can not align that,
* decompresser could be confused by aligned initrd_end
--
1.7.2

2012-08-18 08:32:15

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 11/11] x86/Kconfig: Configurations to enable/disable the feature

From: Fenghua Yu <[email protected]>

MICROCODE_INTEL_LIB, MICROCODE_INTEL_EARLY, and MICROCODE_EARLY are three new
configurations to enable or disable the feature.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/Kconfig | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 50c660d..32caa77 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1035,6 +1035,7 @@ config MICROCODE_INTEL
depends on MICROCODE
default MICROCODE
select FW_LOADER
+ select MICROCODE_INTEL_LIB
---help---
This options enables microcode patch loading support for Intel
processors.
@@ -1055,6 +1056,27 @@ config MICROCODE_OLD_INTERFACE
def_bool y
depends on MICROCODE

+config MICROCODE_EARLY
+ def_bool y
+ depends on MICROCODE_INTEL_EARLY
+
+config MICROCODE_INTEL_LIB
+ def_bool y
+ depends on MICROCODE_INTEL_EARLY
+
+config MICROCODE_INTEL_EARLY
+ bool "Early load microcode"
+ depends on MICROCODE_INTEL && BLK_DEV_INITRD
+ default y
+ select FW_LOADER
+ select MICROCODE_EARLY
+ select MICROCODE_INTEL_LIB
+ help
+ This option provides functionality to read additional microcode data
+ at the beginning of initrd image. The data tells kernel to load
+ microcode to CPU's as early as possible. No functional change if no
+ microcode data is glued to the initrd, therefore it's safe to say Y.
+
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
---help---
--
1.7.2

2012-08-18 08:32:01

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file name

From: Fenghua Yu <[email protected]>

Given a file's name, find its starting point in a cpio formated area. This will
be used to find microcode in combined initrd image. But this function is
generic and could be used in other places.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/include/asm/cpio.h | 10 +++
arch/x86/lib/Makefile | 2 +
arch/x86/lib/cpio.c | 179 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 191 insertions(+), 0 deletions(-)
create mode 100644 arch/x86/include/asm/cpio.h
create mode 100644 arch/x86/lib/cpio.c

diff --git a/arch/x86/include/asm/cpio.h b/arch/x86/include/asm/cpio.h
new file mode 100644
index 0000000..26a4333
--- /dev/null
+++ b/arch/x86/include/asm/cpio.h
@@ -0,0 +1,10 @@
+#include <stddef.h>
+#include <stdbool.h>
+
+struct cpio_data {
+ void *data;
+ unsigned long size;
+};
+
+extern struct cpio_data
+find_cpio_data(const char *name, const void *data, size_t len);
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index b00f678..452a4b5 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -45,3 +45,5 @@ else
lib-y += copy_user_64.o copy_user_nocache_64.o
lib-y += cmpxchg16b_emu.o
endif
+
+obj-y += cpio.o
diff --git a/arch/x86/lib/cpio.c b/arch/x86/lib/cpio.c
new file mode 100644
index 0000000..70ac474
--- /dev/null
+++ b/arch/x86/lib/cpio.c
@@ -0,0 +1,179 @@
+/*
+ * findcpio.c
+ *
+ * Find a specific cpio member; must precede any compressed content.
+ *
+ * Copyright (C) 2012 H Peter Anvin" <[email protected]>
+ * Fenghua Yu <[email protected]>
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+#include <linux/bitmap.h>
+#include <linux/signal.h>
+#include <linux/printk.h>
+#include <linux/proc_fs.h>
+#include <linux/security.h>
+#include <linux/ctype.h>
+#include <linux/kmemcheck.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/net.h>
+#include <linux/sysrq.h>
+#include <linux/highuid.h>
+#include <linux/writeback.h>
+#include <linux/ratelimit.h>
+#include <linux/compaction.h>
+#include <linux/hugetlb.h>
+#include <linux/initrd.h>
+#include <linux/key.h>
+#include <linux/times.h>
+#include <linux/limits.h>
+#include <linux/dcache.h>
+#include <linux/dnotify.h>
+#include <linux/syscalls.h>
+#include <asm/cpio.h>
+
+enum cpio_fields {
+ C_MAGIC,
+ C_INO,
+ C_MODE,
+ C_UID,
+ C_GID,
+ C_NLINK,
+ C_MTIME,
+ C_FILESIZE,
+ C_MAJ,
+ C_MIN,
+ C_RMAJ,
+ C_RMIN,
+ C_NAMESIZE,
+ C_CHKSUM,
+ C_NFIELDS
+};
+
+#if defined(__i386__) || defined(__x86_64__)
+static size_t cpio_strlen(const char *name)
+{
+ size_t n = -1;
+
+ asm("repne; scasb"
+ : "+D" (name), "+c" (n)
+ : "a" (0));
+
+ return -2 - n;
+}
+
+static int cpio_memcmp(const void *p1, const void *p2, size_t n)
+{
+ unsigned char rv;
+
+ asm("repe; cmpsb; setne %0"
+ : "=r" (rv), "+S" (p1), "+D" (p2), "+c" (n));
+
+ return rv;
+}
+#else
+static size_t cpio_strlen(const char *name)
+{
+ size_t n = 0;
+
+ while (*name++)
+ n++;
+
+ return n;
+}
+
+static int cpio_memcmp(const void *p1, const void *p2, size_t n)
+{
+ const unsigned char *u1 = p1;
+ const unsigned char *u2 = p2;
+ int d;
+
+ while (n--) {
+ d = *u2++ - *u1++;
+ if (d)
+ return d;
+ }
+ return 0;
+}
+#endif
+
+#define ALIGN4(p) ((void *)(((size_t)p + 3) & ~3))
+
+struct cpio_data find_cpio_data(const char *name, const void *data, size_t len)
+{
+ const size_t cpio_header_len = 8*C_NFIELDS - 2;
+ struct cpio_data cd = { NULL, 0 };
+ const char *p, *dptr, *nptr;
+ unsigned int ch[C_NFIELDS], *chp, v;
+ unsigned char c, x;
+ size_t mynamesize = cpio_strlen(name) + 1;
+ int i, j;
+
+ p = data;
+
+ while (len > cpio_header_len) {
+ if (!*p) {
+ /* All cpio headers need to be 4-byte aligned */
+ p += 4;
+ len -= 4;
+ continue;
+ }
+
+ j = 6; /* The magic field is only 6 characters */
+ chp = ch;
+ for (i = C_NFIELDS; i; i--) {
+ v = 0;
+ while (j--) {
+ v <<= 4;
+ c = *p++;
+
+ x = c - '0';
+ if (x < 10) {
+ v += x;
+ continue;
+ }
+
+ x = (c | 0x20) - 'a';
+ if (x < 6) {
+ v += x + 10;
+ continue;
+ }
+
+ goto quit; /* Invalid hexadecimal */
+ }
+ *chp++ = v;
+ j = 8; /* All other fields are 8 characters */
+ }
+
+ if ((ch[C_MAGIC] - 0x070701) > 1)
+ goto quit; /* Invalid magic */
+
+ len -= cpio_header_len;
+
+ dptr = ALIGN4(p + ch[C_NAMESIZE]);
+ nptr = ALIGN4(dptr + ch[C_FILESIZE]);
+
+ if (nptr > p + len || dptr < p || nptr < dptr)
+ goto quit; /* Buffer overrun */
+
+ if ((ch[C_MODE] & 0170000) == 0100000 &&
+ ch[C_NAMESIZE] == mynamesize &&
+ !cpio_memcmp(p, name, mynamesize)) {
+ cd.data = (void *)dptr;
+ cd.size = ch[C_FILESIZE];
+ return cd; /* Found it! */
+ }
+
+ len -= (nptr - p);
+ p = nptr;
+ }
+
+quit:
+ return cd;
+}
--
1.7.2

2012-08-18 08:31:57

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 01/11] Documentation/x86: Early load microcode

From: Fenghua Yu <[email protected]>

Documenation for early load microcode methodology.

Signed-off-by: Fenghua Yu <[email protected]>
---
Documentation/x86/earlyucode.txt | 43 ++++++++++++++++++++++++++++++++++++++
1 files changed, 43 insertions(+), 0 deletions(-)
create mode 100644 Documentation/x86/earlyucode.txt

diff --git a/Documentation/x86/earlyucode.txt b/Documentation/x86/earlyucode.txt
new file mode 100644
index 0000000..d8966d6
--- /dev/null
+++ b/Documentation/x86/earlyucode.txt
@@ -0,0 +1,43 @@
+Early load microcode
+====================
+By Fenghua Yu <[email protected]>
+
+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 initrd file. The microcode is read from the initrd file
+and loaded to CPU's during boot time.
+
+The format of the combined initrd image is microcode in cpio format followed by
+initrd image (maybe compressed). Kernel parses the combined initrd image during
+boot time. The microcode file in cpio name space is:
+kernel/x86/microcode/GenuineIntel/microcode.hex
+
+During BSP boot (before SMP starts), if 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
+AP's.
+
+The saved microcode in memory will be used to upload micorcode when system
+resumes from sleep.
+
+In the past, user can issue command to load microcode during run time. There are
+two user space interfaces to load microcode, either through /dev/cpu/microcode
+interface or through reload file in sysfs.
+
+Now user can choose any of the three methods to update microcode during boot
+time or later during run time.
+
+The following sample script shows how to generate a new combined initrd file in
+/boot/initrd-3.5.0.ucode.img with original microcode microcode.hex and
+original initrd image /boot/initrd-3.5.0.img.
+
+mkdir initrd
+cd initrd
+cp ../microcode.hex kernel/x86/microcode/GenuineIntel/microcode.hex
+find .|cpio -oc >../ucode.cpio
+cd ..
+cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img
+
+The generated /boot/initrd-3.5.0.ucode.img can be used as initrd file to load
+microcode during early boot time.
--
1.7.2

2012-08-18 08:31:33

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 06/11] x86/microcode_intel_early.c: Early update ucode on Intel's CPU

From: Fenghua Yu <[email protected]>

Implementation of early update ucode on Intel's CPU.

load_ucode_intel_bsp() scans ucode in initrd image file which is a cpio format
ucode followed by ordinary initrd image file. The binary ucode file is stored
in kernel/x86/microcode/GenuineIntel/microcode.hex in the cpio data. All ucode
patches with the same model as BSP are saved in memory. A matching ucode patch
is updated on BSP.

load_ucode_intel_ap() reads saved ucoded patches and updates ucode on AP.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/kernel/microcode_intel_early.c | 482 +++++++++++++++++++++++++++++++
1 files changed, 482 insertions(+), 0 deletions(-)
create mode 100644 arch/x86/kernel/microcode_intel_early.c

diff --git a/arch/x86/kernel/microcode_intel_early.c b/arch/x86/kernel/microcode_intel_early.c
new file mode 100644
index 0000000..cb3f066
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel_early.c
@@ -0,0 +1,482 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2012 Fenghua Yu <[email protected]>
+ * H Peter Anvin" <[email protected]>
+ *
+ * This driver allows to early upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture
+ * Software Developer's Manual.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <asm/msr.h>
+#include <asm/microcode_intel.h>
+#include <asm/processor.h>
+#include <asm/cpio.h>
+
+struct microcode_intel __initdata *mc_saved_in_initrd[MAX_UCODE_COUNT];
+struct mc_saved_data mc_saved_data;
+
+static inline int
+update_match_cpu(unsigned int csig, unsigned int cpf,
+ unsigned int sig, unsigned int pf)
+{
+ return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1;
+}
+
+static inline int
+update_match_revision(struct microcode_header_intel *mc_header, int rev)
+{
+ return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+static int
+get_matching_sig(unsigned int csig, int cpf, void *mc, int rev)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+
+ if (update_match_cpu(csig, cpf, mc_header->sig, mc_header->pf))
+ return 1;
+
+ /* Look for ext. headers: */
+ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ return 0;
+
+ ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (i = 0; i < ext_sigcount; i++) {
+ if (update_match_cpu(csig, cpf, ext_sig->sig, ext_sig->pf))
+ return 1;
+ ext_sig++;
+ }
+ return 0;
+}
+
+enum ucode_state
+generic_load_microcode_early(int cpu, struct microcode_intel **mc_saved_p,
+ unsigned int mc_saved_count,
+ struct ucode_cpu_info *uci)
+{
+ struct microcode_intel *ucode_ptr, *new_mc = NULL;
+ int new_rev = uci->cpu_sig.rev;
+ enum ucode_state state = UCODE_OK;
+ unsigned int mc_size;
+ struct microcode_header_intel *mc_header;
+ unsigned int csig = uci->cpu_sig.sig;
+ unsigned int cpf = uci->cpu_sig.pf;
+ int i;
+
+ for (i = 0; i < mc_saved_count; i++) {
+ ucode_ptr = mc_saved_p[i];
+ mc_header = (struct microcode_header_intel *)ucode_ptr;
+ mc_size = get_totalsize(mc_header);
+ if (get_matching_microcode(csig, cpf, ucode_ptr, new_rev)) {
+ new_rev = mc_header->rev;
+ new_mc = ucode_ptr;
+ }
+ }
+
+ if (!new_mc) {
+ state = UCODE_NFOUND;
+ goto out;
+ }
+
+ uci->mc = (struct microcode_intel *)new_mc;
+out:
+ return state;
+}
+EXPORT_SYMBOL_GPL(generic_load_microcode_early);
+
+static enum ucode_state __init
+load_microcode(struct mc_saved_data *mc_saved_data, int cpu)
+{
+ struct ucode_cpu_info *uci = mc_saved_data->ucode_cpu_info + cpu;
+
+ return generic_load_microcode_early(cpu, mc_saved_data->mc_saved,
+ mc_saved_data->mc_saved_count, uci);
+}
+
+static u8 get_x86_family(unsigned long sig)
+{
+ u8 x86;
+
+ x86 = (sig >> 8) & 0xf;
+
+ if (x86 == 0xf)
+ x86 += (sig >> 20) & 0xff;
+
+ return x86;
+}
+
+static u8 get_x86_model(unsigned long sig)
+{
+ u8 x86, x86_model;
+
+ x86 = get_x86_family(sig);
+ x86_model = (sig >> 4) & 0xf;
+
+ if (x86 == 0x6 || x86 == 0xf)
+ x86_model += ((sig >> 16) & 0xf) << 4;
+
+ return x86_model;
+}
+
+static enum ucode_state
+matching_model_microcode(struct microcode_header_intel *mc_header,
+ unsigned long sig)
+{
+ u8 x86, x86_model;
+ u8 x86_ucode, x86_model_ucode;
+
+ x86 = get_x86_family(sig);
+ x86_model = get_x86_model(sig);
+
+ x86_ucode = get_x86_family(mc_header->sig);
+ x86_model_ucode = get_x86_model(mc_header->sig);
+
+ if (x86 != x86_ucode || x86_model != x86_model_ucode)
+ return UCODE_ERROR;
+
+ return UCODE_OK;
+}
+
+static void
+save_microcode(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_src,
+ unsigned int mc_saved_count)
+{
+ int i;
+ struct microcode_intel **mc_saved_p;
+
+ if (!mc_saved_count)
+ return;
+
+ mc_saved_p = vmalloc(mc_saved_count*sizeof(struct microcode_intel *));
+ if (!mc_saved_p)
+ return;
+
+ for (i = 0; i < mc_saved_count; i++) {
+ struct microcode_intel *mc = mc_saved_src[i];
+ struct microcode_header_intel *mc_header = &mc->hdr;
+ unsigned long mc_size = get_totalsize(mc_header);
+ mc_saved_p[i] = vmalloc(mc_size);
+ if (mc_saved_src[i])
+ memcpy(mc_saved_p[i], mc, mc_size);
+ }
+
+ mc_saved_data->mc_saved = mc_saved_p;
+}
+
+/*
+ * Get microcode matching with BSP's model. Only CPU's with the same model as
+ * BSP can stay in the platform.
+ */
+enum ucode_state
+get_matching_model_microcode(int cpu, void *data, size_t size,
+ struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd,
+ enum system_states system_state)
+{
+ u8 *ucode_ptr = data;
+ unsigned int leftover = size;
+ enum ucode_state state = UCODE_OK;
+ unsigned int mc_size;
+ struct microcode_header_intel *mc_header;
+ struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT];
+ size_t mc_saved_size;
+ size_t mem_size;
+ unsigned int mc_saved_count = mc_saved_data->mc_saved_count;
+ struct ucode_cpu_info *uci = mc_saved_data->ucode_cpu_info + cpu;
+ int found = 0;
+ int i;
+
+ if (mc_saved_count) {
+ mem_size = mc_saved_count * sizeof(struct microcode_intel *);
+ memcpy(mc_saved_tmp, mc_saved_data->mc_saved, mem_size);
+ }
+
+ while (leftover) {
+ mc_header = (struct microcode_header_intel *)ucode_ptr;
+
+ mc_size = get_totalsize(mc_header);
+ if (!mc_size || mc_size > leftover ||
+ microcode_sanity_check(ucode_ptr, 0) < 0)
+ break;
+
+ leftover -= mc_size;
+ if (matching_model_microcode(mc_header, uci->cpu_sig.sig) !=
+ UCODE_OK) {
+ ucode_ptr += mc_size;
+ continue;
+ }
+
+ found = 0;
+ for (i = 0; i < mc_saved_count; i++) {
+ unsigned int sig, pf;
+ unsigned int new_rev;
+ struct microcode_header_intel *mc_saved_header =
+ (struct microcode_header_intel *)mc_saved_tmp[i];
+ sig = mc_saved_header->sig;
+ pf = mc_saved_header->pf;
+ new_rev = mc_header->rev;
+
+ if (get_matching_sig(sig, pf, ucode_ptr, new_rev)) {
+ found = 1;
+ if (update_match_revision(mc_header, new_rev)) {
+ /*
+ * Found an older ucode saved before.
+ * Replace the older one with this newer
+ * one.
+ */
+ mc_saved_tmp[i] =
+ (struct microcode_intel *)ucode_ptr;
+ break;
+ }
+ }
+ }
+ if (i >= mc_saved_count && !found)
+ /*
+ * This ucode is first time discovered in ucode file.
+ * Save it to memory.
+ */
+ mc_saved_tmp[mc_saved_count++] =
+ (struct microcode_intel *)ucode_ptr;
+
+ ucode_ptr += mc_size;
+ }
+
+ if (leftover) {
+ state = UCODE_ERROR;
+ goto out;
+ }
+
+ if (mc_saved_count == 0) {
+ state = UCODE_NFOUND;
+ goto out;
+ }
+
+ if (system_state == SYSTEM_RUNNING) {
+ vfree(mc_saved_data->mc_saved);
+ save_microcode(mc_saved_data, mc_saved_tmp, mc_saved_count);
+ } else {
+ mc_saved_size = sizeof(struct microcode_intel *) *
+ mc_saved_count;
+ memcpy(mc_saved_in_initrd, mc_saved_tmp, mc_saved_size);
+ mc_saved_data->mc_saved = mc_saved_in_initrd;
+ }
+
+ mc_saved_data->mc_saved_count = mc_saved_count;
+out:
+ return state;
+}
+EXPORT_SYMBOL_GPL(get_matching_model_microcode);
+
+#define native_rdmsr(msr, val1, val2) \
+do { \
+ u64 __val = native_read_msr((msr)); \
+ (void)((val1) = (u32)__val); \
+ (void)((val2) = (u32)(__val >> 32)); \
+} while (0)
+
+#define native_wrmsr(msr, low, high) \
+ native_write_msr(msr, low, high);
+
+static int __cpuinit collect_cpu_info_early(struct ucode_cpu_info *uci)
+{
+ unsigned int val[2];
+ u8 x86, x86_model;
+ struct cpu_signature csig = {0, 0, 0};
+ unsigned int eax, ebx, ecx, edx;
+
+ memset(uci, 0, sizeof(*uci));
+
+ eax = 0x00000001;
+ ecx = 0;
+ native_cpuid(&eax, &ebx, &ecx, &edx);
+ csig.sig = eax;
+
+ x86 = get_x86_family(csig.sig);
+ x86_model = get_x86_model(csig.sig);
+
+ if ((x86_model >= 5) || (x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+ csig.pf = 1 << ((val[1] >> 18) & 7);
+ }
+
+ /* get the current revision from MSR 0x8B */
+ native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+ csig.rev = val[1];
+
+ uci->cpu_sig = csig;
+ uci->valid = 1;
+
+ return 0;
+}
+
+static __init enum ucode_state
+scan_microcode(unsigned long start, unsigned long end,
+ struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd)
+{
+ unsigned int size = end - start + 1;
+ struct cpio_data cd = { 0, 0 };
+ char ucode_name[] = "kernel/x86/microcode/GenuineIntel/microcode.hex";
+
+ cd = find_cpio_data(ucode_name, (void *)start, size);
+ if (!cd.data)
+ return UCODE_ERROR;
+
+ return get_matching_model_microcode(0, cd.data, cd.size, mc_saved_data,
+ mc_saved_in_initrd, SYSTEM_BOOTING);
+}
+
+static int __init
+apply_microcode_early(struct mc_saved_data *mc_saved_data, int cpu)
+{
+ struct ucode_cpu_info *uci = mc_saved_data->ucode_cpu_info + cpu;
+ struct microcode_intel *mc_intel;
+ unsigned int val[2];
+
+ /* We should bind the task to the CPU */
+ mc_intel = uci->mc;
+ if (mc_intel == NULL)
+ return 0;
+
+ /* write microcode via MSR 0x79 */
+ native_wrmsr(MSR_IA32_UCODE_WRITE,
+ (unsigned long) mc_intel->bits,
+ (unsigned long) mc_intel->bits >> 16 >> 16);
+ native_wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+ /* As documented in the SDM: Do a CPUID 1 here */
+ sync_core();
+
+ /* get the current revision from MSR 0x8B */
+ native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+ if (val[1] != mc_intel->hdr.rev)
+ return -1;
+
+ uci->cpu_sig.rev = val[1];
+
+ return 0;
+}
+
+#ifdef CONFIG_X86_32
+static void __init map_mc_saved(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd)
+{
+ int i;
+
+ if (mc_saved_data->mc_saved) {
+ for (i = 0; i < mc_saved_data->mc_saved_count; i++)
+ mc_saved_data->mc_saved[i] =
+ __va(mc_saved_data->mc_saved[i]);
+
+ mc_saved_data->mc_saved = __va(mc_saved_data->mc_saved);
+ }
+
+ if (mc_saved_data->ucode_cpu_info->mc)
+ mc_saved_data->ucode_cpu_info->mc =
+ __va(mc_saved_data->ucode_cpu_info->mc);
+ mc_saved_data->ucode_cpu_info = __va(mc_saved_data->ucode_cpu_info);
+}
+#else
+static inline void __init map_mc_saved(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd)
+{
+}
+#endif
+
+void __init save_microcode_in_initrd(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd)
+{
+ unsigned int count = mc_saved_data->mc_saved_count;
+
+ save_microcode(mc_saved_data, mc_saved_in_initrd, count);
+}
+
+static void __init
+_load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd,
+ unsigned long initrd_start, unsigned long initrd_end)
+{
+ int cpu = 0;
+
+#ifdef CONFIG_X86_64
+ mc_saved_data->ucode_cpu_info = ucode_cpu_info_early;
+#else
+ mc_saved_data->ucode_cpu_info =
+ (struct ucode_cpu_info *)__pa(ucode_cpu_info_early);
+#endif
+ collect_cpu_info_early(mc_saved_data->ucode_cpu_info + cpu);
+ scan_microcode(initrd_start, initrd_end, mc_saved_data,
+ mc_saved_in_initrd);
+ load_microcode(mc_saved_data, cpu);
+ apply_microcode_early(mc_saved_data, cpu);
+ map_mc_saved(mc_saved_data, mc_saved_in_initrd);
+}
+
+void __init
+load_ucode_intel_bsp(char *real_mode_data)
+{
+ u64 ramdisk_image, ramdisk_size, ramdisk_end;
+ unsigned long initrd_start, initrd_end;
+ struct boot_params *boot_params;
+
+ boot_params = (struct boot_params *)real_mode_data;
+ ramdisk_image = boot_params->hdr.ramdisk_image;
+ ramdisk_size = boot_params->hdr.ramdisk_size;
+
+#ifdef CONFIG_X86_64
+ ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
+ initrd_start = ramdisk_image + PAGE_OFFSET;
+ initrd_end = initrd_start + ramdisk_size;
+ _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd,
+ initrd_start, initrd_end);
+#else
+ ramdisk_end = ramdisk_image + ramdisk_size;
+ initrd_start = ramdisk_image;
+ initrd_end = initrd_start + ramdisk_size;
+ _load_ucode_intel_bsp((struct mc_saved_data *)__pa(&mc_saved_data),
+ (struct microcode_intel **)__pa(mc_saved_in_initrd),
+ initrd_start, initrd_end);
+#endif
+}
+
+void __cpuinit load_ucode_intel_ap(void)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * If BSP doesn't find valid ucode and save it in memory, no need to
+ * update ucode on this AP.
+ */
+ if (!mc_saved_data.mc_saved)
+ return;
+
+ collect_cpu_info_early(mc_saved_data.ucode_cpu_info + cpu);
+ load_microcode(&mc_saved_data, cpu);
+ apply_microcode_early(&mc_saved_data, cpu);
+}
--
1.7.2

2012-08-18 08:31:29

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 07/11] x86/head_32.S: Early update ucode in 32-bit

From: Fenghua Yu <[email protected]>

This updates ucode in 32-bit kernel. At this point, there is no paging and no
virtual address yet.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/kernel/head_32.S | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index d42ab17..bb0d1e5 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -144,6 +144,12 @@ ENTRY(startup_32)
movl %eax, pa(olpc_ofw_pgd)
#endif

+#ifdef CONFIG_MICROCODE_EARLY
+ /* Early load ucode on BSP. */
+ movl $pa(boot_params), %eax
+ call load_ucode_bsp
+#endif
+
/*
* Initialize page tables. This creates a PDE and a set of page
* tables, which are located immediately beyond __brk_base. The variable
--
1.7.2

2012-08-18 08:31:27

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

From: Fenghua Yu <[email protected]>

Define interfaces load_ucode_bsp() and load_ucode_ap() to load ucode on BSP and
AP in early boot time. These are generic interfaces. Internally they call
vendor specific implementations.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/include/asm/microcode.h | 23 ++++++++++
arch/x86/kernel/microcode_core_early.c | 74 ++++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+), 0 deletions(-)
create mode 100644 arch/x86/kernel/microcode_core_early.c

diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 4ebe157..080ea77 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -63,4 +63,27 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
static inline void __exit exit_amd_microcode(void) {}
#endif

+struct mc_saved_data {
+ unsigned int mc_saved_count;
+ struct microcode_intel **mc_saved;
+ struct ucode_cpu_info *ucode_cpu_info;
+};
+#ifdef CONFIG_MICROCODE_EARLY
+#define MAX_UCODE_COUNT 128
+extern struct ucode_cpu_info ucode_cpu_info_early[NR_CPUS];
+extern struct microcode_intel __initdata *mc_saved_in_initrd[MAX_UCODE_COUNT];
+extern struct mc_saved_data mc_saved_data;
+extern void __init load_ucode_bsp(char *real_mode_data);
+extern __init void load_ucode_ap(void);
+extern void __init
+save_microcode_in_initrd(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd);
+#else
+static inline void __init load_ucode_bsp(char *real_mode_data) {}
+static inline __init void load_ucode_ap(void) {}
+static inline void __init
+save_microcode_in_initrd(struct mc_saved_data *mc_saved_data,
+ struct microcode_intel **mc_saved_in_initrd) {}
+#endif
+
#endif /* _ASM_X86_MICROCODE_H */
diff --git a/arch/x86/kernel/microcode_core_early.c b/arch/x86/kernel/microcode_core_early.c
new file mode 100644
index 0000000..5bcc6f8
--- /dev/null
+++ b/arch/x86/kernel/microcode_core_early.c
@@ -0,0 +1,74 @@
+/*
+ * X86 CPU microcode early update for Linux
+ *
+ * Copyright (C) 2012 Fenghua Yu <[email protected]>
+ * H Peter Anvin" <[email protected]>
+ *
+ * This driver allows to early upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture
+ * Software Developer's Manual.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/microcode_intel.h>
+#include <asm/processor.h>
+#include <asm/cpio.h>
+
+struct ucode_cpu_info ucode_cpu_info_early[NR_CPUS];
+EXPORT_SYMBOL_GPL(ucode_cpu_info_early);
+
+static __init enum ucode_state
+find_ucode_intel(unsigned long start, unsigned long end)
+{
+ unsigned int size = end - start + 1;
+ struct cpio_data cd = { 0, 0 };
+ char ucode_name[] = "kernel/x86/microcode/GenuineIntel/microcode.hex";
+
+ cd = find_cpio_data(ucode_name, (void *)start, size);
+ if (cd.data)
+ return UCODE_OK;
+
+ return UCODE_ERROR;
+}
+
+void __init load_ucode_bsp(char *real_mode_data)
+{
+ u64 ramdisk_image, ramdisk_size, ramdisk_end;
+ unsigned long initrd_start, initrd_end;
+ struct boot_params *boot_params;
+
+ boot_params = (struct boot_params *)real_mode_data;
+ ramdisk_image = boot_params->hdr.ramdisk_image;
+ ramdisk_size = boot_params->hdr.ramdisk_size;
+
+#ifdef CONFIG_X86_64
+ ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
+ initrd_start = ramdisk_image + PAGE_OFFSET;
+#else
+ ramdisk_end = ramdisk_image + ramdisk_size;
+ initrd_start = ramdisk_image;
+#endif
+ initrd_end = initrd_start + ramdisk_size;
+
+ /*
+ * It's early to get CPU vendor info at this point.
+ * By searching initrd to find right name for vendor's microcode,
+ * it's relative easier to get CPU vendor info.
+ */
+ if (find_ucode_intel(initrd_start, initrd_end) == UCODE_OK)
+ load_ucode_intel_bsp(real_mode_data);
+}
+
+void __cpuinit load_ucode_ap(void)
+{
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ load_ucode_intel_ap();
+}
--
1.7.2

2012-08-18 08:31:24

by Fenghua Yu

[permalink] [raw]
Subject: [PATCH 05/11] x86/microcode_intel_lib.c: Early update ucode on Intel's CPU

From: Fenghua Yu <[email protected]>

Define interfaces microcode_sanity_check() and get_matching_microcode(). They
are called both in early boot time and in microcode Intel driver.

Signed-off-by: Fenghua Yu <[email protected]>
---
arch/x86/kernel/microcode_intel_lib.c | 163 +++++++++++++++++++++++++++++++++
1 files changed, 163 insertions(+), 0 deletions(-)
create mode 100644 arch/x86/kernel/microcode_intel_lib.c

diff --git a/arch/x86/kernel/microcode_intel_lib.c b/arch/x86/kernel/microcode_intel_lib.c
new file mode 100644
index 0000000..66550b3
--- /dev/null
+++ b/arch/x86/kernel/microcode_intel_lib.c
@@ -0,0 +1,163 @@
+/*
+ * Intel CPU Microcode Update Driver for Linux
+ *
+ * Copyright (C) 2012 Fenghua Yu <[email protected]>
+ * H Peter Anvin" <[email protected]>
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to IA-32 family - PentiumPro, Pentium II,
+ * Pentium III, Xeon, Pentium 4, etc.
+ *
+ * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ * Software Developer's Manual
+ * Order Number 253668 or free download from:
+ *
+ * http://developer.intel.com/Assets/PDF/manual/253668.pdf
+ *
+ * For more information, go to http://www.urbanmyth.org/microcode
+ *
+ * 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.
+ *
+ */
+#include <linux/firmware.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/microcode_intel.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+
+static inline int
+update_match_cpu(unsigned int csig, unsigned int cpf,
+ unsigned int sig, unsigned int pf)
+{
+ return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1;
+}
+
+static inline int
+update_match_revision(struct microcode_header_intel *mc_header, int rev)
+{
+ return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+int microcode_sanity_check(void *mc, int print_err)
+{
+ unsigned long total_size, data_size, ext_table_size;
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header = NULL;
+ int sum, orig_sum, ext_sigcount = 0, i;
+ struct extended_signature *ext_sig;
+
+ total_size = get_totalsize(mc_header);
+ data_size = get_datasize(mc_header);
+
+ if (data_size + MC_HEADER_SIZE > total_size) {
+ if (print_err)
+ pr_err("error! Bad data size in microcode data file\n");
+ return -EINVAL;
+ }
+
+ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+ if (print_err)
+ pr_err("error! Unknown microcode update format\n");
+ return -EINVAL;
+ }
+ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+ if (ext_table_size) {
+ if ((ext_table_size < EXT_HEADER_SIZE)
+ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+ if (print_err)
+ pr_err("error! Small exttable size in microcode data file\n");
+ return -EINVAL;
+ }
+ ext_header = mc + MC_HEADER_SIZE + data_size;
+ if (ext_table_size != exttable_size(ext_header)) {
+ if (print_err)
+ pr_err("error! Bad exttable size in microcode data file\n");
+ return -EFAULT;
+ }
+ ext_sigcount = ext_header->count;
+ }
+
+ /* check extended table checksum */
+ if (ext_table_size) {
+ int ext_table_sum = 0;
+ int *ext_tablep = (int *)ext_header;
+
+ i = ext_table_size / DWSIZE;
+ while (i--)
+ ext_table_sum += ext_tablep[i];
+ if (ext_table_sum) {
+ if (print_err)
+ pr_warn("aborting, bad extended signature table checksum\n");
+ return -EINVAL;
+ }
+ }
+
+ /* calculate the checksum */
+ orig_sum = 0;
+ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+ while (i--)
+ orig_sum += ((int *)mc)[i];
+ if (orig_sum) {
+ if (print_err)
+ pr_err("aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ if (!ext_table_size)
+ return 0;
+ /* check extended signature checksum */
+ for (i = 0; i < ext_sigcount; i++) {
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+ EXT_SIGNATURE_SIZE * i;
+ sum = orig_sum
+ - (mc_header->sig + mc_header->pf + mc_header->cksum)
+ + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+ if (sum) {
+ if (print_err)
+ pr_err("aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(microcode_sanity_check);
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+int get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev)
+{
+ struct microcode_header_intel *mc_header = mc;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+
+ if (!update_match_revision(mc_header, rev))
+ return 0;
+
+ if (update_match_cpu(csig, cpf, mc_header->sig, mc_header->pf))
+ return 1;
+
+ /* Look for ext. headers: */
+ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ return 0;
+
+ ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+ ext_sigcount = ext_header->count;
+ ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+ for (i = 0; i < ext_sigcount; i++) {
+ if (update_match_cpu(csig, cpf, ext_sig->sig, ext_sig->pf))
+ return 1;
+ ext_sig++;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(get_matching_microcode);
--
1.7.2

Subject: Re: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file name

On Sat, 18 Aug 2012, Fenghua Yu wrote:
> Given a file's name, find its starting point in a cpio formated area. This will
> be used to find microcode in combined initrd image. But this function is
> generic and could be used in other places.

Shouldn't this (very useful) feature get its own documentation in
Documentation/ ?

--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh

Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On Sat, 18 Aug 2012, Fenghua Yu wrote:
> + char ucode_name[] = "kernel/x86/microcode/GenuineIntel/microcode.hex";

Why name it ".hex" when you're loading binary data? I suggest ".bin". It
is confusing to have .hex there, since you're not dealing with the Intel HEX
format, nor anything text-like.

> +void __init load_ucode_bsp(char *real_mode_data)
> +{
> + u64 ramdisk_image, ramdisk_size, ramdisk_end;
> + unsigned long initrd_start, initrd_end;
> + struct boot_params *boot_params;
> +
> + boot_params = (struct boot_params *)real_mode_data;
> + ramdisk_image = boot_params->hdr.ramdisk_image;
> + ramdisk_size = boot_params->hdr.ramdisk_size;
> +
> +#ifdef CONFIG_X86_64
> + ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
> + initrd_start = ramdisk_image + PAGE_OFFSET;
> +#else
> + ramdisk_end = ramdisk_image + ramdisk_size;
> + initrd_start = ramdisk_image;
> +#endif
> + initrd_end = initrd_start + ramdisk_size;
> +
> + /*
> + * It's early to get CPU vendor info at this point.
> + * By searching initrd to find right name for vendor's microcode,
> + * it's relative easier to get CPU vendor info.
> + */
> + if (find_ucode_intel(initrd_start, initrd_end) == UCODE_OK)
> + load_ucode_intel_bsp(real_mode_data);
> +}

I'd say something down the load_ucode_intel_bsp() chain better check the CPU
vendor to make sure the Intel driver won't attempt to load microcode on some
other vendor's processor.

Or are cpu signatures a global namespace and x86 cpu vendors make sure
(past, present and future) to never use the same cpu signature as someone
else is going to use? Anyway, it would still might be a good thing to do
the vendor check somewhere to avoid wasting time going over every microcode
of the wrong vendor on generic boot images that have both AMD and Intel
microcode.

--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh

2012-08-18 23:24:09

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file name

> -----Original Message-----
> From: Henrique de Moraes Holschuh [mailto:[email protected]]
> Sent: Saturday, August 18, 2012 3:13 PM
> To: Yu, Fenghua
> Cc: H Peter Anvin; Ingo Molnar; Thomas Gleixner; Mallick, Asit K;
> Tigran Aivazian; Andreas Herrmann; Borislav Petkov; linux-kernel; x86
> Subject: Re: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file
> name
>
> On Sat, 18 Aug 2012, Fenghua Yu wrote:
> > Given a file's name, find its starting point in a cpio formated area.
> This will
> > be used to find microcode in combined initrd image. But this function
> is
> > generic and could be used in other places.
>
> Shouldn't this (very useful) feature get its own documentation in
> Documentation/ ?

Yes, I can document the feature. And if it's generic and useful, this function could be put in generic kernel instead of in x86 arch.

Thanks.

-Fenghua

2012-08-19 02:38:51

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

> -----Original Message-----
> From: Henrique de Moraes Holschuh [mailto:[email protected]]
> Sent: Saturday, August 18, 2012 3:45 PM
> To: Yu, Fenghua
> Cc: H Peter Anvin; Ingo Molnar; Thomas Gleixner; Mallick, Asit K;
> Tigran Aivazian; Andreas Herrmann; Borislav Petkov; linux-kernel; x86
> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
> interfaces for early load ucode
>
> On Sat, 18 Aug 2012, Fenghua Yu wrote:
> > + char ucode_name[] =
> "kernel/x86/microcode/GenuineIntel/microcode.hex";
>
> Why name it ".hex" when you're loading binary data? I suggest ".bin".
> It
> is confusing to have .hex there, since you're not dealing with the
> Intel HEX
> format, nor anything text-like.
>
> > +void __init load_ucode_bsp(char *real_mode_data)
> > +{
> > + u64 ramdisk_image, ramdisk_size, ramdisk_end;
> > + unsigned long initrd_start, initrd_end;
> > + struct boot_params *boot_params;
> > +
> > + boot_params = (struct boot_params *)real_mode_data;
> > + ramdisk_image = boot_params->hdr.ramdisk_image;
> > + ramdisk_size = boot_params->hdr.ramdisk_size;
> > +
> > +#ifdef CONFIG_X86_64
> > + ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
> > + initrd_start = ramdisk_image + PAGE_OFFSET;
> > +#else
> > + ramdisk_end = ramdisk_image + ramdisk_size;
> > + initrd_start = ramdisk_image;
> > +#endif
> > + initrd_end = initrd_start + ramdisk_size;
> > +
> > + /*
> > + * It's early to get CPU vendor info at this point.
> > + * By searching initrd to find right name for vendor's microcode,
> > + * it's relative easier to get CPU vendor info.
> > + */
> > + if (find_ucode_intel(initrd_start, initrd_end) == UCODE_OK)
> > + load_ucode_intel_bsp(real_mode_data);
> > +}
>
> I'd say something down the load_ucode_intel_bsp() chain better check
> the CPU
> vendor to make sure the Intel driver won't attempt to load microcode on
> some
> other vendor's processor.
>
> Or are cpu signatures a global namespace and x86 cpu vendors make sure
> (past, present and future) to never use the same cpu signature as
> someone
> else is going to use? Anyway, it would still might be a good thing to
> do
> the vendor check somewhere to avoid wasting time going over every
> microcode
> of the wrong vendor on generic boot images that have both AMD and Intel
> microcode.
>

In this early phase, detecting vendor in initrd is much simpler code. Otherwise, detecting vendor by cpuid (and without cpuid) needs similar but different code as existing functions and coding would be awkward.

I fully thought and agreed the usage complexity you describe here. It might be good thing to do a bit ugly but more practical coding here.

Thanks.

-Fenghua

Subject: Re: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file name

On Sat, 18 Aug 2012, Yu, Fenghua wrote:
> > From: Henrique de Moraes Holschuh [mailto:[email protected]] On Sat, 18 Aug
> > 2012, Fenghua Yu wrote:
> > > Given a file's name, find its starting point in a cpio formated area.
> > This will
> > > be used to find microcode in combined initrd image. But this function
> > is
> > > generic and could be used in other places.
> >
> > Shouldn't this (very useful) feature get its own documentation in
> > Documentation/ ?
>
> Yes, I can document the feature. And if it's generic and useful, this
> function could be put in generic kernel instead of in x86 arch.

It is useful to override/fix all sort of critical firmware-provided tables,
for example. ACPI table overrides should use this new cpio-based scheme as
well, and I recall someone wrote something about device tree overrides in a
past thread...

--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh

Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On Sun, 19 Aug 2012, Yu, Fenghua wrote:
> > From: Henrique de Moraes Holschuh [mailto:[email protected]]
> > On Sat, 18 Aug 2012, Fenghua Yu wrote:
> > > + char ucode_name[] =
> > "kernel/x86/microcode/GenuineIntel/microcode.hex";
> >
> > Why name it ".hex" when you're loading binary data? I suggest ".bin".
> > It
> > is confusing to have .hex there, since you're not dealing with the
> > Intel HEX
> > format, nor anything text-like.
> >
> > > +void __init load_ucode_bsp(char *real_mode_data)
> > > +{
> > > + u64 ramdisk_image, ramdisk_size, ramdisk_end;
> > > + unsigned long initrd_start, initrd_end;
> > > + struct boot_params *boot_params;
> > > +
> > > + boot_params = (struct boot_params *)real_mode_data;
> > > + ramdisk_image = boot_params->hdr.ramdisk_image;
> > > + ramdisk_size = boot_params->hdr.ramdisk_size;
> > > +
> > > +#ifdef CONFIG_X86_64
> > > + ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
> > > + initrd_start = ramdisk_image + PAGE_OFFSET;
> > > +#else
> > > + ramdisk_end = ramdisk_image + ramdisk_size;
> > > + initrd_start = ramdisk_image;
> > > +#endif
> > > + initrd_end = initrd_start + ramdisk_size;
> > > +
> > > + /*
> > > + * It's early to get CPU vendor info at this point.
> > > + * By searching initrd to find right name for vendor's microcode,
> > > + * it's relative easier to get CPU vendor info.
> > > + */
> > > + if (find_ucode_intel(initrd_start, initrd_end) == UCODE_OK)
> > > + load_ucode_intel_bsp(real_mode_data);
> > > +}
> >
> > I'd say something down the load_ucode_intel_bsp() chain better check
> > the CPU
> > vendor to make sure the Intel driver won't attempt to load microcode on
> > some
> > other vendor's processor.
> >
> > Or are cpu signatures a global namespace and x86 cpu vendors make sure
> > (past, present and future) to never use the same cpu signature as
> > someone
> > else is going to use? Anyway, it would still might be a good thing to
> > do
> > the vendor check somewhere to avoid wasting time going over every
> > microcode
> > of the wrong vendor on generic boot images that have both AMD and Intel
> > microcode.
> >
>
> In this early phase, detecting vendor in initrd is much simpler code. Otherwise, detecting vendor by cpuid (and without cpuid) needs similar but different code as existing functions and coding would be awkward.
>
> I fully thought and agreed the usage complexity you describe here. It might be good thing to do a bit ugly but more practical coding here.

Sure, there is no harm in defering the implementation of this check to later
versions of the patch set. As long as the final patch set doesn't risk
loading microcode on the wrong vendor or waste a lot of milliseconds trying
to match intel microcode to a non-intel cpu, I have no objections :-)

But what about the ".hex" naming for the microcode bundle (container) name?
I find it confusing, since the file contains binary data, not structured
text representing binary data using base 16... this is also something that
is of minor importance, but at least it is a very easy thing to change at
this point.

--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh

2012-08-19 05:16:06

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file name

On 08/18/2012 09:35 PM, Henrique de Moraes Holschuh wrote:
> On Sat, 18 Aug 2012, Yu, Fenghua wrote:
>>> From: Henrique de Moraes Holschuh [mailto:[email protected]] On Sat, 18 Aug
>>> 2012, Fenghua Yu wrote:
>>>> Given a file's name, find its starting point in a cpio formated area.
>>> This will
>>>> be used to find microcode in combined initrd image. But this function
>>> is
>>>> generic and could be used in other places.
>>>
>>> Shouldn't this (very useful) feature get its own documentation in
>>> Documentation/ ?
>>
>> Yes, I can document the feature. And if it's generic and useful, this
>> function could be put in generic kernel instead of in x86 arch.
>
> It is useful to override/fix all sort of critical firmware-provided tables,
> for example. ACPI table overrides should use this new cpio-based scheme as
> well, and I recall someone wrote something about device tree overrides in a
> past thread...
>

Indeed, we already have those two users already identified.

-hpa

2012-08-19 05:25:14

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On 08/18/2012 07:38 PM, Yu, Fenghua wrote:
>
> In this early phase, detecting vendor in initrd is much simpler code.
> Otherwise, detecting vendor by cpuid (and without cpuid) needs
> similar but different code as existing functions and coding would be
> awkward.
>

I'm confused by this statement. Getting the vendor from CPUID is a few
lines of code, and non-CPUID processors don't support microcode loading.

> Why name it ".hex" when you're loading binary data? I suggest ".bin". It
> is confusing to have .hex there, since you're not dealing with the Intel HEX
> format, nor anything text-like.

Actually I think we can also skip one level of indirection here... no
need to mention "microcode" twice.

kernel/x86/microcode/GenuineIntel or GenuineIntel.bin seems good
enough... the idea here of course is that the string can come from CPUID.

-hpa

2012-08-19 16:39:49

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

> -----Original Message-----
> From: H. Peter Anvin [mailto:[email protected]]
> Sent: Saturday, August 18, 2012 10:25 PM
> To: Yu, Fenghua
> Cc: Henrique de Moraes Holschuh; Ingo Molnar; Thomas Gleixner; Mallick,
> Asit K; Tigran Aivazian; Andreas Herrmann; Borislav Petkov; linux-
> kernel; x86
> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
> interfaces for early load ucode
>
> On 08/18/2012 07:38 PM, Yu, Fenghua wrote:
> >
> > In this early phase, detecting vendor in initrd is much simpler code.
> > Otherwise, detecting vendor by cpuid (and without cpuid) needs
> > similar but different code as existing functions and coding would be
> > awkward.
> >
>
> I'm confused by this statement. Getting the vendor from CPUID is a few
> lines of code, and non-CPUID processors don't support microcode loading.
>
Will checking vendor info from CPUID in next version.

> > Why name it ".hex" when you're loading binary data? I suggest ".bin".
> It
> > is confusing to have .hex there, since you're not dealing with the
> Intel HEX
> > format, nor anything text-like.
>
> Actually I think we can also skip one level of indirection here... no
> need to mention "microcode" twice.
>
> kernel/x86/microcode/GenuineIntel or GenuineIntel.bin seems good
> enough... the idea here of course is that the string can come from
> CPUID.
That's right. Will do this.

Thanks.

-Fenghua

2012-08-20 12:26:14

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 01/11] Documentation/x86: Early load microcode

On Sat, Aug 18, 2012 at 01:15:19AM -0700, Fenghua Yu wrote:
> From: Fenghua Yu <[email protected]>
>
> Documenation for early load microcode methodology.
>
> Signed-off-by: Fenghua Yu <[email protected]>
> ---
> Documentation/x86/earlyucode.txt | 43 ++++++++++++++++++++++++++++++++++++++
> 1 files changed, 43 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/x86/earlyucode.txt
>
> diff --git a/Documentation/x86/earlyucode.txt b/Documentation/x86/earlyucode.txt
> new file mode 100644
> index 0000000..d8966d6
> --- /dev/null
> +++ b/Documentation/x86/earlyucode.txt

Let's call the doc file "early-microcode.txt" like the rest of the
microcode-related files in the tree.

> @@ -0,0 +1,43 @@
> +Early load microcode
> +====================
> +By Fenghua Yu <[email protected]>
> +
> +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 initrd file. The microcode is read from the initrd file
^
an

> +and loaded to CPU's during boot time.

I think you mean the plural "CPUs" here.

> +
> +The format of the combined initrd image is microcode in cpio format followed by
> +initrd image (maybe compressed). Kernel parses the combined initrd image during
^
the

> +boot time. The microcode file in cpio name space is:

Here and below, can we call the microcode file the "microcode container"
to differentiate from the other "file" types?


s/time//

> +kernel/x86/microcode/GenuineIntel/microcode.hex
> +
> +During BSP boot (before SMP starts), if kernel finds the microcode file in the
^
the

> +initrd file, it parses the microcode and saves matching microcode in memory.

s/the microcode/it/

> +If matching microcode is found, it will be uploaded in BSP and later on in all

I guess "uploaded to the BSP" is more fitting here...

> +AP's.

APs.

> +
> +The saved microcode in memory will be used to upload micorcode when system
> +resumes from sleep.

Simplify:

"The cached microcode patch is applied when the CPU resumes from a sleep state."

> +
> +In the past, user can issue command to load microcode during run time.

Delete that sentence, it is not needed.

> +There are two user space interfaces to load microcode, either through
> +/dev/cpu/microcode interface or through reload file in sysfs.

s/interface//

"... or through /sys/devices/system/cpu/microcode/reload."


> +
> +Now user can choose any of the three methods to update microcode during boot
> +time or later during run time.

That sounds strange, maybe say something like:

"In addition to those two, the early loading method described here is
the third method with which microcode can be uploaded to a system's
CPUs."

> +
> +The following sample script shows how to generate a new combined initrd file in

s/sample/example/

> +/boot/initrd-3.5.0.ucode.img with original microcode microcode.hex and
^
in

> +original initrd image /boot/initrd-3.5.0.img.
> +
> +mkdir initrd
> +cd initrd
> +cp ../microcode.hex kernel/x86/microcode/GenuineIntel/microcode.hex
> +find .|cpio -oc >../ucode.cpio
> +cd ..
> +cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img
> +
> +The generated /boot/initrd-3.5.0.ucode.img can be used as initrd file to load
^
an

> +microcode during early boot time.

Thanks.

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 13:29:33

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 02/11] x86/lib/cpio.c: Find cpio data by its file name

On Sat, Aug 18, 2012 at 01:15:20AM -0700, Fenghua Yu wrote:
> From: Fenghua Yu <[email protected]>
>
> Given a file's name, find its starting point in a cpio formated area. This will

s/file's/file/ cpio-formatted

> be used to find microcode in combined initrd image. But this function is
> generic and could be used in other places.
>
> Signed-off-by: Fenghua Yu <[email protected]>
> ---
> arch/x86/include/asm/cpio.h | 10 +++
> arch/x86/lib/Makefile | 2 +
> arch/x86/lib/cpio.c | 179 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 191 insertions(+), 0 deletions(-)
> create mode 100644 arch/x86/include/asm/cpio.h
> create mode 100644 arch/x86/lib/cpio.c
>
> diff --git a/arch/x86/include/asm/cpio.h b/arch/x86/include/asm/cpio.h
> new file mode 100644
> index 0000000..26a4333
> --- /dev/null
> +++ b/arch/x86/include/asm/cpio.h
> @@ -0,0 +1,10 @@
> +#include <stddef.h>
> +#include <stdbool.h>
> +
> +struct cpio_data {
> + void *data;
> + unsigned long size;
> +};
> +
> +extern struct cpio_data
> +find_cpio_data(const char *name, const void *data, size_t len);
> diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
> index b00f678..452a4b5 100644
> --- a/arch/x86/lib/Makefile
> +++ b/arch/x86/lib/Makefile
> @@ -45,3 +45,5 @@ else
> lib-y += copy_user_64.o copy_user_nocache_64.o
> lib-y += cmpxchg16b_emu.o
> endif
> +
> +obj-y += cpio.o
> diff --git a/arch/x86/lib/cpio.c b/arch/x86/lib/cpio.c
> new file mode 100644
> index 0000000..70ac474
> --- /dev/null
> +++ b/arch/x86/lib/cpio.c
> @@ -0,0 +1,179 @@
> +/*
> + * findcpio.c
> + *
> + * Find a specific cpio member; must precede any compressed content.
> + *
> + * Copyright (C) 2012 H Peter Anvin" <[email protected]>

stray "

> + * Fenghua Yu <[email protected]>
> + */
> +#include <linux/module.h>
> +#include <linux/mm.h>
> +#include <linux/swap.h>
> +#include <linux/slab.h>
> +#include <linux/sysctl.h>
> +#include <linux/bitmap.h>
> +#include <linux/signal.h>
> +#include <linux/printk.h>
> +#include <linux/proc_fs.h>
> +#include <linux/security.h>
> +#include <linux/ctype.h>
> +#include <linux/kmemcheck.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/net.h>
> +#include <linux/sysrq.h>
> +#include <linux/highuid.h>
> +#include <linux/writeback.h>
> +#include <linux/ratelimit.h>
> +#include <linux/compaction.h>
> +#include <linux/hugetlb.h>
> +#include <linux/initrd.h>
> +#include <linux/key.h>
> +#include <linux/times.h>
> +#include <linux/limits.h>
> +#include <linux/dcache.h>
> +#include <linux/dnotify.h>
> +#include <linux/syscalls.h>

Why all those includes?

> +#include <asm/cpio.h>
> +
> +enum cpio_fields {
> + C_MAGIC,
> + C_INO,
> + C_MODE,
> + C_UID,
> + C_GID,
> + C_NLINK,
> + C_MTIME,
> + C_FILESIZE,
> + C_MAJ,
> + C_MIN,
> + C_RMAJ,
> + C_RMIN,
> + C_NAMESIZE,
> + C_CHKSUM,
> + C_NFIELDS
> +};
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +static size_t cpio_strlen(const char *name)
> +{
> + size_t n = -1;
> +
> + asm("repne; scasb"
> + : "+D" (name), "+c" (n)
> + : "a" (0));
> +
> + return -2 - n;
> +}
> +
> +static int cpio_memcmp(const void *p1, const void *p2, size_t n)
> +{
> + unsigned char rv;
> +
> + asm("repe; cmpsb; setne %0"
> + : "=r" (rv), "+S" (p1), "+D" (p2), "+c" (n));
> +
> + return rv;
> +}

I guess those are speed optimizations on x86, right? In any
case, can we reuse some of the already present ones like
memcmp in <arch/x86/boot/compressed/string.c> and strlen in
<arch/x86/lib/string_32.c>...

> +#else
> +static size_t cpio_strlen(const char *name)
> +{
> + size_t n = 0;
> +
> + while (*name++)
> + n++;
> +
> + return n;
> +}
> +
> +static int cpio_memcmp(const void *p1, const void *p2, size_t n)
> +{
> + const unsigned char *u1 = p1;
> + const unsigned char *u2 = p2;
> + int d;
> +
> + while (n--) {
> + d = *u2++ - *u1++;
> + if (d)
> + return d;
> + }
> + return 0;
> +}
> +#endif

and, similarly the generic ones in lib/string.c?

> +
> +#define ALIGN4(p) ((void *)(((size_t)p + 3) & ~3))
> +
> +struct cpio_data find_cpio_data(const char *name, const void *data, size_t len)
> +{
> + const size_t cpio_header_len = 8*C_NFIELDS - 2;
> + struct cpio_data cd = { NULL, 0 };
> + const char *p, *dptr, *nptr;
> + unsigned int ch[C_NFIELDS], *chp, v;
> + unsigned char c, x;
> + size_t mynamesize = cpio_strlen(name) + 1;
> + int i, j;
> +
> + p = data;
> +
> + while (len > cpio_header_len) {
> + if (!*p) {
> + /* All cpio headers need to be 4-byte aligned */
> + p += 4;
> + len -= 4;
> + continue;
> + }
> +
> + j = 6; /* The magic field is only 6 characters */

Maybe put all comments above the line they refer to, like above instead
of them trailing?

> + chp = ch;
> + for (i = C_NFIELDS; i; i--) {
> + v = 0;
> + while (j--) {
> + v <<= 4;
> + c = *p++;
> +
> + x = c - '0';
> + if (x < 10) {
> + v += x;
> + continue;
> + }
> +
> + x = (c | 0x20) - 'a';
> + if (x < 6) {
> + v += x + 10;
> + continue;
> + }
> +
> + goto quit; /* Invalid hexadecimal */
> + }
> + *chp++ = v;
> + j = 8; /* All other fields are 8 characters */
> + }
> +
> + if ((ch[C_MAGIC] - 0x070701) > 1)
> + goto quit; /* Invalid magic */
> +
> + len -= cpio_header_len;
> +
> + dptr = ALIGN4(p + ch[C_NAMESIZE]);
> + nptr = ALIGN4(dptr + ch[C_FILESIZE]);
> +
> + if (nptr > p + len || dptr < p || nptr < dptr)
> + goto quit; /* Buffer overrun */
> +
> + if ((ch[C_MODE] & 0170000) == 0100000 &&
> + ch[C_NAMESIZE] == mynamesize &&
> + !cpio_memcmp(p, name, mynamesize)) {
> + cd.data = (void *)dptr;
> + cd.size = ch[C_FILESIZE];
> + return cd; /* Found it! */
> + }
> +
> + len -= (nptr - p);
> + p = nptr;
> + }
> +
> +quit:
> + return cd;
> +}
> --
> 1.7.2
>
>

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 13:47:44

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 03/11] x86/microcode_intel.h: Define functions and macros for early load ucode

On Sat, Aug 18, 2012 at 01:15:21AM -0700, Fenghua Yu wrote:
> From: Fenghua Yu <[email protected]>
>
> Define some functions and macros that will be used in early load ucode. Some of
> them are moved from microcode_intel.c driver in order to be called in early
> boot phase before module can be called.
>
> Signed-off-by: Fenghua Yu <[email protected]>
> ---
> arch/x86/include/asm/microcode_intel.h | 103 ++++++++++++++++++
> arch/x86/kernel/Makefile | 3 +
> arch/x86/kernel/microcode_core.c | 7 +-
> arch/x86/kernel/microcode_intel.c | 185 ++------------------------------
> 4 files changed, 117 insertions(+), 181 deletions(-)

[ … ]

> -static int microcode_sanity_check(void *mc)
> -{
> - unsigned long total_size, data_size, ext_table_size;
> - struct microcode_header_intel *mc_header = mc;
> - struct extended_sigtable *ext_header = NULL;
> - int sum, orig_sum, ext_sigcount = 0, i;
> - struct extended_signature *ext_sig;
> -
> - total_size = get_totalsize(mc_header);
> - data_size = get_datasize(mc_header);
> -
> - if (data_size + MC_HEADER_SIZE > total_size) {
> - pr_err("error! Bad data size in microcode data file\n");
> - return -EINVAL;
> - }
> -
> - if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
> - pr_err("error! Unknown microcode update format\n");
> - return -EINVAL;
> - }
> - ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
> - if (ext_table_size) {
> - if ((ext_table_size < EXT_HEADER_SIZE)
> - || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
> - pr_err("error! Small exttable size in microcode data file\n");
> - return -EINVAL;
> - }
> - ext_header = mc + MC_HEADER_SIZE + data_size;
> - if (ext_table_size != exttable_size(ext_header)) {
> - pr_err("error! Bad exttable size in microcode data file\n");
> - return -EFAULT;
> - }
> - ext_sigcount = ext_header->count;
> - }
> -
> - /* check extended table checksum */
> - if (ext_table_size) {
> - int ext_table_sum = 0;
> - int *ext_tablep = (int *)ext_header;
> -
> - i = ext_table_size / DWSIZE;
> - while (i--)
> - ext_table_sum += ext_tablep[i];
> - if (ext_table_sum) {
> - pr_warning("aborting, bad extended signature table checksum\n");
> - return -EINVAL;
> - }
> - }
> -
> - /* calculate the checksum */
> - orig_sum = 0;
> - i = (MC_HEADER_SIZE + data_size) / DWSIZE;
> - while (i--)
> - orig_sum += ((int *)mc)[i];
> - if (orig_sum) {
> - pr_err("aborting, bad checksum\n");
> - return -EINVAL;
> - }
> - if (!ext_table_size)
> - return 0;
> - /* check extended signature checksum */
> - for (i = 0; i < ext_sigcount; i++) {
> - ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
> - EXT_SIGNATURE_SIZE * i;
> - sum = orig_sum
> - - (mc_header->sig + mc_header->pf + mc_header->cksum)
> - + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
> - if (sum) {
> - pr_err("aborting, bad checksum\n");
> - return -EINVAL;
> - }
> - }
> - return 0;
> -}

This patch introduces a build error:

In file included from arch/x86/kernel/microcode_intel.c:82:0:
/usr/src/linux/linux-2.6/arch/x86/include/asm/microcode_intel.h:81:14: warning: ‘struct mc_saved_data’ declared inside parameter list [enabled by default]
/usr/src/linux/linux-2.6/arch/x86/include/asm/microcode_intel.h:81:14: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
/usr/src/linux/linux-2.6/arch/x86/include/asm/microcode_intel.h:98:14: warning: ‘struct mc_saved_data’ declared inside parameter list [enabled by default]
ERROR: "get_matching_microcode" [arch/x86/kernel/microcode.ko] undefined!
ERROR: "microcode_sanity_check" [arch/x86/kernel/microcode.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
make: *** Waiting for unfinished jobs....

due to the removal of the two functions.

> -
> -/*
> - * return 0 - no update found
> - * return 1 - found update
> - */
> -static int
> -get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
> -{
> - struct microcode_header_intel *mc_header = mc;
> - struct extended_sigtable *ext_header;
> - unsigned long total_size = get_totalsize(mc_header);
> - int ext_sigcount, i;
> - struct extended_signature *ext_sig;
> -
> - if (!update_match_revision(mc_header, rev))
> - return 0;
> -
> - if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
> - return 1;
> -
> - /* Look for ext. headers: */
> - if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
> - return 0;
> -
> - ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
> - ext_sigcount = ext_header->count;
> - ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
> -
> - for (i = 0; i < ext_sigcount; i++) {
> - if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
> - return 1;
> - ext_sig++;
> - }
> - return 0;
> -}
> -
> -static int apply_microcode(int cpu)
> +int apply_microcode(int cpu)
> {
> struct microcode_intel *mc_intel;
> struct ucode_cpu_info *uci;
> @@ -338,6 +164,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
> unsigned int leftover = size;
> enum ucode_state state = UCODE_OK;
> unsigned int curr_mc_size = 0;
> + unsigned int csig, cpf;
>
> while (leftover) {
> struct microcode_header_intel mc_header;
> @@ -362,11 +189,13 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
> }
>
> if (get_ucode_data(mc, ucode_ptr, mc_size) ||
> - microcode_sanity_check(mc) < 0) {
> + microcode_sanity_check(mc, 1) < 0) {
> break;
> }
>
> - if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
> + csig = uci->cpu_sig.sig;
> + cpf = uci->cpu_sig.pf;
> + if (get_matching_microcode(csig, cpf, mc, new_rev)) {
> vfree(new_mc);
> new_rev = mc_header.rev;
> new_mc = mc;
> --
> 1.7.2
>
>

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 14:04:17

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On Sat, Aug 18, 2012 at 01:15:22AM -0700, Fenghua Yu wrote:
> From: Fenghua Yu <[email protected]>
>
> Define interfaces load_ucode_bsp() and load_ucode_ap() to load ucode on BSP and
> AP in early boot time. These are generic interfaces. Internally they call
> vendor specific implementations.
>
> Signed-off-by: Fenghua Yu <[email protected]>
> ---
> arch/x86/include/asm/microcode.h | 23 ++++++++++
> arch/x86/kernel/microcode_core_early.c | 74 ++++++++++++++++++++++++++++++++
> 2 files changed, 97 insertions(+), 0 deletions(-)

Still the same build error:

ERROR: "get_matching_microcode" [arch/x86/kernel/microcode.ko] undefined!
ERROR: "microcode_sanity_check" [arch/x86/kernel/microcode.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
make: *** Waiting for unfinished jobs....


> create mode 100644 arch/x86/kernel/microcode_core_early.c
>
> diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
> index 4ebe157..080ea77 100644
> --- a/arch/x86/include/asm/microcode.h
> +++ b/arch/x86/include/asm/microcode.h
> @@ -63,4 +63,27 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
> static inline void __exit exit_amd_microcode(void) {}
> #endif
>
> +struct mc_saved_data {
> + unsigned int mc_saved_count;
> + struct microcode_intel **mc_saved;
> + struct ucode_cpu_info *ucode_cpu_info;
> +};
> +#ifdef CONFIG_MICROCODE_EARLY
> +#define MAX_UCODE_COUNT 128
> +extern struct ucode_cpu_info ucode_cpu_info_early[NR_CPUS];
> +extern struct microcode_intel __initdata *mc_saved_in_initrd[MAX_UCODE_COUNT];
> +extern struct mc_saved_data mc_saved_data;
> +extern void __init load_ucode_bsp(char *real_mode_data);
> +extern __init void load_ucode_ap(void);
> +extern void __init
> +save_microcode_in_initrd(struct mc_saved_data *mc_saved_data,
> + struct microcode_intel **mc_saved_in_initrd);
> +#else
> +static inline void __init load_ucode_bsp(char *real_mode_data) {}
> +static inline __init void load_ucode_ap(void) {}
> +static inline void __init
> +save_microcode_in_initrd(struct mc_saved_data *mc_saved_data,
> + struct microcode_intel **mc_saved_in_initrd) {}
> +#endif
> +
> #endif /* _ASM_X86_MICROCODE_H */
> diff --git a/arch/x86/kernel/microcode_core_early.c b/arch/x86/kernel/microcode_core_early.c
> new file mode 100644
> index 0000000..5bcc6f8
> --- /dev/null
> +++ b/arch/x86/kernel/microcode_core_early.c
> @@ -0,0 +1,74 @@
> +/*
> + * X86 CPU microcode early update for Linux
> + *
> + * Copyright (C) 2012 Fenghua Yu <[email protected]>
> + * H Peter Anvin" <[email protected]>
> + *
> + * This driver allows to early upgrade microcode on Intel processors
> + * belonging to IA-32 family - PentiumPro, Pentium II,
> + * Pentium III, Xeon, Pentium 4, etc.

Can we drop the vendor-specific text from generic x86 code pls? This
belongs into microcode_intel_* AFAICT.

> + *
> + * Reference: Section 9.11 of Volume 3, IA-32 Intel Architecture
> + * Software Developer's Manual.
> + *
> + * 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.
> + */
> +#include <linux/module.h>
> +#include <linux/mm.h>
> +#include <asm/microcode_intel.h>
> +#include <asm/processor.h>
> +#include <asm/cpio.h>
> +
> +struct ucode_cpu_info ucode_cpu_info_early[NR_CPUS];
> +EXPORT_SYMBOL_GPL(ucode_cpu_info_early);
> +
> +static __init enum ucode_state
> +find_ucode_intel(unsigned long start, unsigned long end)
> +{
> + unsigned int size = end - start + 1;
> + struct cpio_data cd = { 0, 0 };
> + char ucode_name[] = "kernel/x86/microcode/GenuineIntel/microcode.hex";
> +
> + cd = find_cpio_data(ucode_name, (void *)start, size);
> + if (cd.data)
> + return UCODE_OK;
> +
> + return UCODE_ERROR;
> +}

This function can be made generic by giving the ucode_name down as an
arg, for example, so that other vendors can use it too.

> +
> +void __init load_ucode_bsp(char *real_mode_data)
> +{
> + u64 ramdisk_image, ramdisk_size, ramdisk_end;
> + unsigned long initrd_start, initrd_end;
> + struct boot_params *boot_params;
> +
> + boot_params = (struct boot_params *)real_mode_data;
> + ramdisk_image = boot_params->hdr.ramdisk_image;
> + ramdisk_size = boot_params->hdr.ramdisk_size;
> +
> +#ifdef CONFIG_X86_64
> + ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size);
> + initrd_start = ramdisk_image + PAGE_OFFSET;
> +#else
> + ramdisk_end = ramdisk_image + ramdisk_size;
> + initrd_start = ramdisk_image;
> +#endif
> + initrd_end = initrd_start + ramdisk_size;
> +
> + /*
> + * It's early to get CPU vendor info at this point.
> + * By searching initrd to find right name for vendor's microcode,
> + * it's relative easier to get CPU vendor info.
> + */
> + if (find_ucode_intel(initrd_start, initrd_end) == UCODE_OK)
> + load_ucode_intel_bsp(real_mode_data);
> +}
> +
> +void __cpuinit load_ucode_ap(void)
> +{
> + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
> + load_ucode_intel_ap();
> +}
> --
> 1.7.2
>
>

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 14:06:43

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On Sun, Aug 19, 2012 at 04:39:42PM +0000, Yu, Fenghua wrote:
> > Actually I think we can also skip one level of indirection here... no
> > need to mention "microcode" twice.
> >
> > kernel/x86/microcode/GenuineIntel or GenuineIntel.bin seems good
> > enough... the idea here of course is that the string can come from
> > CPUID.
> That's right. Will do this.

Or,

in case we want to supply more vendor-specific stuff early at boot, we
could do:

kernel/x86/<vendor>/microcode...
|-> bios_overrides
|-> ...

and have this layout extensible from the beginning...

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 15:31:27

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 05/11] x86/microcode_intel_lib.c: Early update ucode on Intel's CPU

On Sat, Aug 18, 2012 at 01:15:23AM -0700, Fenghua Yu wrote:
> From: Fenghua Yu <[email protected]>
>
> Define interfaces microcode_sanity_check() and get_matching_microcode(). They
> are called both in early boot time and in microcode Intel driver.
>
> Signed-off-by: Fenghua Yu <[email protected]>

Actually,

this one should be merged with 3/11 to kill the build error.

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 15:39:42

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Sat, Aug 18, 2012 at 01:15:18AM -0700, Fenghua Yu wrote:
> Documentation/x86/earlyucode.txt | 43 +++
> arch/x86/Kconfig | 22 ++
> arch/x86/include/asm/cpio.h | 10 +
> arch/x86/include/asm/microcode.h | 23 ++
> arch/x86/include/asm/microcode_intel.h | 103 +++++++
> arch/x86/kernel/Makefile | 3 +
> arch/x86/kernel/head64.c | 6 +
> arch/x86/kernel/head_32.S | 6 +
> arch/x86/kernel/microcode_core.c | 7 +-
> arch/x86/kernel/microcode_core_early.c | 74 +++++
> arch/x86/kernel/microcode_intel.c | 185 +------------
> arch/x86/kernel/microcode_intel_early.c | 482 +++++++++++++++++++++++++++++++
> arch/x86/kernel/microcode_intel_lib.c | 163 +++++++++++

One more thing:

This screams for adding a directory called "microcode" in the kernel
sources and moving all the microcode-related files there. IOW:

arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/microcode/core_early.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/microcode/amd.c
...

And yes, they should be under "cpu" too.

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 15:44:28

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 00/11] x86/microcode: Early load microcode

> -----Original Message-----
> From: Borislav Petkov [mailto:[email protected]]
> Sent: Monday, August 20, 2012 8:39 AM
> To: Yu, Fenghua
> Cc: H Peter Anvin; Ingo Molnar; Thomas Gleixner; Mallick, Asit K;
> Tigran Aivazian; Andreas Herrmann; Borislav Petkov; linux-kernel; x86
> Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode
>
> On Sat, Aug 18, 2012 at 01:15:18AM -0700, Fenghua Yu wrote:
> > Documentation/x86/earlyucode.txt | 43 +++
> > arch/x86/Kconfig | 22 ++
> > arch/x86/include/asm/cpio.h | 10 +
> > arch/x86/include/asm/microcode.h | 23 ++
> > arch/x86/include/asm/microcode_intel.h | 103 +++++++
> > arch/x86/kernel/Makefile | 3 +
> > arch/x86/kernel/head64.c | 6 +
> > arch/x86/kernel/head_32.S | 6 +
> > arch/x86/kernel/microcode_core.c | 7 +-
> > arch/x86/kernel/microcode_core_early.c | 74 +++++
> > arch/x86/kernel/microcode_intel.c | 185 +------------
> > arch/x86/kernel/microcode_intel_early.c | 482
> +++++++++++++++++++++++++++++++
> > arch/x86/kernel/microcode_intel_lib.c | 163 +++++++++++
>
> One more thing:
>
> This screams for adding a directory called "microcode" in the kernel
> sources and moving all the microcode-related files there. IOW:
>
> arch/x86/kernel/cpu/microcode/core.c
> arch/x86/kernel/cpu/microcode/core_early.c
> arch/x86/kernel/cpu/microcode/intel.c
> arch/x86/kernel/cpu/microcode/amd.c
> ...
>
> And yes, they should be under "cpu" too.

That's right.

Thanks.

-Fenghua

2012-08-20 16:25:04

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 05/11] x86/microcode_intel_lib.c: Early update ucode on Intel's CPU

On Mon, Aug 20, 2012 at 05:31:10PM +0200, Borislav Petkov wrote:
> On Sat, Aug 18, 2012 at 01:15:23AM -0700, Fenghua Yu wrote:
> > From: Fenghua Yu <[email protected]>
> >
> > Define interfaces microcode_sanity_check() and get_matching_microcode(). They
> > are called both in early boot time and in microcode Intel driver.
> >
> > Signed-off-by: Fenghua Yu <[email protected]>
>
> Actually,
>
> this one should be merged with 3/11 to kill the build error.

This still doesn't suffice:

ERROR: "get_matching_microcode" [arch/x86/kernel/microcode.ko] undefined!
ERROR: "microcode_sanity_check" [arch/x86/kernel/microcode.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
make: *** Waiting for unfinished jobs....

.config attached.

And by quickly grepping through it, none of the new options are there:

obj-$(CONFIG_MICROCODE_EARLY) += microcode_core_early.o
obj-$(CONFIG_MICROCODE_INTEL_EARLY) += microcode_intel_early.o
obj-$(CONFIG_MICROCODE_INTEL_LIB) += microcode_intel_lib.o
microcode-y := microcode_core.o

which most probably causes the build error. AFAICT, you need to pull up
the arch/x86/Kconfig changes from 11/11 too.

HTH.

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551


Attachments:
(No filename) (1.33 kB)
.config (73.81 kB)
Download all attachments

2012-08-20 18:51:51

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On 08/20/2012 08:39 AM, Borislav Petkov wrote:
> On Sat, Aug 18, 2012 at 01:15:18AM -0700, Fenghua Yu wrote:
>> Documentation/x86/earlyucode.txt | 43 +++
>> arch/x86/Kconfig | 22 ++
>> arch/x86/include/asm/cpio.h | 10 +
>> arch/x86/include/asm/microcode.h | 23 ++
>> arch/x86/include/asm/microcode_intel.h | 103 +++++++
>> arch/x86/kernel/Makefile | 3 +
>> arch/x86/kernel/head64.c | 6 +
>> arch/x86/kernel/head_32.S | 6 +
>> arch/x86/kernel/microcode_core.c | 7 +-
>> arch/x86/kernel/microcode_core_early.c | 74 +++++
>> arch/x86/kernel/microcode_intel.c | 185 +------------
>> arch/x86/kernel/microcode_intel_early.c | 482 +++++++++++++++++++++++++++++++
>> arch/x86/kernel/microcode_intel_lib.c | 163 +++++++++++
>
> One more thing:
>
> This screams for adding a directory called "microcode" in the kernel
> sources and moving all the microcode-related files there. IOW:
>
> arch/x86/kernel/cpu/microcode/core.c
> arch/x86/kernel/cpu/microcode/core_early.c
> arch/x86/kernel/cpu/microcode/intel.c
> arch/x86/kernel/cpu/microcode/amd.c
> ...
>
> And yes, they should be under "cpu" too.
>

Not really, but that isn't even Fenghua's fault.

The cpu directory was originally for cpu detection. The whole kernel/
directory, of course, is a morass that might as well be called "misc".
Some things are legitimately there -- mainly the syscall table and
things that mirror the global kernel/ -- but a ton of stuff doesn't make
any sense there.

Reorganizing the kernel/ directory and promoting cpu up one level would
make that make more sense. The pci and irq code are examples of things
that could use their own directories.

-hpa

2012-08-20 20:04:39

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Mon, Aug 20, 2012 at 11:51:14AM -0700, H. Peter Anvin wrote:
> Not really, but that isn't even Fenghua's fault.

Of course it isn't - I was simply pointing out that this is something
that should be fixed at some point in time, when someone needs a project
over an otherwise eventless weekend :-).

> The cpu directory was originally for cpu detection. The whole kernel/
> directory, of course, is a morass that might as well be called "misc".
> Some things are legitimately there -- mainly the syscall table and
> things that mirror the global kernel/ -- but a ton of stuff doesn't make
> any sense there.
>
> Reorganizing the kernel/ directory and promoting cpu up one level would

Yep, arch/x86/cpu, should contain all cpu-related stuff.

> make that make more sense. The pci and irq code are examples of things
> that could use their own directories.

Yep.

Thanks.

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 20:09:33

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On 08/20/2012 07:06 AM, Borislav Petkov wrote:
>
> Or,
>
> in case we want to supply more vendor-specific stuff early at boot, we
> could do:
>
> kernel/x86/<vendor>/microcode...
> |-> bios_overrides
> |-> ...
>
> and have this layout extensible from the beginning...
>

Does that make sense, though? I'm a bit concerned about having multiple
files named microcode.bin by default; the pathname isn't as sticky as
the filename when people move things around...

-hpa

2012-08-20 20:20:01

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On Mon, Aug 20, 2012 at 01:08:49PM -0700, H. Peter Anvin wrote:
> On 08/20/2012 07:06 AM, Borislav Petkov wrote:
> >
> > Or,
> >
> > in case we want to supply more vendor-specific stuff early at boot, we
> > could do:
> >
> > kernel/x86/<vendor>/microcode...
> > |-> bios_overrides
> > |-> ...
> >
> > and have this layout extensible from the beginning...
> >
> Does that make sense, though?

Only time will tell. I was simply saying that we should leave ourselves
the door opened, should we need functionality like that in the future.

> I'm a bit concerned about having multiple files named microcode.bin by
> default; the pathname isn't as sticky as the filename when people move
> things around...

Ok, I see.

How about the following scheme then:

kernel/x86/<vendor>-microcode.bin
kernel/x86/<vendor>-bios-overrides.blob
...

?

All I'm saying is maybe we should impose some sanity rules now before
people go crazy with this and things get out of hands...

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-20 21:41:25

by Paul Bolle

[permalink] [raw]
Subject: Re: [PATCH 11/11] x86/Kconfig: Configurations to enable/disable the feature

Fenghua,

I have a few comments, that were triggered by scanning just this patch
(they also assume I remember the kconfig language correctly).

On Sat, 2012-08-18 at 01:15 -0700, Fenghua Yu wrote:
> From: Fenghua Yu <[email protected]>
>
> MICROCODE_INTEL_LIB, MICROCODE_INTEL_EARLY, and MICROCODE_EARLY are three new
> configurations to enable or disable the feature.
>
> Signed-off-by: Fenghua Yu <[email protected]>
> ---
> arch/x86/Kconfig | 22 ++++++++++++++++++++++
> 1 files changed, 22 insertions(+), 0 deletions(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 50c660d..32caa77 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1035,6 +1035,7 @@ config MICROCODE_INTEL
> depends on MICROCODE
> default MICROCODE
> select FW_LOADER
> + select MICROCODE_INTEL_LIB

MICROCODE_INTEL_LIB depends on MICROCODE_INTEL_EARLY.
MICROCODE_INTEL_EARLY itself also selects MICROCODE_INTEL_LIB. So can't
this kconfig entry be made to select MICROCODE_INTEL_EARLY instead?

If it can't select MICROCODE_INTEL_EARLY (because of that symbol's
dependency on BLK_DEV_INITRD) it seems this select could be dropped.

> ---help---
> This options enables microcode patch loading support for Intel
> processors.
> @@ -1055,6 +1056,27 @@ config MICROCODE_OLD_INTERFACE
> def_bool y
> depends on MICROCODE
>
> +config MICROCODE_EARLY
> + def_bool y
> + depends on MICROCODE_INTEL_EARLY
> +

MICROCODE_INTEL_EARLY selects this kconfig symbol. Doesn't that mean
that this entry can be simplified to:
config MICROCODE_EARLY
bool

> +config MICROCODE_INTEL_LIB
> + def_bool y
> + depends on MICROCODE_INTEL_EARLY

If MICROCODE_INTEL could be made to select MICROCODE_INTEL_EARLY (see
above) it seems this could also be shortened:
config MICROCODE_INTEL_LIB
bool

> +config MICROCODE_INTEL_EARLY
> + bool "Early load microcode"
> + depends on MICROCODE_INTEL && BLK_DEV_INITRD

If MICROCODE_INTEL could be made to select this kconfig symbol than the
dependency on MICROCODE_INTEL could be dropped. But the dependency on
BLK_DEV_INITRD might make that impossible.

> + default y
> + select FW_LOADER
> + select MICROCODE_EARLY
> + select MICROCODE_INTEL_LIB
> + help
> + This option provides functionality to read additional microcode data
> + at the beginning of initrd image. The data tells kernel to load
> + microcode to CPU's as early as possible. No functional change if no
> + microcode data is glued to the initrd, therefore it's safe to say Y.
> +
> config X86_MSR
> tristate "/dev/cpu/*/msr - Model-specific register support"
> ---help---


Paul Bolle

2012-08-21 20:05:37

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

> -----Original Message-----
> From: Borislav Petkov [mailto:[email protected]]
> Sent: Monday, August 20, 2012 1:20 PM
> To: H. Peter Anvin
> Cc: Yu, Fenghua; Henrique de Moraes Holschuh; Ingo Molnar; Thomas
> Gleixner; Mallick, Asit K; Tigran Aivazian; Andreas Herrmann; Borislav
> Petkov; linux-kernel; x86
> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
> interfaces for early load ucode
>
> On Mon, Aug 20, 2012 at 01:08:49PM -0700, H. Peter Anvin wrote:
> > On 08/20/2012 07:06 AM, Borislav Petkov wrote:
> > >
> > > Or,
> > >
> > > in case we want to supply more vendor-specific stuff early at boot,
> we
> > > could do:
> > >
> > > kernel/x86/<vendor>/microcode...
> > > |-> bios_overrides
> > > |-> ...
> > >
> > > and have this layout extensible from the beginning...
> > >
> > Does that make sense, though?
>
> Only time will tell. I was simply saying that we should leave ourselves
> the door opened, should we need functionality like that in the future.
>
> > I'm a bit concerned about having multiple files named microcode.bin
> by
> > default; the pathname isn't as sticky as the filename when people
> move
> > things around...
>
> Ok, I see.
>
> How about the following scheme then:
>
> kernel/x86/<vendor>-microcode.bin
> kernel/x86/<vendor>-bios-overrides.blob
> ...
>
> ?
>
> All I'm saying is maybe we should impose some sanity rules now before
> people go crazy with this and things get out of hands...

We might name the cpio directory as:

kernel/x86/microcode/GenuineIntel.bin
kernel/x86/microcode/AuthenticAMD.bin
kernel/x86/acpi/...
etc.

This is expendable for the future usage.

Plus I will add a doc on the cpio directory, supported directory names and how to add new stuffs in the directory.

Thanks.

-Fenghua


Thanks.

-Fenghua

2012-08-21 20:15:05

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On 08/21/2012 01:05 PM, Yu, Fenghua wrote:
>
> We might name the cpio directory as:
>
> kernel/x86/microcode/GenuineIntel.bin
> kernel/x86/microcode/AuthenticAMD.bin
> kernel/x86/acpi/...
> etc.
>
> This is expendable for the future usage.
>
> Plus I will add a doc on the cpio directory, supported directory names and how to add new stuffs in the directory.
>

I believe that was exactly my original proposal. I think it makes
sense... most things aren't going to be inherently CPU-specific in this way.

I don't know what Borislav was suggesting with "BIOS overrides", is that
another CPU-specific thing?

-hpa

2012-08-21 20:49:30

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On Tue, Aug 21, 2012 at 01:13:26PM -0700, H. Peter Anvin wrote:
> I don't know what Borislav was suggesting with "BIOS overrides", is
> that another CPU-specific thing?

Not CPU- but rather platform-specific. It is Thomas Renninger's
mechanism to override BIOS tables.

--
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551

2012-08-21 20:52:32

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

> -----Original Message-----
> From: Borislav Petkov [mailto:[email protected]]
> Sent: Tuesday, August 21, 2012 1:49 PM
> To: H. Peter Anvin
> Cc: Yu, Fenghua; Henrique de Moraes Holschuh; Ingo Molnar; Thomas
> Gleixner; Mallick, Asit K; Tigran Aivazian; Andreas Herrmann; Borislav
> Petkov; linux-kernel; x86
> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
> interfaces for early load ucode
>
> On Tue, Aug 21, 2012 at 01:13:26PM -0700, H. Peter Anvin wrote:
> > I don't know what Borislav was suggesting with "BIOS overrides", is
> > that another CPU-specific thing?
>
> Not CPU- but rather platform-specific. It is Thomas Renninger's
> mechanism to override BIOS tables.

That's ACPI override. I think the ACPI tables could be put in kernel/x86/acpi/.

Thanks.

-Fenghua

2012-08-21 20:52:47

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On 08/21/2012 01:48 PM, Borislav Petkov wrote:
> On Tue, Aug 21, 2012 at 01:13:26PM -0700, H. Peter Anvin wrote:
>> I don't know what Borislav was suggesting with "BIOS overrides", is
>> that another CPU-specific thing?
>
> Not CPU- but rather platform-specific. It is Thomas Renninger's
> mechanism to override BIOS tables.
>

s/BIOS/ACPI/... Yes, so really it doesn't have any meaningful reason to
live under the CPU vendor.

-hpa

2012-08-21 20:54:13

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

On 08/21/2012 01:52 PM, Yu, Fenghua wrote:
>> -----Original Message-----
>> From: Borislav Petkov [mailto:[email protected]]
>> Sent: Tuesday, August 21, 2012 1:49 PM
>> To: H. Peter Anvin
>> Cc: Yu, Fenghua; Henrique de Moraes Holschuh; Ingo Molnar; Thomas
>> Gleixner; Mallick, Asit K; Tigran Aivazian; Andreas Herrmann; Borislav
>> Petkov; linux-kernel; x86
>> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
>> interfaces for early load ucode
>>
>> On Tue, Aug 21, 2012 at 01:13:26PM -0700, H. Peter Anvin wrote:
>>> I don't know what Borislav was suggesting with "BIOS overrides", is
>>> that another CPU-specific thing?
>>
>> Not CPU- but rather platform-specific. It is Thomas Renninger's
>> mechanism to override BIOS tables.
>
> That's ACPI override. I think the ACPI tables could be put in kernel/x86/acpi/.
>

kernel/acpi... ACPI is not x86-specific.

-hpa

2012-08-21 20:58:15

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 04/11] x86/microcode_core_early.c: Define interfaces for early load ucode

> -----Original Message-----
> From: H. Peter Anvin [mailto:[email protected]]
> Sent: Tuesday, August 21, 2012 1:54 PM
> To: Yu, Fenghua
> Cc: Borislav Petkov; Henrique de Moraes Holschuh; Ingo Molnar; Thomas
> Gleixner; Mallick, Asit K; Tigran Aivazian; Andreas Herrmann; Borislav
> Petkov; linux-kernel; x86
> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
> interfaces for early load ucode
>
> On 08/21/2012 01:52 PM, Yu, Fenghua wrote:
> >> -----Original Message-----
> >> From: Borislav Petkov [mailto:[email protected]]
> >> Sent: Tuesday, August 21, 2012 1:49 PM
> >> To: H. Peter Anvin
> >> Cc: Yu, Fenghua; Henrique de Moraes Holschuh; Ingo Molnar; Thomas
> >> Gleixner; Mallick, Asit K; Tigran Aivazian; Andreas Herrmann;
> Borislav
> >> Petkov; linux-kernel; x86
> >> Subject: Re: [PATCH 04/11] x86/microcode_core_early.c: Define
> >> interfaces for early load ucode
> >>
> >> On Tue, Aug 21, 2012 at 01:13:26PM -0700, H. Peter Anvin wrote:
> >>> I don't know what Borislav was suggesting with "BIOS overrides", is
> >>> that another CPU-specific thing?
> >>
> >> Not CPU- but rather platform-specific. It is Thomas Renninger's
> >> mechanism to override BIOS tables.
> >
> > That's ACPI override. I think the ACPI tables could be put in
> kernel/x86/acpi/.
> >
>
> kernel/acpi... ACPI is not x86-specific.

That's right.

Thanks.

-Fenghua

2012-10-01 16:12:09

by Jamie Gloudon

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

Hey,

Any chance of this getting merge for the 3.7 cycle?

Regards,
Jamie Gloudon

2012-10-01 16:27:18

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
> Hey,
>
> Any chance of this getting merge for the 3.7 cycle?

It is not ready yet: http://marc.info/?l=linux-kernel&m=134910582107898

Out of curiosity: why do you nee it?

Thanks.

--
Regards/Gruss,
Boris.

2012-10-01 23:37:15

by Jamie Gloudon

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

Seems like a better alternative to microcode_ctl which some distros don't
contain.

Regards,
Jamie Gloudon

On Mon, Oct 01, 2012 at 06:27:45PM +0200, Borislav Petkov wrote:
> On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
> > Hey,
> >
> > Any chance of this getting merge for the 3.7 cycle?
>
> It is not ready yet: http://marc.info/?l=linux-kernel&m=134910582107898
>
> Out of curiosity: why do you nee it?
>
> Thanks.
>
> --
> Regards/Gruss,
> Boris.

2012-10-02 04:39:59

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Mon, Oct 01, 2012 at 07:37:04PM -0400, Jamie Gloudon wrote:
> On Mon, Oct 01, 2012 at 06:27:45PM +0200, Borislav Petkov wrote:
> > On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
> > > Hey,
> > >
> > > Any chance of this getting merge for the 3.7 cycle?
> >
> > It is not ready yet: http://marc.info/?l=linux-kernel&m=134910582107898
> >
> > Out of curiosity: why do you nee it?
> >
> Seems like a better alternative to microcode_ctl which some distros don't
> contain.

[ Let me reorganize the mail chain as it should be,
without top-posting. Please try not to top-post:
http://curl.haxx.se/mail/etiquette.html#Do_Not_Top_Post ]


Well,

if you want to reload your microcode, you shouldn't be needing
microcode_ctl (I believe this should be the case too on Intel, from
staring at the code - on AMD it works).

Basically, you simply put the microcode binaries into
/lib/firmware/{amd,intel}-ucode/ and then do as root:

$ echo 1 > /sys/devices/system/cpu/microcode/reload

That's it, no need for special tools.

--
Regards/Gruss,
Boris.

2012-10-02 06:07:06

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On 10/01/2012 09:27 AM, Borislav Petkov wrote:
> On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
>> Hey,
>>
>> Any chance of this getting merge for the 3.7 cycle?
>
> It is not ready yet: http://marc.info/?l=linux-kernel&m=134910582107898
>

Yes, Fenghua who has been working on it unfortunately got preempted at
an inopportune moment. It will get fixed.

-hpa


--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.

2012-10-02 13:11:46

by Jamie Gloudon

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Tue, Oct 02, 2012 at 06:39:54AM +0200, Borislav Petkov wrote:
> On Mon, Oct 01, 2012 at 07:37:04PM -0400, Jamie Gloudon wrote:
> > On Mon, Oct 01, 2012 at 06:27:45PM +0200, Borislav Petkov wrote:
> > > On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
> > > > Hey,
> > > >
> > > > Any chance of this getting merge for the 3.7 cycle?
> > >
> > > It is not ready yet: http://marc.info/?l=linux-kernel&m=134910582107898
> > >
> > > Out of curiosity: why do you nee it?
> > >
> > Seems like a better alternative to microcode_ctl which some distros don't
> > contain.
>
> [ Let me reorganize the mail chain as it should be,
> without top-posting. Please try not to top-post:
> http://curl.haxx.se/mail/etiquette.html#Do_Not_Top_Post ]
>
>
> Well,
>
> if you want to reload your microcode, you shouldn't be needing
> microcode_ctl (I believe this should be the case too on Intel, from
> staring at the code - on AMD it works).
>
> Basically, you simply put the microcode binaries into
> /lib/firmware/{amd,intel}-ucode/ and then do as root:
>
> $ echo 1 > /sys/devices/system/cpu/microcode/reload
>
> That's it, no need for special tools.
>
> --
> Regards/Gruss,
> Boris.

My main interest was getting PEBS events support for perf on Intel SNB cpus. Loading the microcode at runtime was not going to work.

However, thanks for pointing me in the right direction. I notice today this is not the case anymore from the thread below.

http://marc.info/?l=linux-kernel&m=133905353211963&w=2


Regards,
Jamie Gloudon

2012-10-02 13:45:34

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Tue, Oct 02, 2012 at 09:11:38AM -0400, Jamie Gloudon wrote:
> My main interest was getting PEBS events support for perf on Intel SNB
> cpus. Loading the microcode at runtime was not going to work.
>
> However, thanks for pointing me in the right direction. I notice today
> this is not the case anymore from the thread below.
>
> http://marc.info/?l=linux-kernel&m=133905353211963&w=2

Yes, there's a perf callback from within the ucode driver to recheck
PEBS. This is in 3.6 so PEBS should work there with the required ucode
patch.

--
Regards/Gruss,
Boris.

2012-10-02 19:00:08

by Konrad Rzeszutek Wilk

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Tue, Oct 2, 2012 at 2:06 AM, H. Peter Anvin <[email protected]> wrote:
> On 10/01/2012 09:27 AM, Borislav Petkov wrote:
>>
>> On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
>>>
>>> Hey,
>>>
>>> Any chance of this getting merge for the 3.7 cycle?
>>
>>
>> It is not ready yet: http://marc.info/?l=linux-kernel&m=134910582107898
>>
>
> Yes, Fenghua who has been working on it unfortunately got preempted at an
> inopportune moment. It will get fixed.


When he got interrupted did he have any beta patches to dracut that
could be posted?

2012-10-02 19:04:53

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH 00/11] x86/microcode: Early load microcode

> On Tue, Oct 2, 2012 at 2:06 AM, H. Peter Anvin <[email protected]> wrote:
> > On 10/01/2012 09:27 AM, Borislav Petkov wrote:
> >>
> >> On Mon, Oct 01, 2012 at 12:11:51PM -0400, Jamie Gloudon wrote:
> >>>
> >>> Hey,
> >>>
> >>> Any chance of this getting merge for the 3.7 cycle?
> >>
> >>
> >> It is not ready yet: http://marc.info/?l=linux-
> kernel&m=134910582107898
> >>
> >
> > Yes, Fenghua who has been working on it unfortunately got preempted
> at an
> > inopportune moment. It will get fixed.
>
>
> When he got interrupted did he have any beta patches to dracut that
> could be posted?

I'll post new patchset as soon as possible.

Thanks.

-Fenghua

2012-10-02 19:04:59

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On 10/02/2012 12:00 PM, Konrad Rzeszutek Wilk wrote:
>
> When he got interrupted did he have any beta patches to dracut that
> could be posted?
>

To *dracut*?

-hpa

2012-10-03 13:13:17

by Konrad Rzeszutek Wilk

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86/microcode: Early load microcode

On Tue, Oct 2, 2012 at 3:04 PM, H. Peter Anvin <[email protected]> wrote:
> On 10/02/2012 12:00 PM, Konrad Rzeszutek Wilk wrote:
>>
>> When he got interrupted did he have any beta patches to dracut that
>> could be posted?
>>
>
> To *dracut*?

The replacement for mkinitrd. You know the thing that creates your
initramfs.cpio.gz.