a6605d6eb50926a3e956d77d48e6f311d5f1e9dd
[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 hw_trapframe*, struct preempt_data*, uint32_t);
22 void __pop_ros_tf_regs(struct hw_trapframe *tf, struct preempt_data* vcpd,
23                     uint32_t vcoreid, helper_fn helper) __attribute__((noreturn));
24 void __save_ros_tf_regs(struct hw_trapframe *tf) __attribute__((returns_twice));
25
26 /* Helper function that may handle notifications after re-enabling them. */
27 static void __pop_ros_tf_notifs(struct hw_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 hw_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 hw_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 hw_trapframe* _tf = tf;
51
52         set_stack_pointer((void*)tf->gpr[GPR_SP]);
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 a user context, reanabling notifications at the same time.  A Userspace
61  * scheduler can call this when transitioning off the transition stack.
62  *
63  * Make sure you clear the notif_pending flag, and then check the queue before
64  * calling this.  If notif_pending is not clear, this will self_notify this
65  * core, since it should be because we missed a notification message while
66  * notifs were disabled. 
67  *
68  * The important thing is that it can a notification after it enables
69  * notifications, and when it gets resumed it can ultimately run the new
70  * context.  Enough state is saved in the running context and stack to continue
71  * running. */
72 static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid)
73 {
74         struct hw_trapframe *tf = &ctx->tf.hw_tf;
75         assert(ctx->type == ROS_HW_CTX);
76         __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs);
77 }
78
79 /* Like the regular pop_user_ctx, but this one doesn't check or clear
80  * notif_pending. */
81 static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
82 {
83         struct hw_trapframe *tf = &ctx->tf.hw_tf;
84         assert(ctx->type == ROS_HW_CTX);
85         __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw);
86 }
87
88 /* Save the current context/registers into the given ctx, setting the pc of the
89  * tf to the end of this function.  You only need to save that which you later
90  * restore with pop_user_ctx(). */
91 static inline void save_user_ctx(struct user_context *ctx)
92 {
93         struct hw_trapframe *tf = &ctx->tf.hw_tf;
94         ctx->type = ROS_HW_CTX;
95         __save_ros_tf_regs(tf);
96 }
97
98 static inline void init_user_ctx(struct user_context *ctx, uint32_t entry_pt,
99                                  uint32_t stack_top)
100 {
101         struct hw_trapframe *u_tf = &ctx->tf.hw_tf;
102         ctx->type = ROS_HW_CTX;
103         memset(u_tf, 0, sizeof(*u_tf));
104         u_tf->gpr[GPR_SP] = stack_top;
105         u_tf->epc = entry_pt;
106 }
107
108 #define __vcore_id_on_entry \
109 ({ \
110         register int temp asm ("a0"); \
111         temp; \
112 })
113
114 #error implement these
115 static bool has_refl_fault(struct user_context *ctx)
116 {
117         return 0;
118 }
119
120 static void clear_refl_fault(struct user_context *ctx)
121 {
122 }
123
124 static unsigned int __arch_refl_get_nr(struct user_context *ctx)
125 {
126         return 0;
127 }
128
129 static unsigned int __arch_refl_get_err(struct user_context *ctx)
130 {
131         return 0;
132 }
133
134 static unsigned long __arch_refl_get_aux(struct user_context *ctx)
135 {
136         return 0;
137 }
138
139 #endif /* PARLIB_ARCH_VCORE_H */