parlib: Remove get_user_ctx_stack()
[akaros.git] / user / parlib / include / parlib / x86 / vcore.h
1 #pragma once
2
3 #include <parlib/common.h>
4 #include <ros/trapframe.h>
5 #include <ros/procdata.h>
6 #include <ros/syscall.h>
7 #include <ros/arch/mmu.h>
8 #include <sys/tls.h>
9
10 __BEGIN_DECLS
11
12 void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid);
13 void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid);
14
15 /* Save's a SW context, setting the PC to the end of this function.  We only
16  * save callee-saved registers (of the sysv abi).  The compiler knows to save
17  * the others via the input/clobber lists.
18  *
19  * Callers of this function need to have at least one
20  * 'calling-convention-compliant' function call between this and any floating
21  * point, so that the compiler saves any caller-saved FP before getting to
22  * here.
23  *
24  * To some extent, TLS is 'callee-saved', in that no one ever expects it to
25  * change.  We handle uthread TLS changes separately, since we often change to
26  * them early to set some variables.  Arguably we should do this different. */
27 static inline void save_user_ctx(struct user_context *ctx)
28 {
29         struct sw_trapframe *sw_tf = &ctx->tf.sw_tf;
30         long dummy;
31
32         ctx->type = ROS_SW_CTX;
33         asm volatile ("stmxcsr %0" : "=m"(sw_tf->tf_mxcsr));
34         asm volatile ("fnstcw %0" : "=m"(sw_tf->tf_fpucw));
35         /* Pretty simple: save all the regs, IAW the sys-v ABI */
36         asm volatile("mov %%rsp, 0x48(%0);   " /* save rsp in its slot*/
37                      "leaq 1f(%%rip), %%rax; " /* get future rip */
38                      "mov %%rax, 0x40(%0);   " /* save rip in its slot*/
39                      "mov %%r15, 0x38(%0);   "
40                      "mov %%r14, 0x30(%0);   "
41                      "mov %%r13, 0x28(%0);   "
42                      "mov %%r12, 0x20(%0);   "
43                      "mov %%rbp, 0x18(%0);   "
44                      "mov %%rbx, 0x10(%0);   "
45                      "1:                     " /* where this tf will restart */
46                      : "=D"(dummy) /* force clobber for rdi */
47                                  : "D"(sw_tf)
48                      : "rax", "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11",
49                        "memory", "cc");
50 } __attribute__((always_inline, returns_twice))
51
52 /* The old version, kept around for testing */
53 /* Hasn't been used yet for 64 bit.  If you use this, it's worth checking to
54  * make sure rax isn't selected for 0, 1, or 2. (and we probably don't need to
55  * save rax in the beginning) */
56 static inline void save_user_ctx_hw(struct user_context *ctx)
57 {
58         struct hw_trapframe *tf = &ctx->tf.hw_tf;
59
60         ctx->type = ROS_HW_CTX;
61         memset(tf, 0, sizeof(struct hw_trapframe)); /* sanity */
62         /* set CS and make sure eflags is okay */
63         tf->tf_cs = GD_UT | 3;
64         tf->tf_rflags = 0x200; /* interrupts enabled.  bare minimum rflags. */
65         /* Save the regs and the future rsp. */
66         asm volatile("movq %%rsp, (%0);      " /* save rsp in it's slot*/
67                      "pushq %%rax;           " /* temp save rax */
68                      "leaq 1f, %%rax;        " /* get future rip */
69                      "movq %%rax, (%1);      " /* store future rip */
70                      "popq %%rax;            " /* restore rax */
71                      "movq %2, %%rsp;        " /* move to the rax slot of the tf */
72                      "addl $0x78,%%esp;      " /* move to just past r15 */
73                      "pushq %%r15;           " /* save regs */
74                      "pushq %%r14;           "
75                      "pushq %%r13;           "
76                      "pushq %%r12;           "
77                      "pushq %%r11;           "
78                      "pushq %%r10;           "
79                      "pushq %%r9;            "
80                      "pushq %%r8;            "
81                      "pushq %%rdi;           "
82                      "pushq %%rsi;           "
83                      "pushq %%rbp;           "
84                      "pushq %%rdx;           "
85                      "pushq %%rcx;           "
86                      "pushq %%rbx;           "
87                      "pushq %%rax;           "
88                      "addq $0xa0, %%rsp;     " /* move to rsp slot */
89                      "popq %%rsp;            " /* restore saved/original rsp */
90                      "1:                     " /* where this tf will restart */
91                      :
92                      : "g"(&tf->tf_rsp), "g"(&tf->tf_rip), "g"(tf->tf_rax)
93                      : "rax", "memory", "cc");
94 } __attribute__((always_inline, returns_twice))
95
96 static inline void init_user_ctx(struct user_context *ctx, uintptr_t entry_pt,
97                                  uintptr_t stack_top)
98 {
99         struct sw_trapframe *sw_tf = &ctx->tf.sw_tf;
100
101         ctx->type = ROS_SW_CTX;
102         /* Stack pointers in a fresh stackframe need to be such that adding or
103          * subtracting 8 will result in 16 byte alignment (AMD64 ABI).  The reason
104          * is so that input arguments (on the stack) are 16 byte aligned.  The
105          * extra 8 bytes is the retaddr, pushed on the stack.  Compilers know they
106          * can subtract 8 to get 16 byte alignment for instructions like movaps. */
107         sw_tf->tf_rsp = ROUNDDOWN(stack_top, 16) - 8;
108         sw_tf->tf_rip = entry_pt;
109         sw_tf->tf_rbp = 0;      /* for potential backtraces */
110         /* No need to bother with setting the other GP registers; the called
111          * function won't care about their contents. */
112         sw_tf->tf_mxcsr = 0x00001f80;   /* x86 default mxcsr */
113         sw_tf->tf_fpucw = 0x037f;               /* x86 default FP CW */
114 }
115
116 // this is how we get our thread id on entry.
117 #define __vcore_id_on_entry \
118 ({ \
119         register int temp asm ("rbx"); \
120         temp; \
121 })
122
123 __END_DECLS