1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 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>
#define CBFS_FILE_MAGIC 0
#define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8)
#define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4)
#define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4)
#define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4)
#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 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
/* Processor family+model signature=cpuid_eax(1) */
movl %eax, %ebx
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 */
test PROCESSOR_FLAG(%esi), %ebp
jz 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:
|