tools/testing/selftests/x86/fsgsbase.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/x86/fsgsbase.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/x86/fsgsbase.c
Extension
.c
Size
16254 bytes
Lines
661
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (ret != 0) {
			printf("[NOTE]\tcould not create a segment -- test won't do anything\n");
			return 0;
		}
		printf("\tusing GDT slot %d\n", desc.entry_number);
		set_thread_area_entry_number = desc.entry_number;

		unsigned short gs = (unsigned short)((desc.entry_number << 3) | 0x3);
		asm volatile ("mov %0, %%gs" : : "rm" (gs));
		return gs;
	}
}

void test_wrbase(unsigned short index, unsigned long base)
{
	unsigned short newindex;
	unsigned long newbase;

	printf("[RUN]\tGS = 0x%hx, GSBASE = 0x%lx\n", index, base);

	asm volatile ("mov %0, %%gs" : : "rm" (index));
	wrgsbase(base);

	remote_base = 0;
	ftx = 1;
	syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
	while (ftx != 0)
		syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);

	asm volatile ("mov %%gs, %0" : "=rm" (newindex));
	newbase = rdgsbase();

	if (newindex == index && newbase == base) {
		printf("[OK]\tIndex and base were preserved\n");
	} else {
		printf("[FAIL]\tAfter switch, GS = 0x%hx and GSBASE = 0x%lx\n",
		       newindex, newbase);
		nerrs++;
	}
}

static void *threadproc(void *ctx)
{
	while (1) {
		while (ftx == 0)
			syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0);
		if (ftx == 3)
			return NULL;

		if (ftx == 1) {
			do_remote_base();
		} else if (ftx == 2) {
			/*
			 * On AMD chips, this causes GSBASE != 0, GS == 0, and
			 * thread.gsbase == 0.
			 */

			load_gs();
			asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));
		} else {
			errx(1, "helper thread got bad command");
		}

		ftx = 0;
		syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
	}
}

static void set_gs_and_switch_to(unsigned long local,
				 unsigned short force_sel,
				 unsigned long remote)
{
	unsigned long base;
	unsigned short sel_pre_sched, sel_post_sched;

	bool hard_zero = false;
	if (local == HARD_ZERO) {
		hard_zero = true;
		local = 0;
	}

	printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
	       local, hard_zero ? " and clear gs" : "", remote);
	if (force_sel)
		printf("\tBefore schedule, set selector to 0x%hx\n", force_sel);
	if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
		err(1, "ARCH_SET_GS");
	if (hard_zero)
		asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0));

Annotation

Implementation Notes