summaryrefslogtreecommitdiff
path: root/src/sys/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/arch')
-rw-r--r--src/sys/arch/amd64/os/os_proc.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/sys/arch/amd64/os/os_proc.c b/src/sys/arch/amd64/os/os_proc.c
index 8fad7b6..7a65b34 100644
--- a/src/sys/arch/amd64/os/os_proc.c
+++ b/src/sys/arch/amd64/os/os_proc.c
@@ -30,8 +30,44 @@
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/syslog.h>
+#include <sys/cdefs.h>
#include <vm/mmu.h>
+#include <vm/map.h>
#include <machine/pcb.h>
+#include <machine/gdt.h>
+#include <machine/frame.h>
+#include <string.h>
+
+/*
+ * Put the current process into userland for its first
+ * run. The catch is that we have never been in userland
+ * from this context so we'll have to fake an IRET frame
+ * to force the processor to have a CPL of 3.
+ *
+ * @tfp: Trapframe of context to enter
+ */
+static inline void
+__proc_kick(struct trapframe *tfp)
+{
+ __ASMV(
+ "sti\n"
+ "mov %0, %%rax\n"
+ "push %1\n"
+ "push %2\n"
+ "push %3\n"
+ "push %%rax\n"
+ "push %4\n"
+ "lfence\n"
+ "swapgs\n"
+ "iretq"
+ :
+ : "r" (tfp->cs),
+ "i" (USER_DS | 3),
+ "r" (tfp->rsp),
+ "m" (tfp->rflags),
+ "r" (tfp->rip)
+ );
+}
/*
* MD proc init code
@@ -40,6 +76,9 @@ int
md_proc_init(struct proc *procp, int flags)
{
struct md_pcb *pcbp;
+ struct trapframe *tfp;
+ struct mmu_map spec;
+ uint8_t cs, ds;
int error;
if (procp == NULL) {
@@ -51,5 +90,54 @@ md_proc_init(struct proc *procp, int flags)
printf("md_proc_init: could not create new vas\n");
return error;
}
+
+ ds = USER_DS | 3;
+ cs = USER_CS | 3;
+
+ /*
+ * Set up the mapping specifier, we'll use zero
+ * to allocate new pages.
+ */
+ spec.pa = 0;
+ spec.va = STACK_TOP;
+
+ /* Put the trapframe in a known state */
+ tfp = &pcbp->tf;
+ memset(tfp, 0, sizeof(*tfp));
+ tfp->rflags = 0x202;
+ tfp->cs = cs;
+ tfp->ss = ds;
+
+ /* Map the stack */
+ vm_map(
+ &pcbp->vas, &spec,
+ STACK_LEN,
+ PROT_READ
+ | PROT_WRITE
+ | PROT_USER
+ );
+
+ tfp->rsp = STACK_TOP;
+ return 0;
+}
+
+/*
+ * Set process instruction pointer
+ */
+int
+md_set_ip(struct proc *procp, uintptr_t ip)
+{
+ struct md_pcb *pcbp;
+ struct trapframe *tfp;
+
+ if (procp == NULL) {
+ return -EINVAL;
+ }
+
+ pcbp = &procp->pcb;
+ tfp = &pcbp->tf;
+ tfp->rip = ip;
+ mmu_write_vas(&procp->pcb.vas);
+ __proc_kick(tfp);
return 0;
}