diff options
Diffstat (limited to 'src/sys/arch')
-rw-r--r-- | src/sys/arch/amd64/os/os_proc.c | 88 |
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; } |