diff options
author | Ian Moffett <ian@osmora.org> | 2024-07-02 21:19:49 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-07-02 21:25:53 -0400 |
commit | 2d7bc823503167276c6d3c40500c3055d4f38938 (patch) | |
tree | 2971c86e108f5afa1c622afa511a289d12e7a3e6 /sys | |
parent | 52760e9c5e677b76c81e921bbab95da26478f425 (diff) |
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 <ian@osmora.org>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/machdep.c | 20 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/proc_machdep.c | 30 | ||||
-rw-r--r-- | sys/include/arch/amd64/cpu.h | 1 | ||||
-rw-r--r-- | sys/include/arch/amd64/frameasm.h | 24 | ||||
-rw-r--r-- | sys/include/sys/proc.h | 2 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 4 |
6 files changed, 73 insertions, 8 deletions
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 <sys/exec.h> #include <machine/frame.h> #include <machine/gdt.h> +#include <machine/cpu.h> #include <vm/physmem.h> #include <vm/vm.h> #include <vm/map.h> @@ -113,6 +114,35 @@ setregs(struct proc *td, struct exec_prog *prog, uintptr_t stack) } /* + * 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 * * @p: New process. diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index 16936e9..2ce363c 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -42,6 +42,7 @@ struct cpu_info { size_t lapic_tmr_freq; struct tss_entry *tss; struct proc *curtd; + struct cpu_info *self; }; void cpu_startup(struct cpu_info *ci); diff --git a/sys/include/arch/amd64/frameasm.h b/sys/include/arch/amd64/frameasm.h index b8791ba..8983d36 100644 --- a/sys/include/arch/amd64/frameasm.h +++ b/sys/include/arch/amd64/frameasm.h @@ -106,11 +106,19 @@ */ #define INTRENTRY(ENTLABEL, HANDLER) \ ENTLABEL: \ - push_trapframe $0 ; \ + testq $0x3, 8(%rsp) ; \ + jz 1f ; \ + lfence ; \ + swapgs ; \ + 1: push_trapframe $0 ; \ mov %rsp, %rdi ; \ call HANDLER ; \ pop_trapframe ; \ - iretq + testq $0x3, 8(%rsp) ; \ + jz 2f ; \ + lfence ; \ + swapgs ; \ + 2: iretq /* * Trap entry where an error code is on @@ -118,10 +126,18 @@ */ #define TRAPENTRY(ENTLABEL, TRAPNO) \ ENTLABEL: \ - push_trapframe_ec TRAPNO ; \ + testq $0x3, 8(%rsp) ; \ + jz 1f ; \ + lfence ; \ + swapgs ; \ + 1: push_trapframe_ec TRAPNO ; \ mov %rsp, %rdi ; \ call trap_handler ; \ pop_trapframe_ec ; \ - iretq + testq $0x3, 8(%rsp) ; \ + jz 2f ; \ + lfence ; \ + swapgs ; \ + 2: iretq #endif /* !_MACHINE_FRAMEASM_H_ */ diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index ba931f3..805c4a5 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -34,6 +34,7 @@ #include <sys/spinlock.h> #include <sys/queue.h> #include <sys/param.h> +#include <sys/cdefs.h> #if defined(_KERNEL) #include <machine/frame.h> #include <machine/pcb.h> @@ -63,6 +64,7 @@ struct proc *this_td(void); int md_fork(struct proc *p, struct proc *parent, uintptr_t ip); void md_td_stackinit(struct proc *td, void *stack_top, struct exec_prog *prog); +__dead void md_td_kick(struct proc *td); int fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp); int exit1(struct proc *td); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index b21404b..7825448 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -98,11 +98,11 @@ execve(struct proc *td, const struct execve_args *args) setregs(td, &prog, stack_top); /* - * Done, reset flags and yield + * Done, reset flags and start the user thread. * * XXX: PROC_EXEC is unset by the scheduler so it * can properly start the new exec'd program. */ td->flags &= ~PROC_INEXEC; - sched_enter(); + md_td_kick(td); } |