From 2d7bc823503167276c6d3c40500c3055d4f38938 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 2 Jul 2024 21:19:49 -0400 Subject: kernel/amd64: Handle the user GS segment register This commit introduces usage of swapgs to switch out the GS register with the user GS register. An md_td_kick() function is also introduced to start up user threads. The this_cpu() function uses the GS register to read the current CPU structure using a new "self" field. Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/machdep.c | 20 ++++++++++++++++++-- sys/arch/amd64/amd64/proc_machdep.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) (limited to 'sys/arch/amd64') diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 82fa97b..528326a 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -95,20 +95,36 @@ try_mitigate_spectre(void) struct cpu_info * this_cpu(void) { - return (void *)amd64_read_gs_base(); + struct cpu_info *ci; + + /* + * This might look crazy but we are just leveraging the "m" + * constraint to calculate the offset of the self field within + * cpu_info. The self field points to the cpu_info structure + * itself allowing us to access cpu_info through %gs. + */ + __ASMV("mov %%gs:%1, %0" + : "=r" (ci) + : "m" (*&((struct cpu_info *)0)->self) + : "memory"); + + return ci; } void cpu_startup(struct cpu_info *ci) { + ci->self = ci; gdt_load(&bsp_gdtr); idt_load(); setup_vectors(); amd64_write_gs_base((uintptr_t)ci); - init_tss(ci); + __ASMV("swapgs"); /* Get kernel GS */ + init_tss(ci); try_mitigate_spectre(); + __ASMV("sti"); /* Unmask interrupts */ lapic_init(); } diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c index 2b4368b..723582b 100644 --- a/sys/arch/amd64/amd64/proc_machdep.c +++ b/sys/arch/amd64/amd64/proc_machdep.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,35 @@ setregs(struct proc *td, struct exec_prog *prog, uintptr_t stack) tfp->rflags = 0x202; } +/* + * Startup a user thread. + * + * @td: Thead to start up. + */ +void +md_td_kick(struct proc *td) +{ + struct trapframe *tfp; + + tfp = &td->tf; + __ASMV( + "push %0\n" + "push %1\n" + "pushf\n" + "push %2\n" + "push %3\n" + "swapgs\n" + "iretq" + : + : "i" (USER_DS | 3), + "r" (tfp->rsp), + "i" (USER_CS | 3), + "r" (tfp->rip) + ); + + __builtin_unreachable(); +} + /* * MD thread init code * -- cgit v1.2.3