-
Notifications
You must be signed in to change notification settings - Fork 60
/
0124-x86-microcode-Add-an-option-to-reload-microcode-even.patch
173 lines (146 loc) · 5.01 KB
/
0124-x86-microcode-Add-an-option-to-reload-microcode-even.patch
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ashok Raj <[email protected]>
Date: Thu, 19 Aug 2021 14:49:47 -0700
Subject: [PATCH] x86/microcode: Add an option to reload microcode even if
revision is the same
This is POC to support rollback. This is a simple version, admin uses
echo 2 instead of echo 1 to reload. We don't do the version checks.
#echo 1 > /sys/devices/system/cpu/microcode/reload
The following usage, writing 2 to reload file is helpful to reload
the microcode again even if the revision is less than what is loaded.
#echo 2 > /sys/devices/system/cpu/microcode/reload
Signed-off-by: Ashok Raj <[email protected]>
---
arch/x86/kernel/cpu/microcode/core.c | 40 ++++++++++++++++++++++++++-
arch/x86/kernel/cpu/microcode/intel.c | 14 ++++++----
2 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 239ff5fcec6a..b096a43b2b9d 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -44,6 +44,8 @@
static struct microcode_ops *microcode_ops;
static bool dis_ucode_ldr = true;
+bool ucode_rollback = false;
+int enable_rollback = 0;
bool initrd_gone;
@@ -80,6 +82,26 @@ static u32 final_levels[] = {
0, /* T-101 terminator */
};
+static int __init ucode_setup(char *str)
+{
+ if (!str)
+ return -EINVAL;
+
+ while (*str) {
+ if (!strncmp(str, "rollback", 8)) {
+ enable_rollback = 1;
+ pr_info("Microcode Rollback Enabled\n");
+ }
+ str += strcspn(str, ",");
+ while (*str == ',')
+ str++;
+ }
+ return 0;
+}
+
+__setup("ucode=", ucode_setup);
+
+
/*
* Check the current patch level on this CPU.
*
@@ -600,6 +622,7 @@ static ssize_t reload_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
enum ucode_state tmp_ret = UCODE_OK;
int bsp = boot_cpu_data.cpu_index;
unsigned long val;
@@ -609,7 +632,7 @@ static ssize_t reload_store(struct device *dev,
if (ret)
return ret;
- if (val != 1)
+ if (!val || val > 2)
return size;
cpus_read_lock();
@@ -617,6 +640,20 @@ static ssize_t reload_store(struct device *dev,
ret = check_online_cpus();
if (ret)
goto put;
+ /*
+ * Check if the vendor is Intel to permit reloading
+ * microcode even if the revision is unchanged.
+ * This is typically used during development of microcode
+ * and changing rev is a pain.
+ */
+ if ((val == 2) && ((c->x86_vendor != X86_VENDOR_INTEL) ||
+ !enable_rollback))
+ return size;
+ else if (val == 2) {
+ mutex_lock(µcode_mutex);
+ ucode_rollback = true;
+ mutex_unlock(µcode_mutex);
+ }
tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true);
if (tmp_ret != UCODE_NEW)
@@ -627,6 +664,7 @@ static ssize_t reload_store(struct device *dev,
mutex_unlock(µcode_mutex);
put:
+ ucode_rollback = false;
cpus_read_unlock();
if (ret == 0)
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index d28a9f8f3fec..02b506f52a13 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -44,6 +44,7 @@ static struct microcode_intel *intel_ucode_patch;
/* last level cache size per core */
static int llc_size_per_core;
+extern bool ucode_rollback;
static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1,
unsigned int s2, unsigned int p2)
@@ -94,7 +95,7 @@ static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev
{
struct microcode_header_intel *mc_hdr = mc;
- if (mc_hdr->rev <= new_rev)
+ if (!ucode_rollback && mc_hdr->rev <= new_rev)
return 0;
return find_matching_signature(mc, csig, cpf);
@@ -134,7 +135,7 @@ static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigne
if (find_matching_signature(data, sig, pf)) {
prev_found = true;
- if (mc_hdr->rev <= mc_saved_hdr->rev)
+ if (!ucode_rollback && mc_hdr->rev <= mc_saved_hdr->rev)
continue;
p = memdup_patch(data, size);
@@ -694,7 +695,7 @@ static struct microcode_intel *find_patch(struct ucode_cpu_info *uci)
phdr = (struct microcode_header_intel *)iter->data;
- if (phdr->rev <= uci->cpu_sig.rev)
+ if (!ucode_rollback && phdr->rev <= uci->cpu_sig.rev)
continue;
if (!find_matching_signature(phdr,
@@ -779,10 +780,11 @@ static enum ucode_state apply_microcode_intel(int cpu)
* already.
*/
rev = intel_get_microcode_revision();
- if (rev >= mc->hdr.rev) {
+ if (!ucode_rollback && rev >= mc->hdr.rev) {
ret = UCODE_OK;
goto out;
- }
+ } else if (ucode_rollback)
+ ret = UCODE_OK;
/*
* Writeback and invalidate caches before updating microcode to avoid
@@ -801,7 +803,7 @@ static enum ucode_state apply_microcode_intel(int cpu)
return UCODE_ERROR;
}
- if (bsp && rev != prev_rev) {
+ if (bsp && ((rev != prev_rev) || ucode_rollback)) {
pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n",
rev,
mc->hdr.date & 0xffff,
--
https://clearlinux.org