Skip to content

Commit 2a47c26

Browse files
committed
Merge tag 'x86_microcode_for_v6.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode loading updates from Borislav Petkov: - Add microcode staging support on Intel: it moves the sole microcode blobs loading to a non-critical path so that microcode loading latencies are kept at minimum. The actual "directing" the hardware to load microcode is the only step which is done on the critical path. This scheme is also opportunistic as in: on a failure, the machinery falls back to normal loading - Add the capability to the AMD side of the loader to select one of two per-family/model/stepping patches: one is pre-Entrysign and the other is post-Entrysign; with the goal to take care of machines which haven't updated their BIOS yet - something they should absolutely do as this is the only proper Entrysign fix - Other small cleanups and fixlets * tag 'x86_microcode_for_v6.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/microcode: Mark early_parse_cmdline() as __init x86/microcode/AMD: Select which microcode patch to load x86/microcode/intel: Enable staging when available x86/microcode/intel: Support mailbox transfer x86/microcode/intel: Implement staging handler x86/microcode/intel: Define staging state struct x86/microcode/intel: Establish staging control logic x86/microcode: Introduce staging step to reduce late-loading time x86/cpu/topology: Make primary thread mask available with SMP=n
2 parents a612882 + ca8313f commit 2a47c26

9 files changed

Lines changed: 468 additions & 56 deletions

File tree

arch/x86/include/asm/msr-index.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@
166166
* Processor MMIO stale data
167167
* vulnerabilities.
168168
*/
169+
#define ARCH_CAP_MCU_ENUM BIT(16) /*
170+
* Indicates the presence of microcode update
171+
* feature enumeration and status information.
172+
*/
169173
#define ARCH_CAP_FB_CLEAR BIT(17) /*
170174
* VERW clears CPU fill buffer
171175
* even on MDS_NO CPUs.
@@ -949,6 +953,10 @@
949953
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
950954

951955
#define MSR_IA32_UCODE_WRITE 0x00000079
956+
957+
#define MSR_IA32_MCU_ENUMERATION 0x0000007b
958+
#define MCU_STAGING BIT(4)
959+
952960
#define MSR_IA32_UCODE_REV 0x0000008b
953961

954962
/* Intel SGX Launch Enclave Public Key Hash MSRs */
@@ -1246,6 +1254,8 @@
12461254
#define MSR_IA32_VMX_VMFUNC 0x00000491
12471255
#define MSR_IA32_VMX_PROCBASED_CTLS3 0x00000492
12481256

1257+
#define MSR_IA32_MCU_STAGING_MBOX_ADDR 0x000007a5
1258+
12491259
/* Resctrl MSRs: */
12501260
/* - Intel: */
12511261
#define MSR_IA32_L3_QOS_CFG 0xc81

arch/x86/include/asm/topology.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,12 @@ static inline unsigned int topology_amd_nodes_per_pkg(void)
218218
return __amd_nodes_per_pkg;
219219
}
220220

221+
#else /* CONFIG_SMP */
222+
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
223+
static inline int topology_max_smt_threads(void) { return 1; }
224+
static inline unsigned int topology_amd_nodes_per_pkg(void) { return 1; }
225+
#endif /* !CONFIG_SMP */
226+
221227
extern struct cpumask __cpu_primary_thread_mask;
222228
#define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask)
223229

@@ -241,12 +247,6 @@ static inline bool topology_is_core_online(unsigned int cpu)
241247
}
242248
#define topology_is_core_online topology_is_core_online
243249

244-
#else /* CONFIG_SMP */
245-
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
246-
static inline int topology_max_smt_threads(void) { return 1; }
247-
static inline unsigned int topology_amd_nodes_per_pkg(void) { return 1; }
248-
#endif /* !CONFIG_SMP */
249-
250250
static inline void arch_fix_phys_package_id(int num, u32 slot)
251251
{
252252
}

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

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -186,50 +186,61 @@ static u32 cpuid_to_ucode_rev(unsigned int val)
186186
return p.ucode_rev;
187187
}
188188

189+
static u32 get_cutoff_revision(u32 rev)
190+
{
191+
switch (rev >> 8) {
192+
case 0x80012: return 0x8001277; break;
193+
case 0x80082: return 0x800820f; break;
194+
case 0x83010: return 0x830107c; break;
195+
case 0x86001: return 0x860010e; break;
196+
case 0x86081: return 0x8608108; break;
197+
case 0x87010: return 0x8701034; break;
198+
case 0x8a000: return 0x8a0000a; break;
199+
case 0xa0010: return 0xa00107a; break;
200+
case 0xa0011: return 0xa0011da; break;
201+
case 0xa0012: return 0xa001243; break;
202+
case 0xa0082: return 0xa00820e; break;
203+
case 0xa1011: return 0xa101153; break;
204+
case 0xa1012: return 0xa10124e; break;
205+
case 0xa1081: return 0xa108109; break;
206+
case 0xa2010: return 0xa20102f; break;
207+
case 0xa2012: return 0xa201212; break;
208+
case 0xa4041: return 0xa404109; break;
209+
case 0xa5000: return 0xa500013; break;
210+
case 0xa6012: return 0xa60120a; break;
211+
case 0xa7041: return 0xa704109; break;
212+
case 0xa7052: return 0xa705208; break;
213+
case 0xa7080: return 0xa708009; break;
214+
case 0xa70c0: return 0xa70C009; break;
215+
case 0xaa001: return 0xaa00116; break;
216+
case 0xaa002: return 0xaa00218; break;
217+
case 0xb0021: return 0xb002146; break;
218+
case 0xb0081: return 0xb008111; break;
219+
case 0xb1010: return 0xb101046; break;
220+
case 0xb2040: return 0xb204031; break;
221+
case 0xb4040: return 0xb404031; break;
222+
case 0xb4041: return 0xb404101; break;
223+
case 0xb6000: return 0xb600031; break;
224+
case 0xb6080: return 0xb608031; break;
225+
case 0xb7000: return 0xb700031; break;
226+
default: break;
227+
228+
}
229+
return 0;
230+
}
231+
189232
static bool need_sha_check(u32 cur_rev)
190233
{
234+
u32 cutoff;
235+
191236
if (!cur_rev) {
192237
cur_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax);
193238
pr_info_once("No current revision, generating the lowest one: 0x%x\n", cur_rev);
194239
}
195240

196-
switch (cur_rev >> 8) {
197-
case 0x80012: return cur_rev <= 0x8001277; break;
198-
case 0x80082: return cur_rev <= 0x800820f; break;
199-
case 0x83010: return cur_rev <= 0x830107c; break;
200-
case 0x86001: return cur_rev <= 0x860010e; break;
201-
case 0x86081: return cur_rev <= 0x8608108; break;
202-
case 0x87010: return cur_rev <= 0x8701034; break;
203-
case 0x8a000: return cur_rev <= 0x8a0000a; break;
204-
case 0xa0010: return cur_rev <= 0xa00107a; break;
205-
case 0xa0011: return cur_rev <= 0xa0011da; break;
206-
case 0xa0012: return cur_rev <= 0xa001243; break;
207-
case 0xa0082: return cur_rev <= 0xa00820e; break;
208-
case 0xa1011: return cur_rev <= 0xa101153; break;
209-
case 0xa1012: return cur_rev <= 0xa10124e; break;
210-
case 0xa1081: return cur_rev <= 0xa108109; break;
211-
case 0xa2010: return cur_rev <= 0xa20102f; break;
212-
case 0xa2012: return cur_rev <= 0xa201212; break;
213-
case 0xa4041: return cur_rev <= 0xa404109; break;
214-
case 0xa5000: return cur_rev <= 0xa500013; break;
215-
case 0xa6012: return cur_rev <= 0xa60120a; break;
216-
case 0xa7041: return cur_rev <= 0xa704109; break;
217-
case 0xa7052: return cur_rev <= 0xa705208; break;
218-
case 0xa7080: return cur_rev <= 0xa708009; break;
219-
case 0xa70c0: return cur_rev <= 0xa70C009; break;
220-
case 0xaa001: return cur_rev <= 0xaa00116; break;
221-
case 0xaa002: return cur_rev <= 0xaa00218; break;
222-
case 0xb0021: return cur_rev <= 0xb002146; break;
223-
case 0xb0081: return cur_rev <= 0xb008111; break;
224-
case 0xb1010: return cur_rev <= 0xb101046; break;
225-
case 0xb2040: return cur_rev <= 0xb204031; break;
226-
case 0xb4040: return cur_rev <= 0xb404031; break;
227-
case 0xb4041: return cur_rev <= 0xb404101; break;
228-
case 0xb6000: return cur_rev <= 0xb600031; break;
229-
case 0xb6080: return cur_rev <= 0xb608031; break;
230-
case 0xb7000: return cur_rev <= 0xb700031; break;
231-
default: break;
232-
}
241+
cutoff = get_cutoff_revision(cur_rev);
242+
if (cutoff)
243+
return cur_rev <= cutoff;
233244

234245
pr_info("You should not be seeing this. Please send the following couple of lines to x86-<at>-kernel.org\n");
235246
pr_info("CPUID(1).EAX: 0x%x, current revision: 0x%x\n", bsp_cpuid_1_eax, cur_rev);
@@ -494,6 +505,7 @@ static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size)
494505
{
495506
u8 family = x86_family(bsp_cpuid_1_eax);
496507
struct microcode_header_amd *mc_hdr;
508+
u32 cur_rev, cutoff, patch_rev;
497509
u32 sh_psize;
498510
u16 proc_id;
499511
u8 patch_fam;
@@ -533,11 +545,32 @@ static int verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size)
533545
proc_id = mc_hdr->processor_rev_id;
534546
patch_fam = 0xf + (proc_id >> 12);
535547

536-
ucode_dbg("Patch-ID 0x%08x: family: 0x%x\n", mc_hdr->patch_id, patch_fam);
537-
538548
if (patch_fam != family)
539549
return 1;
540550

551+
cur_rev = get_patch_level();
552+
553+
/* No cutoff revision means old/unaffected by signing algorithm weakness => matches */
554+
cutoff = get_cutoff_revision(cur_rev);
555+
if (!cutoff)
556+
goto ok;
557+
558+
patch_rev = mc_hdr->patch_id;
559+
560+
ucode_dbg("cur_rev: 0x%x, cutoff: 0x%x, patch_rev: 0x%x\n",
561+
cur_rev, cutoff, patch_rev);
562+
563+
if (cur_rev <= cutoff && patch_rev <= cutoff)
564+
goto ok;
565+
566+
if (cur_rev > cutoff && patch_rev > cutoff)
567+
goto ok;
568+
569+
return 1;
570+
571+
ok:
572+
ucode_dbg("Patch-ID 0x%08x: family: 0x%x\n", mc_hdr->patch_id, patch_fam);
573+
541574
return 0;
542575
}
543576

@@ -606,8 +639,6 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
606639

607640
mc = (struct microcode_amd *)(buf + SECTION_HDR_SIZE);
608641

609-
ucode_dbg("patch_id: 0x%x\n", mc->hdr.patch_id);
610-
611642
if (mc_patch_matches(mc, eq_id)) {
612643
desc->psize = patch_size;
613644
desc->mc = mc;

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ bool __init microcode_loader_disabled(void)
136136
return dis_ucode_ldr;
137137
}
138138

139-
static void early_parse_cmdline(void)
139+
static void __init early_parse_cmdline(void)
140140
{
141141
char cmd_buf[64] = {};
142142
char *s, *p = cmd_buf;
@@ -589,6 +589,17 @@ static int load_late_stop_cpus(bool is_safe)
589589
pr_err("You should switch to early loading, if possible.\n");
590590
}
591591

592+
/*
593+
* Pre-load the microcode image into a staging device. This
594+
* process is preemptible and does not require stopping CPUs.
595+
* Successful staging simplifies the subsequent late-loading
596+
* process, reducing rendezvous time.
597+
*
598+
* Even if the transfer fails, the update will proceed as usual.
599+
*/
600+
if (microcode_ops->use_staging)
601+
microcode_ops->stage_microcode();
602+
592603
atomic_set(&late_cpus_in, num_online_cpus());
593604
atomic_set(&offline_in_nmi, 0);
594605
loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000);

0 commit comments

Comments
 (0)