blob: 3cd2592903ec8264416f2afaecbad292ae607bd1 [file] [log] [blame]
#include <arch/arch.h>
#include <trap.h>
#include <process.h>
#include <pmap.h>
#include <smp.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
void proc_pop_ctx(struct user_context *ctx)
{
disable_irq();
/* for both HW and SW, note we pass an offset into the TF, beyond the fs and
* gs bases */
if (ctx->type == ROS_HW_CTX) {
struct hw_trapframe *tf = &ctx->tf.hw_tf;
write_msr(MSR_GS_BASE, (uint64_t)tf->tf_gsbase);
write_msr(MSR_FS_BASE, (uint64_t)tf->tf_fsbase);
asm volatile ("movq %0, %%rsp; "
"popq %%rax; "
"popq %%rbx; "
"popq %%rcx; "
"popq %%rdx; "
"popq %%rbp; "
"popq %%rsi; "
"popq %%rdi; "
"popq %%r8; "
"popq %%r9; "
"popq %%r10; "
"popq %%r11; "
"popq %%r12; "
"popq %%r13; "
"popq %%r14; "
"popq %%r15; "
"addq $0x10, %%rsp; "
"iretq "
: : "g" (&tf->tf_rax) : "memory");
panic("iretq failed");
} else {
struct sw_trapframe *tf = &ctx->tf.sw_tf;
write_msr(MSR_GS_BASE, (uint64_t)tf->tf_gsbase);
write_msr(MSR_FS_BASE, (uint64_t)tf->tf_fsbase);
/* We need to 0 out any registers that aren't part of the sw_tf and that
* we won't use/clobber on the out-path. While these aren't part of the
* sw_tf, we also don't want to leak any kernel register content. */
asm volatile ("movq %0, %%rsp; "
"movq $0, %%rax; "
"movq $0, %%rdx; "
"movq $0, %%rsi; "
"movq $0, %%rdi; "
"movq $0, %%r8; "
"movq $0, %%r9; "
"movq $0, %%r10; "
"popq %%rbx; "
"popq %%rbp; "
"popq %%r12; "
"popq %%r13; "
"popq %%r14; "
"popq %%r15; "
"movq %1, %%r11; "
"popq %%rcx; "
"popq %%rsp; "
"rex.w sysret "
: : "g"(&tf->tf_rbx), "i"(FL_IF) : "memory");
panic("sysret failed");
}
panic("Unknown context type!\n");
}
/* Helper: if *addr isn't a canonical user address, poison it. Use this when
* you need a canonical address (like MSR_FS_BASE) */
static void enforce_user_canon(uintptr_t *addr)
{
if (*addr >> 47 != 0)
*addr = 0x5a5a5a5a;
}
/* TODO: consider using a SW context */
void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
uintptr_t stack_top, uintptr_t tls_desc)
{
struct hw_trapframe *tf = &ctx->tf.hw_tf;
ctx->type = ROS_HW_CTX;
memset(tf, 0, sizeof(*tf));
/* Set up appropriate initial values for the segment registers.
* GD_UD is the user data segment selector in the GDT, and
* GD_UT is the user text segment selector (see inc/memlayout.h).
* The low 2 bits of each segment register contains the
* Requestor Privilege Level (RPL); 3 means user mode. */
tf->tf_ss = GD_UD | 3;
/* Stack pointers in a fresh stackframe need to be such that adding or
* subtracting 8 will result in 16 byte alignment (AMD64 ABI). The reason
* is so that input arguments (on the stack) are 16 byte aligned. The
* extra 8 bytes is the retaddr, pushed on the stack. Compilers know they
* can subtract 8 to get 16 byte alignment for instructions like movaps. */
tf->tf_rsp = ROUNDDOWN(stack_top, 16) - 8;
tf->tf_cs = GD_UT | 3;
/* set the env's EFLAGSs to have interrupts enabled */
tf->tf_rflags |= 0x00000200; // bit 9 is the interrupts-enabled
tf->tf_rip = entryp;
/* Coupled closely with user's entry.S. id is the vcoreid, which entry.S
* uses to determine what to do. vcoreid == 0 is the main core/context. */
tf->tf_rax = vcoreid;
tf->tf_fsbase = tls_desc;
enforce_user_canon(&tf->tf_fsbase);
}
void proc_secure_ctx(struct user_context *ctx)
{
if (ctx->type == ROS_SW_CTX) {
struct sw_trapframe *tf = &ctx->tf.sw_tf;
enforce_user_canon(&tf->tf_gsbase);
enforce_user_canon(&tf->tf_fsbase);
} else {
/* If we aren't SW, we're assuming (and forcing) a HW ctx. If this is
* somehow fucked up, userspace should die rather quickly. */
struct hw_trapframe *tf = &ctx->tf.hw_tf;
ctx->type = ROS_HW_CTX;
enforce_user_canon(&tf->tf_gsbase);
enforce_user_canon(&tf->tf_fsbase);
tf->tf_ss = GD_UD | 3;
tf->tf_cs = GD_UT | 3;
tf->tf_rflags |= 0x00000200; // bit 9 is the interrupts-enabled
}
}
/* Called when we are currently running an address space on our core and want to
* abandon it. We need a known good pgdir before releasing the old one. We
* decref, since current no longer tracks the proc (and current no longer
* protects the cr3). */
void __abandon_core(void)
{
struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
lcr3(boot_cr3);
proc_decref(pcpui->cur_proc);
pcpui->cur_proc = 0;
}