Add vcore_entry to vcpd (XCC) (2/2)
authorKevin Klues <klueska@cs.berkeley.edu>
Sat, 18 Jul 2015 17:01:26 +0000 (10:01 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 22 Jul 2015 19:17:58 +0000 (15:17 -0400)
In this commit we finalize the migration of vcore_entry into the vcpd.
As part of this, a significant amount of cleanup has been done.  In
addition to removing all system dependent startup code from glibc, we
also now only initialize __vcore_id, __vcore_context, and only call
__ctype_init() once when a vcore's TLS is first allocated.

Currently, the vcore entry point is set to point to a static function
called __kernel_vcore_entry, whose sole job is to grab the vcore_id of
the vcore passed in by the kernel, and set up the vcore's TLS by
extracting it from the vcpd for that vcore.  It then calls the real
vcore_entry of the application.  In the future, if we decide to
standardize on the kernel setting up our vcore TLS for us (as it does
for x86_64), then this level of indirection can be avoided.

Although not currenlty utilized, one nice property of this approach (in
addition to removing our reliance on making _start reentrant), is that
different vcore_entry() points can be set up for different vcores,
potentially providing a fast path for critical code running on those
vcores that doesn't need to run through the standard vcore_entry()
sequence.  Such functionality may provie useful in the future.

[brho: moved vcore_entry's in VCPD adjacent to stack and tls_desc, added
comment and __vcore_entry = TRUE in __kernel_vcore_entry() ]

kern/include/ros/event.h
kern/src/process.c
kern/src/trap.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/init.c [deleted file]
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/x86_64/start.S [deleted file]
user/parlib/vcore.c

index 44327af..7336350 100644 (file)
@@ -113,6 +113,7 @@ struct preempt_data {
        struct user_context                     vcore_ctx;                      /* for preemptions */
        struct ancillary_state          preempt_anc;
        struct user_context                     uthread_ctx;            /* for preempts or notifs */
+       uintptr_t                                       vcore_entry;            /* advertised by the user */
        uintptr_t                                       transition_stack;       /* advertised by the user */
        uintptr_t                                       vcore_tls_desc;         /* advertised by the user */
        atomic_t                                        flags;
index e07fbeb..96e47b0 100644 (file)
@@ -618,7 +618,7 @@ void proc_run_s(struct proc *p)
                                vcpd->uthread_ctx = p->scp_ctx;
                                pcpui->cur_ctx = &pcpui->actual_ctx;
                                memset(pcpui->cur_ctx, 0, sizeof(struct user_context));
-                               proc_init_ctx(pcpui->cur_ctx, 0, p->env_entry,
+                               proc_init_ctx(pcpui->cur_ctx, 0, vcpd->vcore_entry,
                                              vcpd->transition_stack, vcpd->vcore_tls_desc);
                        } else {
                                /* If they have no transition stack, then they can't receive
@@ -1899,7 +1899,7 @@ static void __set_curctx_to_vcoreid(struct proc *p, uint32_t vcoreid,
                proc_secure_ctx(&pcpui->actual_ctx);
        } else { /* not restarting from a preemption, use a fresh vcore */
                assert(vcpd->transition_stack);
-               proc_init_ctx(&pcpui->actual_ctx, vcoreid, p->env_entry,
+               proc_init_ctx(&pcpui->actual_ctx, vcoreid, vcpd->vcore_entry,
                              vcpd->transition_stack, vcpd->vcore_tls_desc);
                /* Disable/mask active notifications for fresh vcores */
                vcpd->notif_disabled = TRUE;
@@ -2135,7 +2135,7 @@ void __notify(uint32_t srcid, long a0, long a1, long a2)
         * silly state isn't our business for a notification. */
        vcpd->uthread_ctx = *pcpui->cur_ctx;
        memset(pcpui->cur_ctx, 0, sizeof(struct user_context));
-       proc_init_ctx(pcpui->cur_ctx, vcoreid, p->env_entry,
+       proc_init_ctx(pcpui->cur_ctx, vcoreid, vcpd->vcore_entry,
                      vcpd->transition_stack, vcpd->vcore_tls_desc);
        /* this cur_ctx will get run when the kernel returns / idles */
 }
index 728dacd..dd2c79e 100644 (file)
@@ -68,7 +68,7 @@ void reflect_unhandled_trap(unsigned int trap_nr, unsigned int err,
        vcpd->notif_disabled = TRUE;
        vcpd->uthread_ctx = *pcpui->cur_ctx;
        memset(pcpui->cur_ctx, 0, sizeof(struct user_context));
-       proc_init_ctx(pcpui->cur_ctx, vcoreid, p->env_entry,
+       proc_init_ctx(pcpui->cur_ctx, vcoreid, vcpd->vcore_entry,
                      vcpd->transition_stack, vcpd->vcore_tls_desc);
        return;
 error_out:
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/init.c b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/init.c
deleted file mode 100644 (file)
index 61a74b6..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#include <abort-instr.h>
-#include <string.h>
-#include <parlib/vcore.h>
-#include <stdio.h>
-#include <ros/syscall.h>
-#include <ros/procinfo.h>
-#include <unistd.h>
-#include <tls.c>
-#include <ctype.h>
-
-__thread int __vcoreid = 0;
-__thread bool __vcore_context = FALSE;
-
-#define failmsg(str) write(2,str"\n",sizeof(str"\n")-1)
-
-void __attribute__((noreturn)) __uthread_vcore_entry(void)
-{
-       fputs("Define a uthread_vcore_entry() or a vcore_entry(), foo!\n", stderr);
-       abort();
-       __builtin_unreachable();
-}
-weak_alias(__uthread_vcore_entry, uthread_vcore_entry)
-
-void __attribute__((noreturn)) __vcore_entry(void)
-{
-       uthread_vcore_entry();
-       fputs("vcore_entry() should never return!\n", stderr);
-       abort();
-       __builtin_unreachable();
-}
-weak_alias(__vcore_entry, vcore_entry)
-
-void __libc_vcore_entry(int id)
-{
-       static int init = 0;
-       /* For dynamically-linked programs, the first time through,
-        * __vcore_self_on_entry could be clobbered (on x86), because the linker
-        * will have overwritten eax.  Happily, the first time through, we know we
-        * are vcore 0.  Subsequent entries into this routine do not have this
-        * problem. */
-       if (init == 0)
-               id = 0;
-
-       /* vcore0 when it comes up again, and all threads besides thread 0 must
-        * acquire a TCB. */
-       if (init || (id != 0)) {
-               /* The kernel sets the TLS desc for us, based on whatever is in VCPD.
-                *
-                * x86 32-bit TLS is pretty jacked up, so the kernel doesn't set the TLS
-                * desc for us.  it's a little more expensive to do it here, esp for
-                * amd64.  Can remove this when/if we overhaul 32 bit TLS.
-                *
-                * AFAIK, riscv's TLS changes are really cheap, and they don't do it in
-                * the kernel (yet/ever), so they can set their TLS here too. */
-               #ifndef __x86_64__
-               set_tls_desc((void*)__procdata.vcore_preempt_data[id].vcore_tls_desc);
-               #endif
-               /* These TLS setters actually only need to happen once, at init time */
-               __vcoreid = id;
-               __vcore_context = TRUE;
-               __ctype_init(); /* set locale info for ctype functions */
-               vcore_entry();
-               failmsg("why did vcore_entry() return?");
-               abort();
-               #ifdef ABORT_INSTRUCTION
-               ABORT_INSTRUCTION;
-               #endif
-
-               while(1);
-               __builtin_unreachable();
-       }
-       init = 1;
-}
-
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/x86_64/start.S b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/x86_64/start.S
deleted file mode 100644 (file)
index 5da2563..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2015 Google Inc., All Rights Reserved.
- * Kevin Klues <klueska@google.com>
- * See LICENSE for details. */
-
-#define _start _real_start
-#include <sysdeps/x86_64/start.S>
-#undef _start
-
-       .text
-       .globl _start
-       .type _start,@function
-_start:
-       cfi_startproc
-       /* Save rdx on the stack. The SYSV ABI uses rdx as the only register to
-        * pass information to a process (everything else is on the stack). Save
-        * it here since we interpose with a call to __libc_vcore_entry(). */
-       pushq %rdx
-
-       /* Pass vcoreid to __libc_vcore_entry. Akaros passes it to us in the rbx
-        * register. On all but the first time through this function we will
-        * never return. */
-       movq %rbx, %rdi
-       call __libc_vcore_entry
-
-       /* Restore rdx and call out to the real start function. This function is
-        * Only called once even though we may enter on this start function
-        * multiple times. */
-       popq %rdx
-       jmp _real_start
-       cfi_endproc
-
index 2678d0d..862c490 100644 (file)
@@ -15,6 +15,9 @@
 #include <ros/arch/membar.h>
 #include <parlib/printf-ext.h>
 
+__thread int __vcoreid = 0;
+__thread bool __vcore_context = FALSE;
+
 /* starting with 1 since we alloc vcore0's stacks and TLS in vcore_lib_init(). */
 static size_t _max_vcores_ever_wanted = 1;
 atomic_t nr_new_vcores_wanted;
@@ -25,6 +28,48 @@ __thread struct syscall __vcore_one_sysc = {.flags = (atomic_t)SC_DONE, 0};
 /* Per vcore entery function used when reentering at the top of a vcore's stack */
 static __thread void (*__vcore_reentry_func)(void) = NULL;
 
+/* The default user vcore_entry function. */
+void __attribute__((noreturn)) __vcore_entry(void)
+{
+       extern void uthread_vcore_entry(void);
+       uthread_vcore_entry();
+       fprintf(stderr, "vcore_entry() should never return!\n");
+       abort();
+       __builtin_unreachable();
+}
+void vcore_entry(void) __attribute__((weak, alias ("__vcore_entry")));
+
+/* The lowest level function jumped to by the kernel on every vcore_entry.
+ * Currently, this function is only necessary so we can set the tls_desc from
+ * the vcpd for non x86_64 architectures. We should consider removing this and
+ * making it mandatory to set the tls_desc in the kernel. We wouldn't even
+ * need to pass the vcore id to user space at all if we did this.  It would
+ * already be set in the preinstalled TLS as __vcore_id. */
+static void __attribute__((noreturn)) __kernel_vcore_entry(void)
+{
+       /* The kernel sets the TLS desc for us, based on whatever is in VCPD.
+        *
+        * x86 32-bit TLS is pretty jacked up, so the kernel doesn't set the TLS
+        * desc for us.  it's a little more expensive to do it here, esp for
+        * amd64.  Can remove this when/if we overhaul 32 bit TLS.
+        *
+        * AFAIK, riscv's TLS changes are really cheap, and they don't do it in
+        * the kernel (yet/ever), so they can set their TLS here too. */
+       int id = __vcore_id_on_entry;
+       #ifndef __x86_64__
+       set_tls_desc(vcpd_of(id)->vcore_tls_desc);
+       #endif
+       /* Every time the vcore comes up, it must set that it is in vcore context.
+        * uthreads may share the same TLS as their vcore (when uthreads do not have
+        * their own TLS), and if a uthread was preempted, __vcore_context == FALSE,
+        * and that will continue to be true the next time the vcore pops up. */
+       __vcore_context = TRUE;
+       vcore_entry();
+       fprintf(stderr, "vcore_entry() should never return!\n");
+       abort();
+       __builtin_unreachable();
+}
+
 /* TODO: probably don't want to dealloc.  Considering caching */
 static void free_transition_tls(int id)
 {
@@ -38,6 +83,9 @@ static void free_transition_tls(int id)
 
 static int allocate_transition_tls(int id)
 {
+       /* Libc function to initialize TLS-based locale info for ctype functions. */
+       extern void __ctype_init(void);
+
        /* We want to free and then reallocate the tls rather than simply 
         * reinitializing it because its size may have changed.  TODO: not sure if
         * this is right.  0-ing is one thing, but freeing and reallocating can be
@@ -50,6 +98,18 @@ static int allocate_transition_tls(int id)
                errno = ENOMEM;
                return -1;
        }
+
+       /* Setup some intitial TLS data for the newly allocated transition tls. */
+       void *temp_tcb = get_tls_desc();
+       set_tls_desc(tcb);
+       begin_safe_access_tls_vars();
+       __vcoreid = id;
+       __vcore_context = TRUE;
+       __ctype_init();
+       end_safe_access_tls_vars();
+       set_tls_desc(temp_tcb);
+
+       /* Install the new tls into the vcpd. */
        set_vcpd_tls_desc(id, tcb);
        return 0;
 }
@@ -77,9 +137,7 @@ static int allocate_transition_stack(int id)
        return 0;
 }
 
-/* This gets called in glibc before calling the programs 'main'.  Need to set
- * ourselves up so that thread0 is a uthread, and then register basic signals to
- * go to vcore 0. */
+/* Run libc specific early setup code. */
 static void vcore_libc_init(void)
 {
        register_printf_specifier('r', printf_errstr, printf_errstr_info);
@@ -122,6 +180,8 @@ void __attribute__((constructor)) vcore_lib_init(void)
                ucq_init_raw(&vcpd_of(i)->ev_mbox_private.ev_msgs,
                             mmap_block + (4 * i + 2) * PGSIZE,
                             mmap_block + (4 * i + 3) * PGSIZE);
+               /* Set the lowest level entry point for each vcore. */
+               vcpd_of(i)->vcore_entry = (uintptr_t)__kernel_vcore_entry;
        }
        atomic_init(&vc_req_being_handled, 0);
        assert(!in_vcore_context());