Add parlib/common.h
[akaros.git] / user / parlib / include / riscv / vcore.h
1 #ifndef PARLIB_ARCH_VCORE_H
2 #define PARLIB_ARCH_VCORE_H
3
4 #include <parlib/common.h>
5 #include <ros/trapframe.h>
6 #include <parlib/arch/arch.h>
7 #include <ros/syscall.h>
8 #include <ros/procdata.h>
9 #include <assert.h>
10 #include <sys/tls.h>
11
12 __BEGIN_DECLS
13
14 #ifdef __riscv64
15 # define REG_L "ld"
16 # define REG_S "sd"
17 #else
18 # define REG_L "lw"
19 # define REG_S "sw"
20 #endif
21
22 /* Register saves and restores happen in asm. */
23 typedef void (*helper_fn)(struct hw_trapframe*, struct preempt_data*, uint32_t);
24 void __pop_ros_tf_regs(struct hw_trapframe *tf, struct preempt_data* vcpd,
25                     uint32_t vcoreid, helper_fn helper) __attribute__((noreturn));
26 void __save_ros_tf_regs(struct hw_trapframe *tf) __attribute__((returns_twice));
27
28 /* Helper function that may handle notifications after re-enabling them. */
29 static void __pop_ros_tf_notifs(struct hw_trapframe *tf,
30                                 struct preempt_data* vcpd, uint32_t vcoreid)
31 {
32         vcpd->notif_disabled = FALSE;
33
34         __sync_synchronize();
35
36         if(vcpd->notif_pending)
37                 ros_syscall(SYS_self_notify, vcoreid, 0, 0, 0, 0, 0);
38 }
39
40 /* Helper function that won't handle notifications after re-enabling them. */
41 static void __pop_ros_tf_notifs_raw(struct hw_trapframe *tf,
42                                     struct preempt_data* vcpd, uint32_t vcoreid)
43 {
44         vcpd->notif_disabled = FALSE;
45 }
46
47 static inline void __pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid,
48                                 helper_fn helper)
49 {
50         // since we're changing the stack, move stuff into regs for now
51         register uint32_t _vcoreid = vcoreid;
52         register struct hw_trapframe* _tf = tf;
53
54         set_stack_pointer((void*)tf->gpr[GPR_SP]);
55
56         tf = _tf;
57         vcoreid = _vcoreid;
58         struct preempt_data* vcpd = &__procdata.vcore_preempt_data[vcoreid];
59         __pop_ros_tf_regs(tf, vcpd, vcoreid, helper);
60 }
61
62 /* Pops a user context, reanabling notifications at the same time.  A Userspace
63  * scheduler can call this when transitioning off the transition stack.
64  *
65  * Make sure you clear the notif_pending flag, and then check the queue before
66  * calling this.  If notif_pending is not clear, this will self_notify this
67  * core, since it should be because we missed a notification message while
68  * notifs were disabled. 
69  *
70  * The important thing is that it can a notification after it enables
71  * notifications, and when it gets resumed it can ultimately run the new
72  * context.  Enough state is saved in the running context and stack to continue
73  * running. */
74 static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid)
75 {
76         struct hw_trapframe *tf = &ctx->tf.hw_tf;
77         assert(ctx->type == ROS_HW_CTX);
78         __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs);
79 }
80
81 /* Like the regular pop_user_ctx, but this one doesn't check or clear
82  * notif_pending. */
83 static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
84 {
85         struct hw_trapframe *tf = &ctx->tf.hw_tf;
86         assert(ctx->type == ROS_HW_CTX);
87         __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw);
88 }
89
90 /* Save the current context/registers into the given ctx, setting the pc of the
91  * tf to the end of this function.  You only need to save that which you later
92  * restore with pop_user_ctx(). */
93 static inline void save_user_ctx(struct user_context *ctx)
94 {
95         struct hw_trapframe *tf = &ctx->tf.hw_tf;
96         ctx->type = ROS_HW_CTX;
97         __save_ros_tf_regs(tf);
98 }
99
100 static inline void init_user_ctx(struct user_context *ctx, uint32_t entry_pt,
101                                  uint32_t stack_top)
102 {
103         struct hw_trapframe *u_tf = &ctx->tf.hw_tf;
104         ctx->type = ROS_HW_CTX;
105         memset(u_tf, 0, sizeof(*u_tf));
106         u_tf->gpr[GPR_SP] = stack_top;
107         u_tf->epc = entry_pt;
108 }
109
110 #define __vcore_id_on_entry \
111 ({ \
112         register int temp asm ("a0"); \
113         temp; \
114 })
115
116 #error implement these
117 static bool has_refl_fault(struct user_context *ctx)
118 {
119         return 0;
120 }
121
122 static void clear_refl_fault(struct user_context *ctx)
123 {
124 }
125
126 static unsigned int __arch_refl_get_nr(struct user_context *ctx)
127 {
128         return 0;
129 }
130
131 static unsigned int __arch_refl_get_err(struct user_context *ctx)
132 {
133         return 0;
134 }
135
136 static unsigned long __arch_refl_get_aux(struct user_context *ctx)
137 {
138         return 0;
139 }
140
141 __END_DECLS
142
143 #endif /* PARLIB_ARCH_VCORE_H */