x86: Userspace code to restart ROS TFs
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 6 Apr 2010 23:49:28 +0000 (16:49 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:41 +0000 (17:35 -0700)
A user scheduler can pop a TF provided by the kernel, and enable
notifications.  This is the way to leave the transition stack / start up
a user context.

TLSs aren't dealt with in particular.  The code will maintain whatever
gs is loaded, which is set per vcore.  The user scheduler will need to
set up the appropriate LDT entry (on x86) for the TLS/TCB of the user
context it's attempting to load.

This doesn't work on sparc yet.  It will just silently fail (and panic
in mhello).

.gitignore
tests/mhello.c
user/include/hart.h
user/include/i686/hart.h [new file with mode: 0644]
user/include/sparc/hart.h [new file with mode: 0644]

index 864ad8c..46625d7 100644 (file)
@@ -20,6 +20,7 @@ ros-project.tmproj
 kern/boot
 kern/include/arch
 kern/src/arch
+user/include/arch
 Documentation/doxygen/rosdoc
 sim/
 sim
index 0aa08bc..029a059 100644 (file)
@@ -7,6 +7,8 @@
 #include <arch/arch.h>
 #include <stdio.h>
 #include <hart.h>
+#include <timing.h>
+#include <rassert.h>
 
 hart_barrier_t b;
 
@@ -51,6 +53,14 @@ int main(int argc, char** argv)
                //debug("retval = %d\n", retval);
        }
        printf("Vcore %d Done!\n", vcoreid);
+       /* test loop for restarting a notif_tf */
+       if (vcoreid == 0) {
+               int ctr = 0;
+               while(1) {
+                       printf("Vcore %d Spinning (%d)!\n", vcoreid, ctr++);
+                       udelay(5000000);
+               }
+       }
 
        hart_barrier_wait(&b,hart_self());
 
@@ -79,9 +89,18 @@ void hart_entry(void)
        /* can see how many messages had to be sent as bits */
        printf("Number of event overflows: %d\n", vcpd->event_overflows);
 
+       /* Lets try to restart vcore0's context.  Note this doesn't do anything to
+        * set the appropriate TLS.  On x86, this will involve changing the LDT
+        * entry for this vcore to point to the TCB of the new user-thread. */
+       if (vcoreid == 0) {
+               printf("restarting vcore0 from userspace\n");
+               pop_ros_tf(&vcpd->notif_tf, &vcpd->notif_enabled);
+               panic("should never see me!");
+       }       
        /* unmask notifications once you can let go of the notif_tf and it is okay
         * to clobber the transition stack.
-        * Check Documentation/processes.txt: 4.2.4 */
+        * Check Documentation/processes.txt: 4.2.4.  In real code, you should be
+        * popping the tf of whatever user process you want (get off the x-stack) */
        vcpd->notif_enabled = TRUE;
        
 /* end: stuff userspace needs to do to handle notifications */
index 6f82ad3..ac7b5a5 100644 (file)
@@ -6,6 +6,7 @@ extern "C" {
 #endif
 
 #include <ros/arch/hart.h>
+#include <arch/hart.h>
 #include <string.h>
 
 #define HART_LOG2_MAX_MAX_HARTS 6
diff --git a/user/include/i686/hart.h b/user/include/i686/hart.h
new file mode 100644 (file)
index 0000000..5296dcf
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef PARLIB_ARCH_HART_H
+#define PARLIB_ARCH_HART_H
+
+#include <ros/common.h>
+#include <ros/arch/trapframe.h>
+
+/* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
+ * A Userspace scheduler can call this when transitioning off the transition
+ * stack.
+ *
+ * Basically, it sets up the future stack pointer to have extra stuff after it,
+ * and then it pops the registers, then pops the new context's stack
+ * pointer.  Then it uses the extra stuff (the new PC is on the stack, the
+ * location of notif_enabled, and a clobbered work register) to enable notifs,
+ * restore the work reg, and then "ret".
+ *
+ * The important thing is that it can a notification after it enables
+ * notifications, and when it gets resumed it can ultimately run the new
+ * context.  Enough state is saved in the running context and stack to continue
+ * running. */
+static inline void pop_ros_tf(struct user_trapframe *tf, bool *notif_en_loc)
+{
+       asm volatile ("movl %2,-4(%1);          " /* push the PC */
+                     "movl %3,-12(%1);         " /* leave room for eax, push loc */
+                     "movl %0,%%esp;           " /* pop the real tf */
+                     "popal;                   "
+                     "addl $0x24,%%esp;        " /* move to the %esp in the tf */
+                     "popl %%esp;              " /* change to the new %esp */
+                     "subl $0x4,%%esp;         " /* move esp to the slot for eax */
+                     "pushl %%eax;             " /* save eax, will clobber soon */
+                     "subl $0x4,%%esp;         " /* move to notif_en_loc slot */
+                     "popl %%eax;              "
+                     "movb $0x01,(%%eax);      " /* enable notifications */
+                     "popl %%eax;              " /* restore tf's %eax */
+                     "ret;                     " /* return to the new PC */
+                     :
+                     : "g"(tf), "r"(tf->tf_esp), "r"(tf->tf_eip), "r"(notif_en_loc)
+                     : "memory");
+}
+
+#endif /* PARLIB_ARCH_HART_H */
diff --git a/user/include/sparc/hart.h b/user/include/sparc/hart.h
new file mode 100644 (file)
index 0000000..7e1ca6a
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef PARLIB_ARCH_HART_H
+#define PARLIB_ARCH_HART_H
+
+#include <ros/common.h>
+#include <ros/arch/trapframe.h>
+
+/* Pops an ROS kernel-provided TF, reanabling notifications at the same time.
+ * A Userspace scheduler can call this when transitioning off the transition
+ * stack.
+ *
+ * Here's how x86 does it:
+ * Basically, it sets up the future stack pointer to have extra stuff after it,
+ * and then it pops the registers, then pops the new context's stack
+ * pointer.  Then it uses the extra stuff (the new PC is on the stack, the
+ * location of notif_enabled, and a clobbered work register) to enable notifs,
+ * restore the work reg, and then "ret".
+ *
+ * The important thing is that it can a notification after it enables
+ * notifications, and when it gets resumed it can ultimately run the new
+ * context.  Enough state is saved in the running context and stack to continue
+ * running. */
+static inline void pop_ros_tf(struct user_trapframe *tf, bool *notif_en_loc)
+{
+       // TODO: whatever sparc needs.
+}
+
+#endif /* PARLIB_ARCH_HART_H */