Skip to content

Commit ae76d95

Browse files
Ashok Rajbp3tk0v
authored andcommitted
x86/microcode/intel: Rip out mixed stepping support for Intel CPUs
Mixed steppings aren't supported on Intel CPUs. Only one microcode patch is required for the entire system. The caching of microcode blobs which match the family and model is therefore pointless and in fact is dysfunctional as CPU hotplug updates use only a single microcode blob, i.e. the one where *intel_ucode_patch points to. Remove the microcode cache and make it an AMD local feature. [ tglx: - save only at the end. Otherwise random microcode ends up in the pointer for early loading - free the ucode patch pointer in save_microcode_patch() only after kmemdup() has succeeded, as reported by Andrew Cooper ] Originally-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ashok Raj <ashok.raj@intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/20231017211722.404362809@linutronix.de
1 parent 0b62f6c commit ae76d95

4 files changed

Lines changed: 34 additions & 121 deletions

File tree

arch/x86/kernel/cpu/microcode/amd.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@
3737

3838
#include "internal.h"
3939

40+
struct ucode_patch {
41+
struct list_head plist;
42+
void *data;
43+
unsigned int size;
44+
u32 patch_id;
45+
u16 equiv_cpu;
46+
};
47+
48+
static LIST_HEAD(microcode_cache);
49+
4050
#define UCODE_MAGIC 0x00414d44
4151
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
4252
#define UCODE_UCODE_TYPE 0x00000001

arch/x86/kernel/cpu/microcode/core.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ static bool dis_ucode_ldr = true;
4646

4747
bool initrd_gone;
4848

49-
LIST_HEAD(microcode_cache);
50-
5149
/*
5250
* Synchronization.
5351
*

arch/x86/kernel/cpu/microcode/intel.c

Lines changed: 24 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@
3333
static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
3434

3535
/* Current microcode patch used in early patching on the APs. */
36-
static struct microcode_intel *intel_ucode_patch;
36+
static struct microcode_intel *intel_ucode_patch __read_mostly;
3737

3838
/* last level cache size per core */
39-
static int llc_size_per_core;
39+
static int llc_size_per_core __ro_after_init;
4040

4141
/* microcode format is extended from prescott processors */
4242
struct extended_signature {
@@ -253,74 +253,17 @@ static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev
253253
return intel_find_matching_signature(mc, csig, cpf);
254254
}
255255

256-
static struct ucode_patch *memdup_patch(void *data, unsigned int size)
256+
static void save_microcode_patch(void *data, unsigned int size)
257257
{
258-
struct ucode_patch *p;
259-
260-
p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL);
261-
if (!p)
262-
return NULL;
263-
264-
p->data = kmemdup(data, size, GFP_KERNEL);
265-
if (!p->data) {
266-
kfree(p);
267-
return NULL;
268-
}
269-
270-
return p;
271-
}
272-
273-
static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size)
274-
{
275-
struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
276-
struct ucode_patch *iter, *tmp, *p = NULL;
277-
bool prev_found = false;
278-
unsigned int sig, pf;
279-
280-
mc_hdr = (struct microcode_header_intel *)data;
281-
282-
list_for_each_entry_safe(iter, tmp, &microcode_cache, plist) {
283-
mc_saved_hdr = (struct microcode_header_intel *)iter->data;
284-
sig = mc_saved_hdr->sig;
285-
pf = mc_saved_hdr->pf;
286-
287-
if (intel_find_matching_signature(data, sig, pf)) {
288-
prev_found = true;
289-
290-
if (mc_hdr->rev <= mc_saved_hdr->rev)
291-
continue;
292-
293-
p = memdup_patch(data, size);
294-
if (!p)
295-
pr_err("Error allocating buffer %p\n", data);
296-
else {
297-
list_replace(&iter->plist, &p->plist);
298-
kfree(iter->data);
299-
kfree(iter);
300-
}
301-
}
302-
}
303-
304-
/*
305-
* There weren't any previous patches found in the list cache; save the
306-
* newly found.
307-
*/
308-
if (!prev_found) {
309-
p = memdup_patch(data, size);
310-
if (!p)
311-
pr_err("Error allocating buffer for %p\n", data);
312-
else
313-
list_add_tail(&p->plist, &microcode_cache);
314-
}
258+
struct microcode_header_intel *p;
315259

260+
p = kmemdup(data, size, GFP_KERNEL);
316261
if (!p)
317262
return;
318263

319-
if (!intel_find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
320-
return;
321-
264+
kfree(intel_ucode_patch);
322265
/* Save for early loading */
323-
intel_ucode_patch = p->data;
266+
intel_ucode_patch = (struct microcode_intel *)p;
324267
}
325268

326269
/*
@@ -332,6 +275,7 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
332275
{
333276
struct microcode_header_intel *mc_header;
334277
struct microcode_intel *patch = NULL;
278+
u32 cur_rev = uci->cpu_sig.rev;
335279
unsigned int mc_size;
336280

337281
while (size) {
@@ -341,8 +285,7 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
341285
mc_header = (struct microcode_header_intel *)data;
342286

343287
mc_size = get_totalsize(mc_header);
344-
if (!mc_size ||
345-
mc_size > size ||
288+
if (!mc_size || mc_size > size ||
346289
intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0)
347290
break;
348291

@@ -354,31 +297,16 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
354297
continue;
355298
}
356299

357-
if (save) {
358-
save_microcode_patch(uci, data, mc_size);
300+
/* BSP scan: Check whether there is newer microcode */
301+
if (!save && cur_rev >= mc_header->rev)
359302
goto next;
360-
}
361-
362-
363-
if (!patch) {
364-
if (!has_newer_microcode(data,
365-
uci->cpu_sig.sig,
366-
uci->cpu_sig.pf,
367-
uci->cpu_sig.rev))
368-
goto next;
369303

370-
} else {
371-
struct microcode_header_intel *phdr = &patch->hdr;
372-
373-
if (!has_newer_microcode(data,
374-
phdr->sig,
375-
phdr->pf,
376-
phdr->rev))
377-
goto next;
378-
}
304+
/* Save scan: Check whether there is newer or matching microcode */
305+
if (save && cur_rev != mc_header->rev)
306+
goto next;
379307

380-
/* We have a newer patch, save it. */
381308
patch = data;
309+
cur_rev = mc_header->rev;
382310

383311
next:
384312
data += mc_size;
@@ -387,6 +315,9 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
387315
if (size)
388316
return NULL;
389317

318+
if (save && patch)
319+
save_microcode_patch(patch, mc_size);
320+
390321
return patch;
391322
}
392323

@@ -528,26 +459,10 @@ void load_ucode_intel_ap(void)
528459
apply_microcode_early(&uci);
529460
}
530461

531-
static struct microcode_intel *find_patch(struct ucode_cpu_info *uci)
462+
/* Accessor for microcode pointer */
463+
static struct microcode_intel *ucode_get_patch(void)
532464
{
533-
struct microcode_header_intel *phdr;
534-
struct ucode_patch *iter, *tmp;
535-
536-
list_for_each_entry_safe(iter, tmp, &microcode_cache, plist) {
537-
538-
phdr = (struct microcode_header_intel *)iter->data;
539-
540-
if (phdr->rev <= uci->cpu_sig.rev)
541-
continue;
542-
543-
if (!intel_find_matching_signature(phdr,
544-
uci->cpu_sig.sig,
545-
uci->cpu_sig.pf))
546-
continue;
547-
548-
return iter->data;
549-
}
550-
return NULL;
465+
return intel_ucode_patch;
551466
}
552467

553468
void reload_ucode_intel(void)
@@ -557,7 +472,7 @@ void reload_ucode_intel(void)
557472

558473
intel_cpu_collect_info(&uci);
559474

560-
p = find_patch(&uci);
475+
p = ucode_get_patch();
561476
if (!p)
562477
return;
563478

@@ -601,7 +516,7 @@ static enum ucode_state apply_microcode_intel(int cpu)
601516
return UCODE_ERROR;
602517

603518
/* Look for a newer patch in our cache: */
604-
mc = find_patch(uci);
519+
mc = ucode_get_patch();
605520
if (!mc) {
606521
mc = uci->mc;
607522
if (!mc)
@@ -730,7 +645,7 @@ static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
730645
uci->mc = (struct microcode_intel *)new_mc;
731646

732647
/* Save for CPU hotplug */
733-
save_microcode_patch(uci, new_mc, new_mc_size);
648+
save_microcode_patch(new_mc, new_mc_size);
734649

735650
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
736651
cpu, new_rev, uci->cpu_sig.rev);

arch/x86/kernel/cpu/microcode/internal.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,6 @@
88
#include <asm/cpu.h>
99
#include <asm/microcode.h>
1010

11-
struct ucode_patch {
12-
struct list_head plist;
13-
void *data; /* Intel uses only this one */
14-
unsigned int size;
15-
u32 patch_id;
16-
u16 equiv_cpu;
17-
};
18-
19-
extern struct list_head microcode_cache;
20-
2111
struct device;
2212

2313
enum ucode_state {

0 commit comments

Comments
 (0)