Defines new struct user_context (XCC)
[akaros.git] / user / parlib / include / sparc / vcore.h
1 #ifndef PARLIB_ARCH_VCORE_H
2 #define PARLIB_ARCH_VCORE_H
3
4 #include <ros/common.h>
5 #include <ros/trapframe.h>
6 #include <arch/arch.h>
7 #include <ros/syscall.h>
8 #include <ros/procdata.h>
9 #include <assert.h>
10
11 /* Feel free to ignore vcoreid.  It helps x86 to avoid a call to
12  * sys_getvcoreid() if we pass it in. */
13 static inline void *get_tls_desc(uint32_t vcoreid)
14 {
15         void *tmp;
16         asm volatile ("mov %%g7,%0" : "=r"(tmp));
17         return tmp;
18 }
19
20 static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
21 {
22         asm volatile ("mov %0,%%g7" : : "r"(tls_desc) : "memory");
23         __vcoreid = vcoreid;
24 }
25
26 /* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
27  * A Userspace scheduler can call this when transitioning off the transition
28  * stack.
29  *
30  * Make sure you clear the notif_pending flag, and then check the queue before
31  * calling this.  If notif_pending is not clear, this will self_notify this
32  * core, since it should be because we missed a notification message while
33  * notifs were disabled. 
34  *
35  * The important thing is that it can a notification after it enables
36  * notifications, and when it gets resumed it can ultimately run the new
37  * context.  Enough state is saved in the running context and stack to continue
38  * running. */
39 static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
40 {
41         // since we're changing the stack, move stuff into regs for now
42         register uint32_t _vcoreid = vcoreid;
43         register struct user_trapframe* _tf = tf;
44
45         set_stack_pointer((void*)tf->gpr[14]);
46
47         tf = _tf;
48         vcoreid = _vcoreid;
49         struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid];
50
51         // if this is a trap frame we just init'ed, we need to set up TLS
52         if(tf->gpr[7] == 0)
53                 tf->gpr[7] = (uint32_t)get_tls_desc(vcoreid);
54         else
55                 assert(tf->gpr[7] == (uint32_t)get_tls_desc(vcoreid));
56
57         vcpd->notif_disabled = FALSE;
58         if(vcpd->notif_pending)
59                 ros_syscall(SYS_self_notify, vcoreid, 0, 0, 0, 0, 0);
60
61         // tell the kernel to load the new trapframe
62         asm volatile ("mov %0, %%o0; ta 4" : : "r"(tf) : "memory");
63 }
64
65 /* Like the regular pop_ros_tf, but this one doesn't check or clear
66  * notif_pending.  TODO: someone from sparc should look at this. */
67 static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
68 {
69         // since we're changing the stack, move stuff into regs for now
70         register uint32_t _vcoreid = vcoreid;
71         register struct user_trapframe* _tf = tf;
72
73         set_stack_pointer((void*)tf->gpr[14]);
74
75         tf = _tf;
76         vcoreid = _vcoreid;
77         struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid];
78
79         // if this is a trap frame we just init'ed, we need to set up TLS
80         if(tf->gpr[7] == 0)
81                 tf->gpr[7] = (uint32_t)get_tls_desc(vcoreid);
82         else
83                 assert(tf->gpr[7] == (uint32_t)get_tls_desc(vcoreid));
84
85         vcpd->notif_disabled = FALSE;
86         /* This is just like the regular one, but we don't bother with
87          * notif_pending.  This comment is where it was dealt with. */
88
89         // tell the kernel to load the new trapframe
90         asm volatile ("mov %0, %%o0; ta 4" : : "r"(tf) : "memory");
91 }
92
93 /* Save the current context/registers into the given tf, setting the pc of the
94  * tf to the end of this function.  You only need to save that which you later
95  * restore with pop_ros_tf(). */
96 static inline void save_ros_tf(struct user_trapframe *tf)
97 {
98         // just do it in the kernel.  since we need to flush windows anyway,
99         // this isn't an egregious overhead.
100         asm volatile ("mov %0, %%o0; ta 5" : : "r"(tf) : "o0","memory");
101 }
102
103 /* This assumes a user_tf looks like a regular kernel trapframe */
104 static __inline void
105 init_user_tf(struct user_trapframe *u_tf, uint32_t entry_pt, uint32_t stack_top)
106 {
107         memset(u_tf, 0, sizeof(struct user_trapframe));
108         u_tf->gpr[14] = stack_top - 96;
109         u_tf->pc = entry_pt;
110         u_tf->npc = entry_pt + 4;
111 }
112
113 #define __vcore_id_on_entry \
114 ({ \
115         register int temp asm ("g6"); \
116         temp; \
117 })
118
119 #endif /* PARLIB_ARCH_VCORE_H */