Skip to content

Commit 1582c0f

Browse files
KAGA-KOKObp3tk0v
authored andcommitted
x86/microcode: Protect against instrumentation
The wait for control loop in which the siblings are waiting for the microcode update on the primary thread must be protected against instrumentation as instrumentation can end up in #INT3, #DB or #PF, which then returns with IRET. That IRET reenables NMI which is the opposite of what the NMI rendezvous is trying to achieve. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7eb314a commit 1582c0f

File tree

1 file changed

+83
-28
lines changed
  • arch/x86/kernel/cpu/microcode

1 file changed

+83
-28
lines changed

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

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -272,54 +272,65 @@ struct microcode_ctrl {
272272

273273
DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
274274
static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl);
275+
static unsigned int loops_per_usec;
275276
static atomic_t late_cpus_in;
276277

277-
static bool wait_for_cpus(atomic_t *cnt)
278+
static noinstr bool wait_for_cpus(atomic_t *cnt)
278279
{
279-
unsigned int timeout;
280+
unsigned int timeout, loops;
280281

281-
WARN_ON_ONCE(atomic_dec_return(cnt) < 0);
282+
WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0);
282283

283284
for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
284-
if (!atomic_read(cnt))
285+
if (!raw_atomic_read(cnt))
285286
return true;
286287

287-
udelay(1);
288+
for (loops = 0; loops < loops_per_usec; loops++)
289+
cpu_relax();
288290

289291
/* If invoked directly, tickle the NMI watchdog */
290-
if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC))
292+
if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
293+
instrumentation_begin();
291294
touch_nmi_watchdog();
295+
instrumentation_end();
296+
}
292297
}
293298
/* Prevent the late comers from making progress and let them time out */
294-
atomic_inc(cnt);
299+
raw_atomic_inc(cnt);
295300
return false;
296301
}
297302

298-
static bool wait_for_ctrl(void)
303+
static noinstr bool wait_for_ctrl(void)
299304
{
300-
unsigned int timeout;
305+
unsigned int timeout, loops;
301306

302307
for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
303-
if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
308+
if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
304309
return true;
305-
udelay(1);
310+
311+
for (loops = 0; loops < loops_per_usec; loops++)
312+
cpu_relax();
313+
306314
/* If invoked directly, tickle the NMI watchdog */
307-
if (!microcode_ops->use_nmi && !(timeout % 1000))
315+
if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
316+
instrumentation_begin();
308317
touch_nmi_watchdog();
318+
instrumentation_end();
319+
}
309320
}
310321
return false;
311322
}
312323

313-
static void load_secondary(unsigned int cpu)
324+
/*
325+
* Protected against instrumentation up to the point where the primary
326+
* thread completed the update. See microcode_nmi_handler() for details.
327+
*/
328+
static noinstr bool load_secondary_wait(unsigned int ctrl_cpu)
314329
{
315-
unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu);
316-
enum ucode_state ret;
317-
318330
/* Initial rendezvous to ensure that all CPUs have arrived */
319331
if (!wait_for_cpus(&late_cpus_in)) {
320-
pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1);
321-
this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
322-
return;
332+
raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
333+
return false;
323334
}
324335

325336
/*
@@ -329,9 +340,33 @@ static void load_secondary(unsigned int cpu)
329340
* scheduler, watchdogs etc. There is no way to safely evacuate the
330341
* machine.
331342
*/
332-
if (!wait_for_ctrl())
333-
panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
343+
if (wait_for_ctrl())
344+
return true;
345+
346+
instrumentation_begin();
347+
panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
348+
instrumentation_end();
349+
}
334350

351+
/*
352+
* Protected against instrumentation up to the point where the primary
353+
* thread completed the update. See microcode_nmi_handler() for details.
354+
*/
355+
static noinstr void load_secondary(unsigned int cpu)
356+
{
357+
unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu);
358+
enum ucode_state ret;
359+
360+
if (!load_secondary_wait(ctrl_cpu)) {
361+
instrumentation_begin();
362+
pr_err_once("load: %d CPUs timed out\n",
363+
atomic_read(&late_cpus_in) - 1);
364+
instrumentation_end();
365+
return;
366+
}
367+
368+
/* Primary thread completed. Allow to invoke instrumentable code */
369+
instrumentation_begin();
335370
/*
336371
* If the primary succeeded then invoke the apply() callback,
337372
* otherwise copy the state from the primary thread.
@@ -343,6 +378,7 @@ static void load_secondary(unsigned int cpu)
343378

344379
this_cpu_write(ucode_ctrl.result, ret);
345380
this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE);
381+
instrumentation_end();
346382
}
347383

348384
static void load_primary(unsigned int cpu)
@@ -380,25 +416,43 @@ static void load_primary(unsigned int cpu)
380416
}
381417
}
382418

383-
static bool microcode_update_handler(void)
419+
static noinstr bool microcode_update_handler(void)
384420
{
385-
unsigned int cpu = smp_processor_id();
421+
unsigned int cpu = raw_smp_processor_id();
386422

387-
if (this_cpu_read(ucode_ctrl.ctrl_cpu) == cpu)
423+
if (raw_cpu_read(ucode_ctrl.ctrl_cpu) == cpu) {
424+
instrumentation_begin();
388425
load_primary(cpu);
389-
else
426+
instrumentation_end();
427+
} else {
390428
load_secondary(cpu);
429+
}
391430

431+
instrumentation_begin();
392432
touch_nmi_watchdog();
433+
instrumentation_end();
434+
393435
return true;
394436
}
395437

396-
bool microcode_nmi_handler(void)
438+
/*
439+
* Protection against instrumentation is required for CPUs which are not
440+
* safe against an NMI which is delivered to the secondary SMT sibling
441+
* while the primary thread updates the microcode. Instrumentation can end
442+
* up in #INT3, #DB and #PF. The IRET from those exceptions reenables NMI
443+
* which is the opposite of what the NMI rendezvous is trying to achieve.
444+
*
445+
* The primary thread is safe versus instrumentation as the actual
446+
* microcode update handles this correctly. It's only the sibling code
447+
* path which must be NMI safe until the primary thread completed the
448+
* update.
449+
*/
450+
bool noinstr microcode_nmi_handler(void)
397451
{
398-
if (!this_cpu_read(ucode_ctrl.nmi_enabled))
452+
if (!raw_cpu_read(ucode_ctrl.nmi_enabled))
399453
return false;
400454

401-
this_cpu_write(ucode_ctrl.nmi_enabled, false);
455+
raw_cpu_write(ucode_ctrl.nmi_enabled, false);
402456
return microcode_update_handler();
403457
}
404458

@@ -425,6 +479,7 @@ static int load_late_stop_cpus(void)
425479
pr_err("You should switch to early loading, if possible.\n");
426480

427481
atomic_set(&late_cpus_in, num_online_cpus());
482+
loops_per_usec = loops_per_jiffy / (TICK_NSEC / 1000);
428483

429484
/*
430485
* Take a snapshot before the microcode update in order to compare and

0 commit comments

Comments
 (0)