Userspace saving/restoring of TLS
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 8 Apr 2010 23:13:41 +0000 (16:13 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:41 +0000 (17:35 -0700)
Example in mhello of what a scheduler would need to do.

tests/mhello.c
user/include/i686/hart.h
user/include/sparc/hart.h

index a7cc0c6..6f52de6 100644 (file)
@@ -13,6 +13,7 @@
 hart_barrier_t b;
 
 __thread int temp;
+void *core0_tls = 0;
 
 int main(int argc, char** argv)
 {
@@ -33,6 +34,10 @@ int main(int argc, char** argv)
                nm->vcoreid = i % 2; // vcore0 or 1, keepin' it fresh.
        }
 
+       /* Need to save this somewhere that you can find it again when restarting
+        * core0 */
+       core0_tls = get_tls_desc(0);
+
        /* don't forget to enable notifs on vcore0 at some point */
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[0];
@@ -53,6 +58,7 @@ int main(int argc, char** argv)
                //debug("retval = %d\n", retval);
        }
 
+#if 0
        /* test notifying my vcore2 */
        udelay(5000000);
        printf("Vcore 0 self-notifying vcore 2 with notif 4!\n");
@@ -64,12 +70,13 @@ int main(int argc, char** argv)
        ne.ne_type = 3;
        sys_notify(sys_getpid(), 3, &ne);
        udelay(1000000);
+#endif
 
        /* test loop for restarting a notif_tf */
        if (vcoreid == 0) {
                int ctr = 0;
                while(1) {
-                       printf("Vcore %d Spinning (%d)!\n", vcoreid, ctr++);
+                       printf("Vcore %d Spinning (%d), temp = %08x!\n", vcoreid, ctr++, temp);
                        udelay(5000000);
                }
        }
@@ -86,6 +93,7 @@ void hart_entry(void)
 {
        uint32_t vcoreid = hart_self();
 
+       temp = 0xcafebabe;
 /* begin: stuff userspace needs to do to handle notifications */
 
        struct preempt_data *vcpd;
@@ -107,6 +115,7 @@ void hart_entry(void)
         * entry for this vcore to point to the TCB of the new user-thread. */
        if (vcoreid == 0) {
                printf("restarting vcore0 from userspace\n");
+               set_tls_desc(core0_tls, 0);
                pop_ros_tf(&vcpd->notif_tf, &vcpd->notif_enabled);
                panic("should never see me!");
        }       
@@ -118,7 +127,6 @@ void hart_entry(void)
        
 /* end: stuff userspace needs to do to handle notifications */
 
-       temp = 0xcafebabe;
        printf("Hello from hart_entry in vcore %d with temp addr %p and temp %p\n",
               vcoreid, &temp, temp);
        hart_barrier_wait(&b,hart_self());
index 5296dcf..f3e3457 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <ros/common.h>
 #include <ros/arch/trapframe.h>
+#include <ros/procdata.h>
+#include <ros/arch/mmu.h>
 
 /* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
  * A Userspace scheduler can call this when transitioning off the transition
@@ -38,4 +40,29 @@ static inline void pop_ros_tf(struct user_trapframe *tf, bool *notif_en_loc)
                      : "memory");
 }
 
+/* Reading from the LDT.  Could also use %gs, but that would require including
+ * half of libc's TLS header.  Sparc will probably ignore the vcoreid, so don't
+ * rely on it too much.  The intent of it is vcoreid is the caller's vcoreid,
+ * and that vcoreid might be in the TLS of the caller (it will be for transition
+ * stacks) and we could avoid a trap on x86 to sys_getvcoreid(). */
+static inline void *get_tls_desc(uint32_t vcoreid)
+{
+       return (void*)(__procdata.ldt[vcoreid].sd_base_31_24 << 24 |
+                      __procdata.ldt[vcoreid].sd_base_23_16 << 16 |
+                      __procdata.ldt[vcoreid].sd_base_15_0);
+}
+
+/* passing in the vcoreid, since it'll be in TLS of the caller */
+static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
+{
+  /* Keep this technique in sync with sysdeps/ros/i386/tls.h */
+  segdesc_t tmp = SEG(STA_W, (uint32_t)tls_desc, 0xffffffff, 3);
+  __procdata.ldt[vcoreid] = tmp;
+
+  /* GS is still the same (should be!), but it needs to be reloaded to force a
+   * re-read of the LDT. */
+  uint32_t gs = (vcoreid << 3) | 0x07;
+  asm volatile("movl %0,%%gs" : : "r" (gs));
+}
+
 #endif /* PARLIB_ARCH_HART_H */
index 7e1ca6a..346419a 100644 (file)
@@ -24,4 +24,17 @@ static inline void pop_ros_tf(struct user_trapframe *tf, bool *notif_en_loc)
        // TODO: whatever sparc needs.
 }
 
+/* Feel free to ignore vcoreid.  It helps x86 to avoid a call to
+ * sys_getvcoreid() if we pass it in. */
+static inline void *get_tls_desc(uint32_t vcoreid)
+{
+       void *tmp;
+       asm volatile ("mov %%g7,%0" : "=r"(tmp));
+       return tmp;
+}
+
+static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
+{
+       asm volatile ("mov %0,%%g7" : : "r"(tls_desc) : "memory");
+}
 #endif /* PARLIB_ARCH_HART_H */