Use fprintf() for printing user TFs
[akaros.git] / user / parlib / include / parlib / vcore.h
1 #pragma once
2
3 #include <parlib/arch/vcore.h>
4 #include <parlib/arch/atomic.h>
5 #include <sys/param.h>
6 #include <string.h>
7 #include <parlib/timing.h>
8 #include <parlib/common.h>
9 #include <stdio.h>
10
11 __BEGIN_DECLS
12
13 /*****************************************************************************/
14 /* TODO: This is a complete hack, but necessary for vcore stuff to work for now
15  * The issue is that exit sometimes calls sys_yield(), and we can't recover from
16  * that properly under our vcore model (we shouldn't though).  We really need to
17  * rethink what sys_yield 'should' do when in multicore mode, or else come up 
18  * with a different syscall entirely. */
19 #undef exit
20 extern void _exit (int status);
21 extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
22 #define exit(status) _exit(status)
23 /*****************************************************************************/
24
25 #define TRANSITION_STACK_PAGES 2
26 #define TRANSITION_STACK_SIZE (TRANSITION_STACK_PAGES*PGSIZE)
27
28 /* Defined in vcore.c */
29 void __attribute__((noreturn)) vcore_entry(void);
30 extern __thread bool __vcore_context;
31 extern __thread int __vcoreid;
32 extern __thread struct syscall __vcore_one_sysc;        /* see sys_change_vcore */
33
34 /* Arch specific entry from the kernel */
35 void __attribute__((noreturn)) __kernel_vcore_entry(void);
36
37 /* Vcore API functions */
38 static inline uint32_t max_vcores(void);
39 static inline uint32_t num_vcores(void);
40 static inline int vcore_id(void);
41 static inline bool in_vcore_context(void);
42 static inline bool in_multi_mode(void);
43 static inline void __enable_notifs(uint32_t vcoreid);
44 static inline void __disable_notifs(uint32_t vcoreid);
45 static inline bool notif_is_enabled(uint32_t vcoreid);
46 static inline bool vcore_is_mapped(uint32_t vcoreid);
47 static inline bool vcore_is_preempted(uint32_t vcoreid);
48 static inline struct preempt_data *vcpd_of(uint32_t vcoreid);
49 static inline bool preempt_is_pending(uint32_t vcoreid);
50 static inline bool __preempt_is_pending(uint32_t vcoreid);
51 static inline void *get_vcpd_tls_desc(uint32_t vcoreid);
52 static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc);
53 static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid);
54 static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid);
55 void vcore_lib_init(void);
56 void vcore_change_to_m(void);
57 void vcore_request_more(long nr_new_vcores);
58 void vcore_request_total(long nr_vcores_wanted);
59 void vcore_yield(bool preempt_pending);
60 void vcore_reenter(void (*entry_func)(void));
61 void enable_notifs(uint32_t vcoreid);
62 void disable_notifs(uint32_t vcoreid);
63 void vcore_idle(void);
64 void ensure_vcore_runs(uint32_t vcoreid);
65 void cpu_relax_vc(uint32_t vcoreid);
66 uint32_t get_vcoreid(void);
67 bool check_vcoreid(const char *str, uint32_t vcoreid);
68 void __attribute__((noreturn)) vcore_yield_or_restart(void);
69 void fprintf_hw_tf(FILE *f, struct hw_trapframe *hw_tf);
70 void fprintf_sw_tf(FILE *f, struct sw_trapframe *sw_tf);
71 void fprintf_vm_tf(FILE *f, struct vm_trapframe *vm_tf);
72 void print_user_context(struct user_context *ctx);
73
74 /* This works so long as we don't dlopen parlib (which we never do) */
75 #define get_tlsvar_linaddr(_vcoreid, _var)                                     \
76 ({                                                                             \
77         uintptr_t vc_tls_desc = (uintptr_t)get_vcpd_tls_desc(_vcoreid);            \
78         uintptr_t var_off = (uintptr_t)&_var - (uintptr_t)get_tls_desc();          \
79         (typeof(_var) *)(vc_tls_desc + var_off);                                   \
80 })
81
82 /* Static inlines */
83 static inline uint32_t max_vcores(void)
84 {
85         return MAX(1, __procinfo.max_vcores);
86 }
87
88 static inline uint32_t num_vcores(void)
89 {
90         return __procinfo.num_vcores;
91 }
92
93 static inline int vcore_id(void)
94 {
95         return __vcoreid;
96 }
97
98 static inline bool in_vcore_context(void)
99 {
100         return __vcore_context;
101 }
102
103 static inline bool in_multi_mode(void)
104 {
105         return __procinfo.is_mcp;
106 }
107
108 /* Only call this if you know what you are doing. */
109 static inline void __enable_notifs(uint32_t vcoreid)
110 {
111         vcpd_of(vcoreid)->notif_disabled = FALSE;
112 }
113
114 static inline void __disable_notifs(uint32_t vcoreid)
115 {
116         vcpd_of(vcoreid)->notif_disabled = TRUE;
117 }
118
119 static inline bool notif_is_enabled(uint32_t vcoreid)
120 {
121         return !vcpd_of(vcoreid)->notif_disabled;
122 }
123
124 static inline bool vcore_is_mapped(uint32_t vcoreid)
125 {
126         return __procinfo.vcoremap[vcoreid].valid;
127 }
128
129 /* We could also check for VC_K_LOCK, but that's a bit much. */
130 static inline bool vcore_is_preempted(uint32_t vcoreid)
131 {
132         struct preempt_data *vcpd = vcpd_of(vcoreid);
133         return atomic_read(&vcpd->flags) & VC_PREEMPTED;
134 }
135
136 static inline struct preempt_data *vcpd_of(uint32_t vcoreid)
137 {
138         return &__procdata.vcore_preempt_data[vcoreid];
139 }
140
141 /* Uthread's can call this in case they care if a preemption is coming.  If a
142  * preempt is incoming, this will return TRUE, if you are in uthread context.  A
143  * reasonable response for a uthread is to yield, and vcore_entry will deal with
144  * the preempt pending.
145  *
146  * If you call this from vcore context, it will do nothing.  In general, it's
147  * not safe to just yield (or do whatever you plan on doing) from arbitrary
148  * places in vcore context.  So we just lie about PP. */
149 static inline bool preempt_is_pending(uint32_t vcoreid)
150 {
151         if (in_vcore_context())
152                 return FALSE;
153         return __preempt_is_pending(vcoreid);
154 }
155
156 static inline bool __preempt_is_pending(uint32_t vcoreid)
157 {
158         return __procinfo.vcoremap[vcoreid].preempt_pending;
159 }
160
161 /* The kernel interface uses uintptr_t, but we have a lot of older code that
162  * uses void *, hence the casting. */
163 static inline void *get_vcpd_tls_desc(uint32_t vcoreid)
164 {
165         return (void*)__procdata.vcore_preempt_data[vcoreid].vcore_tls_desc;
166 }
167
168 static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc)
169 {
170         __procdata.vcore_preempt_data[vcoreid].vcore_tls_desc = (uintptr_t)tls_desc;
171 }
172
173 static inline uint64_t vcore_account_resume_ticks(uint32_t vcoreid)
174 {
175         return __procinfo.vcoremap[vcoreid].resume_ticks;
176 }
177
178 static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid)
179 {
180         return tsc2nsec(vcore_account_resume_ticks(vcoreid));
181 }
182
183 static inline uint64_t vcore_account_total_ticks(uint32_t vcoreid)
184 {
185         return __procinfo.vcoremap[vcoreid].total_ticks;
186 }
187
188 static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid)
189 {
190         return tsc2nsec(vcore_account_total_ticks(vcoreid));
191 }
192
193 static inline uint64_t vcore_account_uptime_ticks(uint32_t vcoreid)
194 {
195         uint64_t resume = __procinfo.vcoremap[vcoreid].resume_ticks; 
196         uint64_t total = __procinfo.vcoremap[vcoreid].total_ticks; 
197         uint64_t now = read_tsc();
198         return now - resume + total;
199 }
200
201 static inline uint64_t vcore_account_uptime_nsec(uint32_t vcoreid)
202 {
203         return tsc2nsec(vcore_account_uptime_ticks(vcoreid));
204 }
205
206 #ifndef __PIC__
207
208 #define begin_safe_access_tls_vars()
209
210 #define end_safe_access_tls_vars()
211
212 #else
213
214 #include <features.h>
215
216 /* These macro acrobatics trick the compiler into not caching the (linear)
217  * address of TLS variables across loads/stores of the TLS descriptor, in lieu
218  * of a "TLS cmb()". */
219 #define begin_safe_access_tls_vars()                                           \
220 {                                                                              \
221         void __attribute__((noinline, optimize("O0")))                             \
222         safe_access_tls_var_internal() {                                           \
223                 asm("");                                                               \
224
225 #define end_safe_access_tls_vars()                                             \
226         } safe_access_tls_var_internal();                                          \
227 }
228
229 #endif // __PIC__
230
231 /* Switches into the TLS 'tls_desc'.  Capable of being called from either
232  * uthread or vcore context.  Pairs with end_access_tls_vars(). */
233 #define begin_access_tls_vars(tls_desc)                                        \
234 {                                                                              \
235         struct uthread *caller;                                                    \
236         uint32_t vcoreid;                                                          \
237         void *temp_tls_desc;                                                       \
238         bool invcore = in_vcore_context();                                         \
239         if (!invcore) {                                                            \
240                 caller = current_uthread;                                              \
241                 /* If you have no current_uthread, you might be called too early in the
242                  * process's lifetime.  Make sure something like uthread_slim_init() has
243                  * been run. */                                                        \
244                 assert(caller);                                                        \
245                 /* We need to disable notifs here (in addition to not migrating), since
246                  * we could get interrupted when we're in the other TLS, and when the
247                  * vcore restarts us, it will put us in our old TLS, not the one we were
248                  * in when we were interrupted.  We need to not migrate, since once we
249                  * know the vcoreid, we depend on being on the same vcore throughout.*/\
250                 caller->flags |= UTHREAD_DONT_MIGRATE;                                 \
251                 /* Not concerned about cross-core memory ordering, so no CPU mbs needed.
252                  * The cmb is to prevent the compiler from issuing the vcore read before
253                  * the DONT_MIGRATE write. */                                          \
254                 cmb();                                                                 \
255                 vcoreid = vcore_id();                                                  \
256                 disable_notifs(vcoreid);                                               \
257         } else { /* vcore context */                                               \
258                 vcoreid = vcore_id();                                                  \
259         }                                                                          \
260         temp_tls_desc = get_tls_desc();                                            \
261         set_tls_desc(tls_desc);                                                    \
262         begin_safe_access_tls_vars();
263
264 #define end_access_tls_vars()                                                  \
265         end_safe_access_tls_vars();                                                \
266         set_tls_desc(temp_tls_desc);                                               \
267         if (!invcore) {                                                            \
268                 /* Note we reenable migration before enabling notifs, which is reverse
269                  * from how we disabled notifs.  We must enabling migration before
270                  * enabling notifs.  See 6c7fb12 and 5e4825eb4 for details. */         \
271                 caller->flags &= ~UTHREAD_DONT_MIGRATE;                                \
272                 cmb();  /* turn off DONT_MIGRATE before enabling notifs */             \
273                 enable_notifs(vcoreid);                                                \
274         }                                                                          \
275 }
276
277 #define safe_set_tls_var(name, val)                                            \
278 ({                                                                             \
279         begin_safe_access_tls_vars();                                              \
280         name = val;                                                                \
281         end_safe_access_tls_vars();                                                \
282 })
283
284 #define safe_get_tls_var(name)                                                 \
285 ({                                                                             \
286         typeof(name) __val;                                                        \
287         begin_safe_access_tls_vars();                                              \
288         __val = name;                                                              \
289         end_safe_access_tls_vars();                                                \
290         __val;                                                                     \
291 })
292
293 #define vcore_set_tls_var(name, val)                                           \
294 ({                                                                             \
295         typeof(val) __val = val;                                                   \
296         begin_access_tls_vars(get_vcpd_tls_desc(vcoreid));                         \
297         name = __val;                                                              \
298         end_access_tls_vars();                                                     \
299 })
300
301 #define vcore_get_tls_var(name)                                                \
302 ({                                                                             \
303         typeof(name) val;                                                          \
304         begin_access_tls_vars(get_vcpd_tls_desc(vcoreid));                         \
305         val = name;                                                                \
306         end_access_tls_vars();                                                     \
307         val;                                                                       \
308 })
309
310 __END_DECLS