x86 userspace uses software contexts (XCC)
[akaros.git] / user / c3po / threads / ucontext.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdarg.h>
4 #include <threadlib_internal.h>
5 #include <vcore.h>
6 #include <ucontext.h>
7
8
9 /* Maintain a static reference to the main threads tls region */
10 static void *__main_tls_desc;
11
12 struct u_context* create_context(thread_t *t, void *entry_pt, void *stack_top)
13 {
14         uint32_t vcoreid = vcore_id();
15
16         /* Allocate a new context struct */
17         /* TODO: careful of alignment here */
18         struct u_context *uc = malloc(sizeof(struct u_context));
19         if(!uc) return NULL;
20
21         /* If we are the main thread, then current_thread has not been set yet, so
22          * we set the tls descriptor to the tls on the currently running core */
23         if(current_thread == NULL) {
24                 /* Make sure this only executes once! */
25                 static int done = FALSE;
26                 assert(!done); done = TRUE;
27
28                 /* Set up the tls regions for the main thred */
29                 uc->tls_desc = get_tls_desc(vcoreid);
30                 __main_tls_desc = uc->tls_desc;
31
32                 /* And set the current thread in this tls region */
33                 current_thread = t;
34         }
35     /* Otherwise, allocate a new tls region for this context */
36         else {
37                 /* Allocate the tls, freeing the whole uc if it fails */
38         uc->tls_desc = allocate_tls();
39                 if(!uc->tls_desc) {
40                         free(uc);
41                         return NULL;
42                 }
43                 /* Temporarily switch into the new the context's tls region to set the
44                  * current_thread variable in that tls region */
45                 void *temp_tls = get_tls_desc(vcoreid);
46                 set_tls_desc(uc->tls_desc, vcoreid);
47                 current_thread = t;
48                 /* Then switch back to the origin one */
49                 set_tls_desc(temp_tls, vcoreid);
50         }
51
52         /* For good measure, also save the thread associated with this context in
53          * the ucontext struct */
54         uc->thread = t;
55
56         /* Initialize the trapframe for this context */
57         init_user_ctx(&uc->u_ctx, (uint32_t)entry_pt, (uint32_t)stack_top);
58         return uc;
59 }
60
61 void save_context(struct u_context *uc)
62 {
63         /* Save the trapframe for this context */
64         save_user_ctx(&uc->u_ctx);
65 }
66
67 void restore_context(struct u_context *uc)
68 {
69         uint32_t vcoreid = vcore_id();
70
71         /* Save the thread we are about to restore into current_thread
72          * in this vcores tls region */
73         current_thread = uc->thread;
74         /* Set the proper tls descriptor for the context we are restoring */
75     set_tls_desc(uc->tls_desc, vcoreid);
76         /* Tell the uthread which vcore it is on */
77         __vcoreid = vcoreid;
78         /* Pop the trapframe */
79         pop_user_ctx(&uc->u_ctx, vcoreid);
80 }
81
82 void destroy_context(struct u_context *uc)
83 {
84     extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
85
86         /* Make sure we have passed in Non-Null pointers for our ucontext / tls */
87     assert(uc);
88     assert(uc->tls_desc);
89
90         /* Dont' deallocate the main tls descriptor, glibc will do that */
91         if(uc->tls_desc != __main_tls_desc)
92         _dl_deallocate_tls(uc->tls_desc, TRUE);
93         free(uc);
94 }
95
96 void print_context(struct u_context *uc)
97 {
98         printf("GIANT WARNING: this assumes a HW ctx\n");
99         /* Just print the trapframe */
100         print_hw_tf(&uc->u_ctx.tf.hw_tf);
101 }
102