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