aboutsummaryrefslogtreecommitdiff
path: root/kernel/proc/context.c
diff options
context:
space:
mode:
authornthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
committernthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
commitc63f340d90800895f007de64b7d2d14624263331 (patch)
tree2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/proc/context.c
Created student weenix repository
Diffstat (limited to 'kernel/proc/context.c')
-rw-r--r--kernel/proc/context.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/kernel/proc/context.c b/kernel/proc/context.c
new file mode 100644
index 0000000..b1902d8
--- /dev/null
+++ b/kernel/proc/context.c
@@ -0,0 +1,150 @@
+
+#include "proc/context.h"
+#include "proc/kthread.h"
+#include <main/cpuid.h>
+
+#include "main/apic.h"
+#include "main/gdt.h"
+
+typedef struct context_initial_func_args
+{
+ context_func_t func;
+ long arg1;
+ void *arg2;
+} packed context_initial_func_args_t;
+
+static void __context_thread_initial_func(context_initial_func_args_t args)
+{
+ preemption_reset();
+ apic_setipl(IPL_LOW);
+ intr_enable();
+
+ void *result = (args.func)(args.arg1, args.arg2);
+ kthread_exit(result);
+
+ panic("\nReturned from kthread_exit.\n");
+}
+
+void context_setup_raw(context_t *c, void (*func)(), void *kstack,
+ size_t kstacksz, pml4_t *pml4)
+{
+ KASSERT(NULL != pml4);
+ KASSERT(PAGE_ALIGNED(kstack));
+ c->c_kstack = (uintptr_t)kstack;
+ c->c_kstacksz = kstacksz;
+ c->c_pml4 = pml4;
+ c->c_rsp = (uintptr_t)kstack + kstacksz;
+ c->c_rsp -= sizeof(uintptr_t);
+ *((uintptr_t *)c->c_rsp) = 0;
+ c->c_rbp = c->c_rsp;
+ c->c_rip = (uintptr_t)func;
+}
+
+/*
+ * Initializes a context_t struct with the given parameters. arg1 and arg2 will
+ * appear as arguments to the function passed in when this context is first
+ * used.
+ */
+void context_setup(context_t *c, context_func_t func, long arg1, void *arg2,
+ void *kstack, size_t kstacksz, pml4_t *pml4)
+{
+ KASSERT(NULL != pml4);
+ KASSERT(PAGE_ALIGNED(kstack));
+
+ c->c_kstack = (uintptr_t)kstack;
+ c->c_kstacksz = kstacksz;
+ c->c_pml4 = pml4;
+
+ /* put the arguments for __context_thread_initial_func onto the
+ * stack */
+ c->c_rsp = (uintptr_t)kstack + kstacksz;
+ c->c_rsp -= sizeof(arg2);
+ *(void **)c->c_rsp = arg2;
+ c->c_rsp -= sizeof(arg1);
+ *(long *)c->c_rsp = arg1;
+ c->c_rsp -= sizeof(context_func_t);
+ *(context_func_t *)c->c_rsp = func;
+ // Take space for the function return address (unused)
+ c->c_rsp -= sizeof(uintptr_t);
+
+ c->c_rbp = c->c_rsp;
+ c->c_rip = (uintptr_t)__context_thread_initial_func;
+}
+
+/*
+ * WARNING!! POTENTIAL EDITOR BEWARE!!
+ * IF YOU REMOVE THE PT_SET CALLS BELOW,
+ * YOU ***MUST*** DEAL WITH SMP TLB SHOOTDOWN
+ *
+ * IN OTHER WORDS, THINK *VERY* CAREFULLY BEFORE
+ * REMOVING THE CALLS TO PT_SET BELOW
+ */
+
+void context_make_active(context_t *c)
+{
+ // gdt_set_kernel_stack((void *)((uintptr_t)c->c_kstack + c->c_kstacksz));
+ pt_set(c->c_pml4);
+
+ /* Switch stacks and run the thread */
+ __asm__ volatile(
+ "movq %0,%%rbp\n\t" /* update rbp */
+ "movq %1,%%rsp\n\t" /* update rsp */
+ "push %2\n\t" /* save rip */
+ "ret" /* jump to new rip */
+ ::"m"(c->c_rbp),
+ "m"(c->c_rsp), "m"(c->c_rip));
+}
+
+void context_switch(context_t *oldc, context_t *newc)
+{
+ gdt_set_kernel_stack(
+ (void *)((uintptr_t)newc->c_kstack + newc->c_kstacksz));
+
+ // sanity check that core-specific data is being managed (paged in)
+ // correctly
+ KASSERT(oldc->c_pml4 == pt_get());
+ uintptr_t curthr_paddr =
+ pt_virt_to_phys_helper(oldc->c_pml4, (uintptr_t)&curthr);
+ uintptr_t new_curthr_paddr =
+ pt_virt_to_phys_helper(newc->c_pml4, (uintptr_t)&curthr);
+
+ kthread_t *prev_curthr = curthr;
+ pt_set(newc->c_pml4);
+ KASSERT(pt_get() == newc->c_pml4);
+
+ KASSERT(curthr_paddr == new_curthr_paddr);
+ KASSERT(prev_curthr == curthr);
+
+ /*
+ * Save the current value of the stack pointer and the frame pointer into
+ * the old context. Set the instruction pointer to the return address
+ * (whoever called us).
+ */
+ __asm__ volatile(
+ "pushfq;" /* save RFLAGS on the stack */
+ "pushq %%rbp \n" /* save base pointer */
+ "pushq %%rbx \n" /* save other callee-saved registers */
+ "pushq %%r12 \n"
+ "pushq %%r13 \n"
+ "pushq %%r14 \n"
+ "pushq %%r15 \n"
+ "movq %%rsp, %0 \n" /* save RSP into oldc */
+ "movq %2, %%rsp \n" /* restore RSP from newc */
+ "pushq %%rax\n\t"
+ "movabs $1f, %%rax \n\t" /* save RIP into oldc (saves the label '1'
+ below) */
+ "mov %%rax, %1\n\t"
+ "popq %%rax\n\t"
+ "pushq %3 \n\t" /* restore RIP */
+ "ret \n\t"
+ "1:\t" /* this is where oldc starts executing later */
+ "popq %%r15 \n\t" /* restore callee-saved registers */
+ "popq %%r14 \n\t"
+ "popq %%r13 \n\t"
+ "popq %%r12 \n\t"
+ "popq %%rbx \n\t"
+ "popq %%rbp \n\t" /* restore base pointer */
+ "popfq" /* restore RFLAGS */
+ : "=m"(oldc->c_rsp), "=m"(oldc->c_rip)
+ : "m"(newc->c_rsp), "m"(newc->c_rip));
+}