aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-07-02 21:19:49 -0400
committerIan Moffett <ian@osmora.org>2024-07-02 21:25:53 -0400
commit2d7bc823503167276c6d3c40500c3055d4f38938 (patch)
tree2971c86e108f5afa1c622afa511a289d12e7a3e6
parent52760e9c5e677b76c81e921bbab95da26478f425 (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>
-rw-r--r--sys/arch/amd64/amd64/machdep.c20
-rw-r--r--sys/arch/amd64/amd64/proc_machdep.c30
-rw-r--r--sys/include/arch/amd64/cpu.h1
-rw-r--r--sys/include/arch/amd64/frameasm.h24
-rw-r--r--sys/include/sys/proc.h2
-rw-r--r--sys/kern/kern_exec.c4
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);
}