arch/x86/kernel/process_64.c

Source file repositories/reference/linux-study-clean/arch/x86/kernel/process_64.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/process_64.c
Extension
.c
Size
26446 bytes
Lines
983
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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

if (next_base == 0) {
			/*
			 * Nasty case: on AMD CPUs, we need to forcibly zero
			 * the base.
			 */
			if (static_cpu_has_bug(X86_BUG_NULL_SEG)) {
				loadseg(which, __USER_DS);
				loadseg(which, next_index);
			} else {
				/*
				 * We could try to exhaustively detect cases
				 * under which we can skip the segment load,
				 * but there's really only one case that matters
				 * for performance: if both the previous and
				 * next states are fully zeroed, we can skip
				 * the load.
				 *
				 * (This assumes that prev_base == 0 has no
				 * false positives.  This is the case on
				 * Intel-style CPUs.)
				 */
				if (likely(prev_index | next_index | prev_base))
					loadseg(which, next_index);
			}
		} else {
			if (prev_index != next_index)
				loadseg(which, next_index);
			wrmsrq(which == FS ? MSR_FS_BASE : MSR_KERNEL_GS_BASE,
			       next_base);
		}
	} else {
		/*
		 * The next task is using a real segment.  Loading the selector
		 * is sufficient.
		 */
		loadseg(which, next_index);
	}
}

/*
 * Store prev's PKRU value and load next's PKRU value if they differ. PKRU
 * is not XSTATE managed on context switch because that would require a
 * lookup in the task's FPU xsave buffer and require to keep that updated
 * in various places.
 */
static __always_inline void x86_pkru_load(struct thread_struct *prev,
					  struct thread_struct *next)
{
	if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
		return;

	/* Stash the prev task's value: */
	prev->pkru = rdpkru();

	/*
	 * PKRU writes are slightly expensive.  Avoid them when not
	 * strictly necessary:
	 */
	if (prev->pkru != next->pkru)
		wrpkru(next->pkru);
}

static __always_inline void x86_fsgsbase_load(struct thread_struct *prev,
					      struct thread_struct *next)
{
	if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
		/* Update the FS and GS selectors if they could have changed. */
		if (unlikely(prev->fsindex || next->fsindex))
			loadseg(FS, next->fsindex);
		if (unlikely(prev->gsindex || next->gsindex))
			loadseg(GS, next->gsindex);

		/* Update the bases. */
		wrfsbase(next->fsbase);
		__wrgsbase_inactive(next->gsbase);
	} else {
		load_seg_legacy(prev->fsindex, prev->fsbase,
				next->fsindex, next->fsbase, FS);
		load_seg_legacy(prev->gsindex, prev->gsbase,
				next->gsindex, next->gsbase, GS);
	}
}

unsigned long x86_fsgsbase_read_task(struct task_struct *task,
				     unsigned short selector)
{
	unsigned short idx = selector >> 3;
	unsigned long base;

	if (likely((selector & SEGMENT_TI_MASK) == 0)) {

Annotation

Implementation Notes