xref: /aosp_15_r20/external/coreboot/src/cpu/intel/microcode/microcode_asm.S (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1/* SPDX-License-Identifier: GPL-2.0-only */
2
3/*
4 * input %esp: return address (not pointer to return address!)
5 * clobber the content of eax, ebx, ecx, edx, esi, edi, and ebp
6 */
7
8#include <cpu/x86/post_code.h>
9#include <cpu/x86/msr.h>
10
11#define CBFS_FILE_MAGIC 0
12#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8)
13#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4)
14#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4)
15#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4)
16
17#define HEADER_VER_OFFSET 0
18#define UPDATE_VER_OFFSET 4
19#define DATE_OFFSET 8
20#define PROCESSOR_SIG_OFFSET 12
21#define CHKSUM_OFFSET 16
22#define LOADER_REV_OFFSET 20
23#define PROCESSOR_FLAG 24
24#define DATA_SIZE_OFFSET 28
25#define TOTAL_OFFSET 32
26#define HEADER_SIZE 48
27
28/*
29 * The microcode header is 48 bytes wide and has the following
30 * structure:
31 *   Header Version      : 32bit
32 *   Update Revision     : 32bit
33 *   Date                : 32bit
34 *   Processor Signature : 32bit
35 *   Checksum            : 32bit
36 *   Loader Revision     : 32bit
37 *   Processor Flags     : 32bit
38 *   Data Size           : 32bit
39 *   Total Size          : 32bit
40 *   Reserved            : 96bit
41 *
42 * We only check if the Processor signature and flags match and check
43 * if the revision of the update is newer than what is installed
44 */
45
46.code32
47.section .init
48.global update_bsp_microcode
49
50update_bsp_microcode:
51	/* Keep return address */
52	movl	%esp, %edx
53	/* find microcodes in cbfs */
54	leal	microcode_name, %esi
55	movl	$1f, %esp
56	jmp	walkcbfs_asm
57
581:
59	/* restore return address */
60	movl	%edx, %esp
61
62	cmpl	$0, %eax
63	je	end_microcode_update
64	movl	CBFS_FILE_OFFSET(%eax), %ebx
65	bswap	%ebx
66	addl	%eax, %ebx
67	movl	%ebx, %esi
68
69	movl	CBFS_FILE_LEN(%eax), %edi
70	bswap	%edi
71	addl	%esi, %edi
72
73	/*
74	 * Microcode revision -> %ebx
75	 * Processor flags -> %ebp
76	 * Current installed microcode revision -> %edx
77	 */
78
79	/* Processor flags
80	 * rdmsr 0x17
81	 * pf = 1 << ((msr.hi >> 18) & 7) */
82	movl	$IA32_PLATFORM_ID, %ecx
83	rdmsr
84	shr	$18, %edx
85	andl	$7, %edx
86	movl	$1, %eax
87	/* needs to be %cl for shl */
88	movl	%edx, %ecx
89	shl	%cl, %eax
90	movl	%eax, %ebp
91
92	/* Fetch the current microcode revision*/
93	xorl	%eax, %eax
94	xorl	%edx, %edx
95	movl	$IA32_BIOS_SIGN_ID, %ecx
96	wrmsr
97	movl	$0x1, %eax
98	cpuid
99
100	/* Processor family+model signature=cpuid_eax(1) */
101	movl	%eax, %ebx
102
103	movl	$IA32_BIOS_SIGN_ID, %ecx
104	rdmsr
105
106check_microcode_entry:
107	/* Test if header revision is non zero */
108	cmpl	$0, HEADER_VER_OFFSET(%esi)
109	je	end_microcode_update
110
111	/* Processor family+model signature=cpuid_eax(1) */
112	cmpl	PROCESSOR_SIG_OFFSET(%esi), %ebx
113	jne	next_entry
114
115	/* Processor flags */
116	test	PROCESSOR_FLAG(%esi), %ebp
117	jz	next_entry
118
119	/* Check if revision is higher than current */
120	cmpl	UPDATE_VER_OFFSET(%esi), %edx
121	/* Don't upgrade if already greater or equal */
122	jge	end_microcode_update
123
124	/* Do actual update */
125	movl	%esi, %eax
126	addl	$HEADER_SIZE, %eax
127	xorl	%edx, %edx
128	movl	$IA32_BIOS_UPDT_TRIG, %ecx
129	wrmsr
130
131	jmp	end_microcode_update
132
133next_entry:
134	movl	TOTAL_OFFSET(%esi), %eax
135	cmpl	$0, %eax
136	jne	1f
137	/* Newer microcode updates include a size field, whereas older
138	 * containers set it at 0 and are exactly 2048 bytes long */
139	addl	$2048, %esi
140	jmp	check_end
1411:
142	addl	%eax, %esi
143
144check_end:
145	cmpl	%esi, %edi
146	ja	check_microcode_entry
147
148end_microcode_update:
149	jmp	*%esp
150
151microcode_name:
152	.string	"cpu_microcode_blob.bin"
153
154_update_bsp_microcode_end:
155