summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Heymans <arthur@aheymans.xyz>2018-06-13 15:54:35 +0200
committerKyösti Mälkki <kyosti.malkki@gmail.com>2018-12-31 21:36:02 +0000
commit2e658f8edf2f6b08f160297c0300103f5367ac3e (patch)
tree19d9ebddbc89ff66a44ce7ff0b967231da61b5aa
parent2d324cafd84c18256221894fd14954a80e52f43a (diff)
src/cpu/microcode: Add code to update microcode in assembly
Add code to update microcode from cbfsfiles using assembly. Change-Id: I8bd192f3f345651db0010239f99293ae63b00652 Signed-off-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-on: https://review.coreboot.org/c/27091 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Rudolph <siro@das-labor.org> Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
-rw-r--r--src/cpu/intel/microcode/microcode_asm.S162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/cpu/intel/microcode/microcode_asm.S b/src/cpu/intel/microcode/microcode_asm.S
new file mode 100644
index 0000000000..ef85760269
--- /dev/null
+++ b/src/cpu/intel/microcode/microcode_asm.S
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2018 Arthur Heymans <arthur@aheymans.xyz>
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * input %esp: return address (not pointer to return address!)
+ * clobber the content of eax, ebx, ecx, edx, esi, edi, and ebp
+ */
+
+#include <cpu/x86/post_code.h>
+#include <cpu/x86/msr.h>
+#include <arch/x86/walkcbfs.S>
+
+#define HEADER_VER_OFFSET 0
+#define UPDATE_VER_OFFSET 4
+#define DATE_OFFSET 8
+#define PROCESSOR_SIG_OFFSET 12
+#define CHKSUM_OFFSET 16
+#define LOADER_REV_OFFSET 20
+#define PROCESSOR_FLAG 24
+#define DATA_SIZE_OFFSET 28
+#define TOTAL_OFFSET 32
+#define HEADER_SIZE 48
+
+/*
+ * The microcode header is 48 bytes wide and has the following
+ * structure:
+ * Header Version : 32bit
+ * Update Revision : 32bit
+ * Date : 32bit
+ * Processor Signature : 32bit
+ * Checksum : 32bit
+ * Loader Revision : 32bit
+ * Processor Flags : 32bit
+ * Data Size : 32bit
+ * Total Size : 32bit
+ * Reserved : 96bit
+ *
+ * We only check if the Processor signature and flags match and check
+ * if the revision of the update is newer than what is installed
+ */
+
+.section .text
+.global update_bsp_microcode
+
+update_bsp_microcode:
+ /* Keep return address */
+ movl %esp, %edx
+ /* find microcodes in cbfs */
+ leal microcode_name, %esi
+ movl $1f, %esp
+ jmp walkcbfs_asm
+
+1:
+ /* restore return address */
+ movl %edx, %esp
+
+ cmpl $0, %eax
+ je end_microcode_update
+ movl CBFS_FILE_OFFSET(%eax), %ebx
+ bswap %ebx
+ addl %eax, %ebx
+ movl %ebx, %esi
+
+ movl CBFS_FILE_LEN(%eax), %edi
+ bswap %edi
+ addl %esi, %edi
+
+ /*
+ * Microcode revision -> %ebx
+ * Processor flags -> %ebp
+ * Current installed microcode revision -> %edx
+ */
+
+ /* Processor family+model signature=cpuid_eax(1) */
+ movl $1, %eax
+ cpuid
+ movl %eax, %ebx
+
+ /* Processor flags
+ * rdmsr 0x17
+ * pf = 1 << ((msr.hi >> 18) & 7) */
+ movl $IA32_PLATFORM_ID, %ecx
+ rdmsr
+ shr $18, %edx
+ andl $7, %edx
+ movl $1, %eax
+ /* needs to be %cl for shl */
+ movl %edx, %ecx
+ shl %cl, %eax
+ movl %eax, %ebp
+
+ /* Fetch the current microcode revision*/
+ xorl %eax, %eax
+ xorl %edx, %edx
+ movl $IA32_BIOS_SIGN_ID, %ecx
+ wrmsr
+ movl $0x1, %eax
+ cpuid
+ movl $IA32_BIOS_SIGN_ID, %ecx
+ rdmsr
+
+check_microcode_entry:
+ /* Test if header revision is non zero */
+ cmpl $0, HEADER_VER_OFFSET(%esi)
+ je end_microcode_update
+
+ /* Processor family+model signature=cpuid_eax(1) */
+ cmpl PROCESSOR_SIG_OFFSET(%esi), %ebx
+ jne next_entry
+
+ /* Processor flags */
+ cmpl PROCESSOR_FLAG(%esi), %ebp
+ jne next_entry
+
+ /* Check if revision is higher than current */
+ cmpl UPDATE_VER_OFFSET(%esi), %edx
+ /* Don't upgrade if already greater or equal */
+ jge end_microcode_update
+
+ /* Do actual update */
+ movl %esi, %eax
+ addl $HEADER_SIZE, %eax
+ xorl %edx, %edx
+ movl $IA32_BIOS_UPDT_TRIG, %ecx
+ wrmsr
+
+ jmp end_microcode_update
+
+next_entry:
+ movl TOTAL_OFFSET(%esi), %eax
+ cmpl $0, %eax
+ jne 1f
+ /* Newer microcode updates include a size field, whereas older
+ * containers set it at 0 and are exactly 2048 bytes long */
+ addl $2048, %esi
+ jmp check_end
+1:
+ addl %eax, %esi
+
+check_end:
+ cmpl %esi, %edi
+ ja check_microcode_entry
+
+end_microcode_update:
+ jmp *%esp
+
+microcode_name:
+ .string "cpu_microcode_blob.bin"
+
+_update_bsp_microcode_end: