From: Simon Glass Date: Sat, 12 Mar 2016 05:06:54 +0000 (-0700) Subject: x86: Move microcode code to a common location X-Git-Tag: v2016.05-rc1~297 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=9e66506d33eac67bfa814ccba1c9ccd06bb5b107;p=u-boot x86: Move microcode code to a common location This code is used on several Intel CPUs. Move it into a common location. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 5dd95739a0..ca4e171d20 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -5,3 +5,6 @@ # obj-$(CONFIG_HAVE_MRC) += car.o +ifndef CONFIG_TARGET_EFI +obj-y += microcode.o +endif diff --git a/arch/x86/cpu/intel_common/car.S b/arch/x86/cpu/intel_common/car.S index 1defabf91f..81ac976ddd 100644 --- a/arch/x86/cpu/intel_common/car.S +++ b/arch/x86/cpu/intel_common/car.S @@ -12,12 +12,12 @@ */ #include +#include #include #include #include #include #include -#include #define MTRR_PHYS_BASE_MSR(reg) (0x200 + 2 * (reg)) #define MTRR_PHYS_MASK_MSR(reg) (0x200 + 2 * (reg) + 1) diff --git a/arch/x86/cpu/intel_common/microcode.c b/arch/x86/cpu/intel_common/microcode.c new file mode 100644 index 0000000000..3054fabfde --- /dev/null +++ b/arch/x86/cpu/intel_common/microcode.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2014 Google, Inc + * Copyright (C) 2000 Ronald G. Minnich + * + * Microcode update for Intel PIII and later CPUs + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/** + * struct microcode_update - standard microcode header from Intel + * + * We read this information out of the device tree and use it to determine + * whether the update is applicable or not. We also use the same structure + * to read information from the CPU. + */ +struct microcode_update { + uint header_version; + uint update_revision; + uint date_code; + uint processor_signature; + uint checksum; + uint loader_revision; + uint processor_flags; + const void *data; + int size; +}; + +static int microcode_decode_node(const void *blob, int node, + struct microcode_update *update) +{ + update->data = fdt_getprop(blob, node, "data", &update->size); + if (!update->data) + return -EINVAL; + update->data += UCODE_HEADER_LEN; + update->size -= UCODE_HEADER_LEN; + + update->header_version = fdtdec_get_int(blob, node, + "intel,header-version", 0); + update->update_revision = fdtdec_get_int(blob, node, + "intel,update-revision", 0); + update->date_code = fdtdec_get_int(blob, node, + "intel,date-code", 0); + update->processor_signature = fdtdec_get_int(blob, node, + "intel,processor-signature", 0); + update->checksum = fdtdec_get_int(blob, node, "intel,checksum", 0); + update->loader_revision = fdtdec_get_int(blob, node, + "intel,loader-revision", 0); + update->processor_flags = fdtdec_get_int(blob, node, + "intel,processor-flags", 0); + + return 0; +} + +static inline uint32_t microcode_read_rev(void) +{ + /* + * Some Intel CPUs can be very finicky about the CPUID sequence used. + * So this is implemented in assembly so that it works reliably. + */ + uint32_t low, high; + + asm volatile ( + "xorl %%eax, %%eax\n" + "xorl %%edx, %%edx\n" + "movl %2, %%ecx\n" + "wrmsr\n" + "movl $0x01, %%eax\n" + "cpuid\n" + "movl %2, %%ecx\n" + "rdmsr\n" + : /* outputs */ + "=a" (low), "=d" (high) + : /* inputs */ + "i" (MSR_IA32_UCODE_REV) + : /* clobbers */ + "ebx", "ecx" + ); + + return high; +} + +static void microcode_read_cpu(struct microcode_update *cpu) +{ + /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */ + unsigned int x86_model, x86_family; + struct cpuid_result result; + uint32_t low, high; + + wrmsr(MSR_IA32_UCODE_REV, 0, 0); + result = cpuid(1); + rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision); + x86_model = (result.eax >> 4) & 0x0f; + x86_family = (result.eax >> 8) & 0x0f; + cpu->processor_signature = result.eax; + + cpu->processor_flags = 0; + if ((x86_model >= 5) || (x86_family > 6)) { + rdmsr(0x17, low, high); + cpu->processor_flags = 1 << ((high >> 18) & 7); + } + debug("microcode: sig=%#x pf=%#x revision=%#x\n", + cpu->processor_signature, cpu->processor_flags, + cpu->update_revision); +} + +/* Get a microcode update from the device tree and apply it */ +int microcode_update_intel(void) +{ + struct microcode_update cpu, update; + const void *blob = gd->fdt_blob; + int skipped; + int count; + int node; + int ret; + int rev; + + microcode_read_cpu(&cpu); + node = 0; + count = 0; + skipped = 0; + do { + node = fdtdec_next_compatible(blob, node, + COMPAT_INTEL_MICROCODE); + if (node < 0) { + debug("%s: Found %d updates\n", __func__, count); + return count ? 0 : skipped ? -EEXIST : -ENOENT; + } + + ret = microcode_decode_node(blob, node, &update); + if (ret) { + debug("%s: Unable to decode update: %d\n", __func__, + ret); + return ret; + } + if (!(update.processor_signature == cpu.processor_signature && + (update.processor_flags & cpu.processor_flags))) { + debug("%s: Skipping non-matching update, sig=%x, pf=%x\n", + __func__, update.processor_signature, + update.processor_flags); + skipped++; + continue; + } + wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0); + rev = microcode_read_rev(); + debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n", + rev, update.date_code & 0xffff, + (update.date_code >> 24) & 0xff, + (update.date_code >> 16) & 0xff); + if (update.update_revision != rev) { + printf("Microcode update failed\n"); + return -EFAULT; + } + count++; + } while (1); +} diff --git a/arch/x86/cpu/ivybridge/Makefile b/arch/x86/cpu/ivybridge/Makefile index b117f0deb2..78006f12b3 100644 --- a/arch/x86/cpu/ivybridge/Makefile +++ b/arch/x86/cpu/ivybridge/Makefile @@ -13,7 +13,6 @@ obj-y += gma.o obj-y += lpc.o obj-y += me_status.o obj-y += model_206ax.o -obj-y += microcode_intel.o obj-y += northbridge.o obj-y += report_platform.o obj-y += sata.o diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c index 5d839a7e1b..f0e733bc33 100644 --- a/arch/x86/cpu/ivybridge/cpu.c +++ b/arch/x86/cpu/ivybridge/cpu.c @@ -19,13 +19,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include diff --git a/arch/x86/cpu/ivybridge/microcode_intel.c b/arch/x86/cpu/ivybridge/microcode_intel.c deleted file mode 100644 index 2440a97c48..0000000000 --- a/arch/x86/cpu/ivybridge/microcode_intel.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2014 Google, Inc - * Copyright (C) 2000 Ronald G. Minnich - * - * Microcode update for Intel PIII and later CPUs - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * struct microcode_update - standard microcode header from Intel - * - * We read this information out of the device tree and use it to determine - * whether the update is applicable or not. We also use the same structure - * to read information from the CPU. - */ -struct microcode_update { - uint header_version; - uint update_revision; - uint date_code; - uint processor_signature; - uint checksum; - uint loader_revision; - uint processor_flags; - const void *data; - int size; -}; - -static int microcode_decode_node(const void *blob, int node, - struct microcode_update *update) -{ - update->data = fdt_getprop(blob, node, "data", &update->size); - if (!update->data) - return -EINVAL; - update->data += UCODE_HEADER_LEN; - update->size -= UCODE_HEADER_LEN; - - update->header_version = fdtdec_get_int(blob, node, - "intel,header-version", 0); - update->update_revision = fdtdec_get_int(blob, node, - "intel,update-revision", 0); - update->date_code = fdtdec_get_int(blob, node, - "intel,date-code", 0); - update->processor_signature = fdtdec_get_int(blob, node, - "intel,processor-signature", 0); - update->checksum = fdtdec_get_int(blob, node, "intel,checksum", 0); - update->loader_revision = fdtdec_get_int(blob, node, - "intel,loader-revision", 0); - update->processor_flags = fdtdec_get_int(blob, node, - "intel,processor-flags", 0); - - return 0; -} - -static inline uint32_t microcode_read_rev(void) -{ - /* - * Some Intel CPUs can be very finicky about the CPUID sequence used. - * So this is implemented in assembly so that it works reliably. - */ - uint32_t low, high; - - asm volatile ( - "xorl %%eax, %%eax\n" - "xorl %%edx, %%edx\n" - "movl %2, %%ecx\n" - "wrmsr\n" - "movl $0x01, %%eax\n" - "cpuid\n" - "movl %2, %%ecx\n" - "rdmsr\n" - : /* outputs */ - "=a" (low), "=d" (high) - : /* inputs */ - "i" (MSR_IA32_UCODE_REV) - : /* clobbers */ - "ebx", "ecx" - ); - - return high; -} - -static void microcode_read_cpu(struct microcode_update *cpu) -{ - /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */ - unsigned int x86_model, x86_family; - struct cpuid_result result; - uint32_t low, high; - - wrmsr(MSR_IA32_UCODE_REV, 0, 0); - result = cpuid(1); - rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision); - x86_model = (result.eax >> 4) & 0x0f; - x86_family = (result.eax >> 8) & 0x0f; - cpu->processor_signature = result.eax; - - cpu->processor_flags = 0; - if ((x86_model >= 5) || (x86_family > 6)) { - rdmsr(0x17, low, high); - cpu->processor_flags = 1 << ((high >> 18) & 7); - } - debug("microcode: sig=%#x pf=%#x revision=%#x\n", - cpu->processor_signature, cpu->processor_flags, - cpu->update_revision); -} - -/* Get a microcode update from the device tree and apply it */ -int microcode_update_intel(void) -{ - struct microcode_update cpu, update; - const void *blob = gd->fdt_blob; - int skipped; - int count; - int node; - int ret; - int rev; - - microcode_read_cpu(&cpu); - node = 0; - count = 0; - skipped = 0; - do { - node = fdtdec_next_compatible(blob, node, - COMPAT_INTEL_MICROCODE); - if (node < 0) { - debug("%s: Found %d updates\n", __func__, count); - return count ? 0 : skipped ? -EEXIST : -ENOENT; - } - - ret = microcode_decode_node(blob, node, &update); - if (ret) { - debug("%s: Unable to decode update: %d\n", __func__, - ret); - return ret; - } - if (!(update.processor_signature == cpu.processor_signature && - (update.processor_flags & cpu.processor_flags))) { - debug("%s: Skipping non-matching update, sig=%x, pf=%x\n", - __func__, update.processor_signature, - update.processor_flags); - skipped++; - continue; - } - wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0); - rev = microcode_read_rev(); - debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n", - rev, update.date_code & 0xffff, - (update.date_code >> 24) & 0xff, - (update.date_code >> 16) & 0xff); - if (update.update_revision != rev) { - printf("Microcode update failed\n"); - return -EFAULT; - } - count++; - } while (1); -} diff --git a/arch/x86/include/asm/arch-ivybridge/microcode.h b/arch/x86/include/asm/arch-ivybridge/microcode.h deleted file mode 100644 index 67f32cc38f..0000000000 --- a/arch/x86/include/asm/arch-ivybridge/microcode.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2015 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __ASM_ARCH_MICROCODE_H -#define __ASM_ARCH_MICROCODE_H - -#ifndef __ASSEMBLY__ - -/** - * microcode_update_intel() - Apply microcode updates - * - * Applies any microcode updates in the device tree. - * - * @return 0 if OK, -EEXIST if the updates were already applied, -ENOENT if - * not updates were found, -EINVAL if an update was invalid - */ -int microcode_update_intel(void); -#endif /* __ASSEMBLY__ */ - -#endif diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h new file mode 100644 index 0000000000..67f32cc38f --- /dev/null +++ b/arch/x86/include/asm/microcode.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_ARCH_MICROCODE_H +#define __ASM_ARCH_MICROCODE_H + +#ifndef __ASSEMBLY__ + +/** + * microcode_update_intel() - Apply microcode updates + * + * Applies any microcode updates in the device tree. + * + * @return 0 if OK, -EEXIST if the updates were already applied, -ENOENT if + * not updates were found, -EINVAL if an update was invalid + */ +int microcode_update_intel(void); +#endif /* __ASSEMBLY__ */ + +#endif