Skip to content

Commit dd5e3e3

Browse files
KAGA-KOKObp3tk0v
authored andcommitted
x86/microcode/intel: Simplify early loading
The early loading code is overly complicated: - It scans the builtin/initrd for microcode not only on the BSP, but also on all APs during early boot and then later in the boot process it scans again to duplicate and save the microcode before initrd goes away. That's a pointless exercise because this can be simply done before bringing up the APs when the memory allocator is up and running. - Saving the microcode from within the scan loop is completely non-obvious and a left over of the microcode cache. This can be done at the call site now which makes it obvious. Rework the code so that only the BSP scans the builtin/initrd microcode once during early boot and save it away in an early initcall for later use. [ bp: Test and fold in a fix from tglx ontop which handles the need to distinguish what save_microcode() does depending on when it is called: - when on the BSP during early load, it needs to find a newer revision than the one currently loaded on the BSP - later, before SMP init, it still runs on the BSP and gets the BSP revision just loaded and uses that revision to know which patch to save for the APs. For that it needs to find the exact one as on the BSP. ] Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/20231017211722.629085215@linutronix.de
1 parent 0177669 commit dd5e3e3

3 files changed

Lines changed: 79 additions & 93 deletions

File tree

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
#define DRIVER_VERSION "2.2"
4343

4444
static struct microcode_ops *microcode_ops;
45-
static bool dis_ucode_ldr = true;
45+
bool dis_ucode_ldr = true;
4646

4747
bool initrd_gone;
4848

@@ -186,10 +186,6 @@ static int __init save_microcode_in_initrd(void)
186186
int ret = -EINVAL;
187187

188188
switch (c->x86_vendor) {
189-
case X86_VENDOR_INTEL:
190-
if (c->x86 >= 6)
191-
ret = save_microcode_in_initrd_intel();
192-
break;
193189
case X86_VENDOR_AMD:
194190
if (c->x86 >= 0x10)
195191
ret = save_microcode_in_initrd_amd(cpuid_eax(1));

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

Lines changed: 77 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232

3333
static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
3434

35+
#define UCODE_BSP_LOADED ((struct microcode_intel *)0x1UL)
36+
3537
/* Current microcode patch used in early patching on the APs. */
36-
static struct microcode_intel *intel_ucode_patch __read_mostly;
38+
static struct microcode_intel *ucode_patch_va __read_mostly;
3739

3840
/* last level cache size per core */
3941
static unsigned int llc_size_per_core __ro_after_init;
@@ -240,22 +242,30 @@ int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type)
240242
}
241243
EXPORT_SYMBOL_GPL(intel_microcode_sanity_check);
242244

243-
static void save_microcode_patch(void *data, unsigned int size)
245+
static void update_ucode_pointer(struct microcode_intel *mc)
244246
{
245-
struct microcode_header_intel *p;
247+
kfree(ucode_patch_va);
248+
249+
/*
250+
* Save the virtual address for early loading and for eventual free
251+
* on late loading.
252+
*/
253+
ucode_patch_va = mc;
254+
}
246255

247-
p = kmemdup(data, size, GFP_KERNEL);
248-
if (!p)
249-
return;
256+
static void save_microcode_patch(struct microcode_intel *patch)
257+
{
258+
struct microcode_intel *mc;
250259

251-
kfree(intel_ucode_patch);
252-
/* Save for early loading */
253-
intel_ucode_patch = (struct microcode_intel *)p;
260+
mc = kmemdup(patch, get_totalsize(&patch->hdr), GFP_KERNEL);
261+
if (mc)
262+
update_ucode_pointer(mc);
254263
}
255264

256-
/* Scan CPIO for microcode matching the boot CPU's family, model, stepping */
257-
static struct microcode_intel *scan_microcode(void *data, size_t size,
258-
struct ucode_cpu_info *uci, bool save)
265+
/* Scan blob for microcode matching the boot CPUs family, model, stepping */
266+
static __init struct microcode_intel *scan_microcode(void *data, size_t size,
267+
struct ucode_cpu_info *uci,
268+
bool save)
259269
{
260270
struct microcode_header_intel *mc_header;
261271
struct microcode_intel *patch = NULL;
@@ -273,35 +283,35 @@ static struct microcode_intel *scan_microcode(void *data, size_t size,
273283
if (!intel_find_matching_signature(data, uci->cpu_sig.sig, uci->cpu_sig.pf))
274284
continue;
275285

276-
/* BSP scan: Check whether there is newer microcode */
277-
if (!save && cur_rev >= mc_header->rev)
278-
continue;
279-
280-
/* Save scan: Check whether there is newer or matching microcode */
281-
if (save && cur_rev != mc_header->rev)
286+
/*
287+
* For saving the early microcode, find the matching revision which
288+
* was loaded on the BSP.
289+
*
290+
* On the BSP during early boot, find a newer revision than
291+
* actually loaded in the CPU.
292+
*/
293+
if (save) {
294+
if (cur_rev != mc_header->rev)
295+
continue;
296+
} else if (cur_rev >= mc_header->rev) {
282297
continue;
298+
}
283299

284300
patch = data;
285301
cur_rev = mc_header->rev;
286302
}
287303

288-
if (size)
289-
return NULL;
290-
291-
if (save && patch)
292-
save_microcode_patch(patch, mc_size);
293-
294-
return patch;
304+
return size ? NULL : patch;
295305
}
296306

297-
static int apply_microcode_early(struct ucode_cpu_info *uci)
307+
static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci)
298308
{
299309
struct microcode_intel *mc;
300310
u32 rev, old_rev, date;
301311

302312
mc = uci->mc;
303313
if (!mc)
304-
return 0;
314+
return UCODE_NFOUND;
305315

306316
/*
307317
* Save us the MSR write below - which is a particular expensive
@@ -327,17 +337,17 @@ static int apply_microcode_early(struct ucode_cpu_info *uci)
327337

328338
rev = intel_get_microcode_revision();
329339
if (rev != mc->hdr.rev)
330-
return -1;
340+
return UCODE_ERROR;
331341

332342
uci->cpu_sig.rev = rev;
333343

334344
date = mc->hdr.date;
335345
pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n",
336346
old_rev, rev, date & 0xffff, date >> 24, (date >> 16) & 0xff);
337-
return 0;
347+
return UCODE_UPDATED;
338348
}
339349

340-
static bool load_builtin_intel_microcode(struct cpio_data *cp)
350+
static __init bool load_builtin_intel_microcode(struct cpio_data *cp)
341351
{
342352
unsigned int eax = 1, ebx, ecx = 0, edx;
343353
struct firmware fw;
@@ -359,89 +369,71 @@ static bool load_builtin_intel_microcode(struct cpio_data *cp)
359369
return false;
360370
}
361371

362-
int __init save_microcode_in_initrd_intel(void)
372+
static __init struct microcode_intel *get_microcode_blob(struct ucode_cpu_info *uci, bool save)
363373
{
364-
struct ucode_cpu_info uci;
365374
struct cpio_data cp;
366375

367-
/*
368-
* initrd is going away, clear patch ptr. We will scan the microcode one
369-
* last time before jettisoning and save a patch, if found. Then we will
370-
* update that pointer too, with a stable patch address to use when
371-
* resuming the cores.
372-
*/
373-
intel_ucode_patch = NULL;
374-
375376
if (!load_builtin_intel_microcode(&cp))
376377
cp = find_microcode_in_initrd(ucode_path);
377378

378379
if (!(cp.data && cp.size))
379-
return 0;
380+
return NULL;
380381

381-
intel_cpu_collect_info(&uci);
382+
intel_cpu_collect_info(uci);
382383

383-
scan_microcode(cp.data, cp.size, &uci, true);
384-
return 0;
384+
return scan_microcode(cp.data, cp.size, uci, save);
385385
}
386386

387387
/*
388-
* @res_patch, output: a pointer to the patch we found.
388+
* Invoked from an early init call to save the microcode blob which was
389+
* selected during early boot when mm was not usable. The microcode must be
390+
* saved because initrd is going away. It's an early init call so the APs
391+
* just can use the pointer and do not have to scan initrd/builtin firmware
392+
* again.
389393
*/
390-
static struct microcode_intel *__load_ucode_intel(struct ucode_cpu_info *uci)
394+
static int __init save_builtin_microcode(void)
391395
{
392-
struct cpio_data cp;
393-
394-
/* try built-in microcode first */
395-
if (!load_builtin_intel_microcode(&cp))
396-
cp = find_microcode_in_initrd(ucode_path);
396+
struct ucode_cpu_info uci;
397397

398-
if (!(cp.data && cp.size))
399-
return NULL;
398+
if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED)
399+
return 0;
400400

401-
intel_cpu_collect_info(uci);
401+
if (dis_ucode_ldr || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
402+
return 0;
402403

403-
return scan_microcode(cp.data, cp.size, uci, false);
404+
uci.mc = get_microcode_blob(&uci, true);
405+
if (uci.mc)
406+
save_microcode_patch(uci.mc);
407+
return 0;
404408
}
409+
early_initcall(save_builtin_microcode);
405410

411+
/* Load microcode on BSP from initrd or builtin blobs */
406412
void __init load_ucode_intel_bsp(void)
407413
{
408-
struct microcode_intel *patch;
409414
struct ucode_cpu_info uci;
410415

411-
patch = __load_ucode_intel(&uci);
412-
if (!patch)
413-
return;
414-
415-
uci.mc = patch;
416-
417-
apply_microcode_early(&uci);
416+
uci.mc = get_microcode_blob(&uci, false);
417+
if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED)
418+
ucode_patch_va = UCODE_BSP_LOADED;
418419
}
419420

420421
void load_ucode_intel_ap(void)
421422
{
422423
struct ucode_cpu_info uci;
423424

424-
if (!intel_ucode_patch) {
425-
intel_ucode_patch = __load_ucode_intel(&uci);
426-
if (!intel_ucode_patch)
427-
return;
428-
}
429-
430-
uci.mc = intel_ucode_patch;
431-
apply_microcode_early(&uci);
425+
uci.mc = ucode_patch_va;
426+
if (uci.mc)
427+
apply_microcode_early(&uci);
432428
}
433429

430+
/* Reload microcode on resume */
434431
void reload_ucode_intel(void)
435432
{
436-
struct ucode_cpu_info uci;
437-
438-
intel_cpu_collect_info(&uci);
439-
440-
uci.mc = intel_ucode_patch;
441-
if (!uci.mc)
442-
return;
433+
struct ucode_cpu_info uci = { .mc = ucode_patch_va, };
443434

444-
apply_microcode_early(&uci);
435+
if (uci.mc)
436+
apply_microcode_early(&uci);
445437
}
446438

447439
static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
@@ -478,7 +470,7 @@ static enum ucode_state apply_microcode_intel(int cpu)
478470
if (WARN_ON(raw_smp_processor_id() != cpu))
479471
return UCODE_ERROR;
480472

481-
mc = intel_ucode_patch;
473+
mc = ucode_patch_va;
482474
if (!mc) {
483475
mc = uci->mc;
484476
if (!mc)
@@ -538,8 +530,8 @@ static enum ucode_state apply_microcode_intel(int cpu)
538530
static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
539531
{
540532
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
541-
unsigned int curr_mc_size = 0, new_mc_size = 0;
542533
int cur_rev = uci->cpu_sig.rev;
534+
unsigned int curr_mc_size = 0;
543535
u8 *new_mc = NULL, *mc = NULL;
544536

545537
while (iov_iter_count(iter)) {
@@ -589,7 +581,6 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
589581
vfree(new_mc);
590582
cur_rev = mc_header.rev;
591583
new_mc = mc;
592-
new_mc_size = mc_size;
593584
mc = NULL;
594585
}
595586

@@ -603,11 +594,11 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
603594
if (!new_mc)
604595
return UCODE_NFOUND;
605596

606-
vfree(uci->mc);
607-
uci->mc = (struct microcode_intel *)new_mc;
608-
609597
/* Save for CPU hotplug */
610-
save_microcode_patch(new_mc, new_mc_size);
598+
save_microcode_patch((struct microcode_intel *)new_mc);
599+
uci->mc = ucode_patch_va;
600+
601+
vfree(new_mc);
611602

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

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ static inline unsigned int x86_cpuid_family(void)
8484
return x86_family(eax);
8585
}
8686

87+
extern bool dis_ucode_ldr;
8788
extern bool initrd_gone;
8889

8990
#ifdef CONFIG_CPU_SUP_AMD
@@ -107,13 +108,11 @@ static inline void exit_amd_microcode(void) { }
107108
#ifdef CONFIG_CPU_SUP_INTEL
108109
void load_ucode_intel_bsp(void);
109110
void load_ucode_intel_ap(void);
110-
int save_microcode_in_initrd_intel(void);
111111
void reload_ucode_intel(void);
112112
struct microcode_ops *init_intel_microcode(void);
113113
#else /* CONFIG_CPU_SUP_INTEL */
114114
static inline void load_ucode_intel_bsp(void) { }
115115
static inline void load_ucode_intel_ap(void) { }
116-
static inline int save_microcode_in_initrd_intel(void) { return -EINVAL; }
117116
static inline void reload_ucode_intel(void) { }
118117
static inline struct microcode_ops *init_intel_microcode(void) { return NULL; }
119118
#endif /* !CONFIG_CPU_SUP_INTEL */

0 commit comments

Comments
 (0)