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

Source file repositories/reference/linux-study-clean/arch/x86/kernel/cpu/microcode/core.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/cpu/microcode/core.c
Extension
.c
Size
23973 bytes
Lines
934
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct microcode_ctrl {
	enum sibling_ctrl	ctrl;
	enum ucode_state	result;
	unsigned int		ctrl_cpu;
	bool			nmi_enabled;
};

DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);
static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl);
static atomic_t late_cpus_in, offline_in_nmi;
static unsigned int loops_per_usec;
static cpumask_t cpu_offline_mask;

static noinstr bool wait_for_cpus(atomic_t *cnt)
{
	unsigned int timeout, loops;

	WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0);

	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
		if (!raw_atomic_read(cnt))
			return true;

		for (loops = 0; loops < loops_per_usec; loops++)
			cpu_relax();

		/* If invoked directly, tickle the NMI watchdog */
		if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
			instrumentation_begin();
			touch_nmi_watchdog();
			instrumentation_end();
		}
	}
	/* Prevent the late comers from making progress and let them time out */
	raw_atomic_inc(cnt);
	return false;
}

static noinstr bool wait_for_ctrl(void)
{
	unsigned int timeout, loops;

	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
		if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
			return true;

		for (loops = 0; loops < loops_per_usec; loops++)
			cpu_relax();

		/* If invoked directly, tickle the NMI watchdog */
		if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) {
			instrumentation_begin();
			touch_nmi_watchdog();
			instrumentation_end();
		}
	}
	return false;
}

/*
 * Protected against instrumentation up to the point where the primary
 * thread completed the update. See microcode_nmi_handler() for details.
 */
static noinstr bool load_secondary_wait(unsigned int ctrl_cpu)
{
	/* Initial rendezvous to ensure that all CPUs have arrived */
	if (!wait_for_cpus(&late_cpus_in)) {
		raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
		return false;
	}

	/*
	 * Wait for primary threads to complete. If one of them hangs due
	 * to the update, there is no way out. This is non-recoverable
	 * because the CPU might hold locks or resources and confuse the
	 * scheduler, watchdogs etc. There is no way to safely evacuate the
	 * machine.
	 */
	if (wait_for_ctrl())
		return true;

	instrumentation_begin();
	panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
	instrumentation_end();
}

/*
 * Protected against instrumentation up to the point where the primary
 * thread completed the update. See microcode_nmi_handler() for details.
 */

Annotation

Implementation Notes