Defines new struct user_context (XCC)
[akaros.git] / user / parlib / include / riscv / 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 #include <sys/vcore-tls.h>
11
12 #ifdef __riscv64
13 # define REG_L "ld"
14 # define REG_S "sd"
15 #else
16 # define REG_L "lw"
17 # define REG_S "sw"
18 #endif
19
20 /* Register saves and restores happen in asm. */
21 typedef void (*helper_fn)(struct user_trapframe*, struct preempt_data*, uint32_t);
22 void __pop_ros_tf_regs(struct user_trapframe *tf, struct preempt_data* vcpd,
23                     uint32_t vcoreid, helper_fn helper) __attribute__((noreturn));
24 void __save_ros_tf_regs(struct user_trapframe *tf);
25
26 /* Helper function that may handle notifications after re-enabling them. */
27 static void __pop_ros_tf_notifs(struct user_trapframe *tf,
28                                 struct preempt_data* vcpd, uint32_t vcoreid)
29 {
30         vcpd->notif_disabled = FALSE;
31
32         __sync_synchronize();
33
34         if(vcpd->notif_pending)
35                 ros_syscall(SYS_self_notify, vcoreid, 0, 0, 0, 0, 0);
36 }
37
38 /* Helper function that won't handle notifications after re-enabling them. */
39 static void __pop_ros_tf_notifs_raw(struct user_trapframe *tf,
40                                     struct preempt_data* vcpd, uint32_t vcoreid)
41 {
42         vcpd->notif_disabled = FALSE;
43 }
44
45 static inline void __pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid,
46                                 helper_fn helper)
47 {
48         // since we're changing the stack, move stuff into regs for now
49         register uint32_t _vcoreid = vcoreid;
50         register struct user_trapframe* _tf = tf;
51
52         set_stack_pointer((void*)tf->gpr[30]);
53
54         tf = _tf;
55         vcoreid = _vcoreid;
56         struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid];
57         __pop_ros_tf_regs(tf, vcpd, vcoreid, helper);
58 }
59
60 /* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
61  * A Userspace scheduler can call this when transitioning off the transition
62  * stack.
63  *
64  * Make sure you clear the notif_pending flag, and then check the queue before
65  * calling this.  If notif_pending is not clear, this will self_notify this
66  * core, since it should be because we missed a notification message while
67  * notifs were disabled. 
68  *
69  * The important thing is that it can a notification after it enables
70  * notifications, and when it gets resumed it can ultimately run the new
71  * context.  Enough state is saved in the running context and stack to continue
72  * running. */
73 static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
74 {
75         __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs);
76 }
77
78 /* Like the regular pop_ros_tf, but this one doesn't check or clear
79  * notif_pending. */
80 static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
81 {
82         __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw);
83 }
84
85 /* Save the current context/registers into the given tf, setting the pc of the
86  * tf to the end of this function.  You only need to save that which you later
87  * restore with pop_ros_tf(). */
88 static inline void save_ros_tf(struct user_trapframe *tf)
89 {
90         __save_ros_tf_regs(tf);
91 }
92
93 /* This assumes a user_tf looks like a regular kernel trapframe */
94 static __inline void
95 init_user_tf(struct user_trapframe *u_tf, long entry_pt, long stack_top)
96 {
97         memset(u_tf, 0, sizeof(*u_tf));
98         u_tf->gpr[30] = stack_top;
99         u_tf->epc = entry_pt;
100 }
101
102 #define __vcore_id_on_entry \
103 ({ \
104         register int temp asm ("a0"); \
105         temp; \
106 })
107
108 #endif /* PARLIB_ARCH_VCORE_H */