Procdata uses user_contexts (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 13 Apr 2013 02:59:45 +0000 (19:59 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 13 Apr 2013 02:59:45 +0000 (19:59 -0700)
This changes the kernel interface from struct trapframes to struct
user_contexts.  I also found some ancient documentation, though I'm sure
a lot more of it is out of date (esp regarding preemption).

Userspace libraries (and ancient ghetto test programs...) use the new
kernel interface, though the user-level arch-dependent functions still
operate on HW TFs (instead of contexts).

Also, c3po looks like it might not work; not sure what its deal is/was.

21 files changed:
Documentation/process-internals.txt
Documentation/processes.txt
kern/arch/i686/ros/trapframe.h
kern/arch/riscv/ros/trapframe.h
kern/arch/sparc/ros/trapframe.h
kern/include/ros/event.h
kern/src/process.c
tests/eth_audio.c
tests/mhello.c
tests/msr_get_cores.c
tests/msr_get_singlecore.c
tests/syscall.c
user/c3po/threads/ucontext.c
user/c3po/threads/ucontext.h
user/c3po/threads/vcore.c
user/parlib/include/i686/vcore.h
user/parlib/include/riscv/vcore.h
user/parlib/include/sparc/vcore.h
user/parlib/include/uthread.h
user/parlib/uthread.c
user/pthread/pthread.c

index 05f601e..94bf091 100644 (file)
@@ -507,7 +507,7 @@ assumptions about the vcore->pcore mapping and can result in multiple
 instances of the same vcore on different pcores.  Imagine a preempt message
 sent to a pcore (after the alarm goes off), meanwhile that vcore/pcore yields
 and the vcore reactivates somewhere else.  There is a potential race on the
-preempt_tf state: the new vcore is reading while the old is writing.  This
+vcore_ctx state: the new vcore is reading while the old is writing.  This
 issue is sorted naturally: the vcore entry in the vcoremap isn't cleared until
 the vcore/pcore is actually yielded/taken away, so the code looking for a free
 vcoreid slot will not try to use it.
@@ -546,7 +546,7 @@ process is not running.  Ultimately, the process wants to be notified on a
 given vcore.  Whenever we send an active notification, we set a flag in procdata
 (notif_pending).  If the vcore is offline, we don't bother sending the IPI/notif
 message.  The kernel will make sure it runs the notification handler (as well as
-restoring the preempt_tf) the next time that vcore is restarted.  Note that
+restoring the vcore_ctx) the next time that vcore is restarted.  Note that
 userspace can toggle this, so they can handle the notifications from a different
 core if it likes, or they can independently send a notification.
 
@@ -555,9 +555,10 @@ disabled (this is done in pop_ros_tf() by userspace).  The overall meaning of
 notif_pending is that a vcore wants to be IPI'd.  The IPI could be in-flight, or
 it could be missed.  Since notification IPIs can be spurious, when we have
 potential races, we err on the side of sending.  This happens when pop_ros_tf()
-notifies itself, and when the kernel starts a vcore in it's notif handler if it
-was preempted and notif was pending.  In the latter case, the kernel will put
-the preempt_tf in the notif_tf, so userspace can restart that at its leisure.
+notifies itself, and when the kernel makes sure to start a vcore in vcore
+context if a notif was pending.  This was simplified a bit over the years by
+having uthreads always get saved into the uthread_ctx (formerly the notif_tf),
+instead of in the old preempt_tf (which is now the vcore_ctx).
 
 If a vcore has a preempt_pending, we will still send the active notification
 (IPI).  The core ought to get a notification for the preemption anyway, so we
@@ -576,7 +577,7 @@ do is execute the notification handler and jump to userspace.  Since there is
 still an k_msg in the queue (and we self_ipi'd ourselves, it's part of how
 k_msgs work), the IPI will fire and push us right back into the kernel to
 execute the preemption, and the notif handler's context will be saved in the
-preempt_tf (ready to go when the vcore gets started again).
+vcore_ctx (ready to go when the vcore gets started again).
 
 We could try to just leave the notif_pending flag set and ignore the message,
 but that would involve inspecting the queue for the preempt k_msg.
index 53c7f11..8593fd0 100644 (file)
@@ -163,7 +163,7 @@ is currently done via sys_getcpuid().  The name will probably change.
 2.4.1: To go from _S to _M, a process requests cores.
 --------------
 A resource request from 0 to 1 or more causes a transition from _S to _M.  The
-calling context is saved in the notification slot (notif_tf) in vcore0's
+calling context is saved in the uthread slot (uthread_ctx) in vcore0's
 preemption data (in procdata).  The second level scheduler needs to be able to
 restart the context when vcore0 starts up.  To do this, it will need to save the
 TLS/TCB descriptor and the floating point/silly state (if applicable) in the
@@ -182,13 +182,13 @@ also a syscall to get the vcoreid, but this will save an extra trap at vcore
 start time.
 
 Future proc_runs(), like from RUNNABLE_M to RUNNING_M start all cores at the
-entry point, including vcore0.  The saving of a _S context to vcore0's notif_tf
-only happens on the transition from _S to _M (which the process needs to be
-aware of for a variety of reasons).  This also means that userspace needs to
-handle vcore0 coming up at the entry point again (and not starting the program
-over).  This is currently done in sysdeps-ros/start.c, via the static variable
-init.  Note there are some tricky things involving dynamically linked programs,
-but it all works currently.
+entry point, including vcore0.  The saving of a _S context to vcore0's
+uthread_ctx only happens on the transition from _S to _M (which the process
+needs to be aware of for a variety of reasons).  This also means that userspace
+needs to handle vcore0 coming up at the entry point again (and not starting the
+program over).  This is currently done in sysdeps-ros/start.c, via the static
+variable init.  Note there are some tricky things involving dynamically linked
+programs, but it all works currently.
 
 When coming in to the entry point, whether as the result of a startcore or a
 notification, the kernel will set the stack pointer to whatever is requested
@@ -451,14 +451,14 @@ This can be really tricky.  When userspace is changing threads, it will need to
 unmask notifs as well as jump to the new thread.  There is a slight race here,
 but it is okay.  The race is that an IPI can arrive after notifs are unmasked,
 but before returning to the real user thread.  Then the code will think the
-notif_tf represents the new user thread, even though it hasn't started (and the
-PC is wrong).  The trick is to make sure that all state required to start the
-new thread, as well as future instructions, are all saved within the "stuff"
-that gets saved in the notif_tf.  When these threading packages change contexts,
-they ought to push the PC on the stack of the new thread, (then enable notifs)
-and then execute a return.  If an IPI arrives before the "function return", then
-when that context gets restarted, it will run the "return" with the appropriate
-value on the stack still.
+uthread_ctx represents the new user thread, even though it hasn't started (and
+the PC is wrong).  The trick is to make sure that all state required to start
+the new thread, as well as future instructions, are all saved within the "stuff"
+that gets saved in the uthread_ctx.  When these threading packages change
+contexts, they ought to push the PC on the stack of the new thread, (then enable
+notifs) and then execute a return.  If an IPI arrives before the "function
+return", then when that context gets restarted, it will run the "return" with
+the appropriate value on the stack still.
 
 There is a further complication.  The kernel can send an IPI that the process
 wanted, but the vcore did not get truly interrupted since its notifs were
@@ -478,31 +478,14 @@ handled in pop_ros_tf().
 
 4.3: Preemption Specifics
 -------------------------------
-When a vcore is preempted, the kernel takes whatever context was running (which
-could be a notification context) and stores it in the preempt trapframe for
-that vcore in procdata.  There is also a flag (actually a counter) that states
-if the context there has been sorted out.  Userspace should set this once it
-has copied out the data and dealt with it accordingly.
-
-The invariant regarding the preemption slot is that there should never be
-anything running on a vcore when there is a valid/not-sorted preempt
-trapframe.  The reason is that a preemption can come in at any time (such as
-right after returning from a preemption).
-
-To maintain this invariant, when the kernel starts a vcore, it will run the
-context that is in the preempt trapframe if the "preempt_tf_valid" seq_ctr is
-not set.  A process needs to be careful of a race here.  If they are trying to
-deal with a preempt trapframe (must be from another vcore, btw), the kernel
-could start to run that trapframe (in case it is granting a core request /
-proc_startcore()ing).  When the kernel prepares to use the trapframe (which it
-will do regardless of userspace activities), it will up the seq_ctr.  We use a
-seq_ctr (mostly just a counter) to avoid ABA-related issues.  If the process
-notices a change in that flag, it ought to abort its operation.  It can up the
-counter on its own when it no longer wants the kernel to run that context (this
-means the preempt_tf can get clobbered).
+There's an issue with a preempted vcore getting restarted while a remote core
+tries to restart that context.  They resolve this fight with a variety of VC
+flags (VC_UTHREAD_STEALING).  Check out handle_preempt() in uthread.c.
 
 4.4: Other trickiness
 -------------------------------
+Take all of these with a grain of salt - it's quite old.
+
 4.4.1: Preemption -> deadlock
 -------------------------------
 One issue is that a context can be holding a lock that is necessary for the
@@ -553,35 +536,9 @@ hardware interrupts (on x86, at least).
 
 4.4.3: Restarting a Preempted Notification
 -------------------------------
-There will be cases where the trapframe in the preempt_tf slot is actually a
-notification handler, which was running on the transition stack of that
-particular vcore.  Userspace needs to be careful about restarting contexts
-that were on those cores on different cores.  They can tell by examining the
-stack pointer to see if it was on a transition stack.  Alternatively, if
-notifications are masked, it is also likely they in a notification handler.  The
-real concern is the transition stack.  If a vcore is processing on the
-transition stack of another vcore, there is a risk that the vcore comes back up
-and starts clobbering the transition stack.
-
-To avoid this, userspace could allocate a new transition stack and switch the
-target vcore to use that new stack (in procdata).  The only time (for now)
-that the kernel cares about a transition stack is when it is popping a tf on a
-new or freshly notified vcore.  Something similar will need to be done with TLS.
-
-This all should be a rare occurance, since the vcore should see the
-preempt_pending when it starts its notification and yield, instead of being
-forced into this weird situation.  This also means that notifications should
-take less time than the kernel will wait before preempting.
-
-This issue ties in with deadlocking in 4.4.1.  If userspace is never in a
-notif handler when it gets preempted, that deadlock will not happen (and we
-also may need only one trapframe slot).  Userspace probably cannot guarantee
-that, so we'll have to deal with it.  Avoiding the deadlock on a spinlock is
-much more reasonable (and we can provide the locking function).
-
-Another thing to keep in mind is that userspace probably won't want to restart a
-notification handler on a different core.  It's conceivable that they want to
-take a regular user thread and context and restart it, not a transition context.
+Nowadays, to restart a preempted notification, you just restart the vcore.
+The kernel does, either if it gives the process more cores or if userspace asked
+it to with a sys_change_vcore().
 
 4.4.4: Userspace Yield Races
 -------------------------------
index 70686d8..bda7ae1 100644 (file)
@@ -43,17 +43,10 @@ struct hw_trapframe {
        uint16_t tf_padding6;
 };
 
-/* Temporary aliasing */
-#define trapframe hw_trapframe
-
 struct sw_trapframe {
        /* TODO */
 };
 
-/* TODO: consider using a user-space specific trapframe, since they don't need
- * all of this information.  Might do that eventually, but til then: */
-#define user_trapframe trapframe
-
 /* FP state and whatever else the kernel won't muck with automatically.  For
  * now, it's the Non-64-bit-mode layout of FP and XMM registers, as used by
  * FXSAVE and FXRSTOR.  Other modes will require a union on a couple entries.
index 31d011c..3422ce3 100644 (file)
@@ -17,17 +17,10 @@ struct hw_trapframe
   long cause;
 };
 
-/* Temporary aliasing */
-#define trapframe hw_trapframe
-
 struct sw_trapframe {
        /* TODO */
 };
 
-/* TODO: consider using a user-space specific trapframe, since they don't need
- * all of this information.  Will do that eventually, but til then: */
-#define user_trapframe trapframe
-
 typedef struct ancillary_state
 {
        uint64_t fpr[32];
index 912596b..de6cb0b 100644 (file)
@@ -22,17 +22,10 @@ struct hw_trapframe
        uint64_t timestamp;
 };
 
-/* Temporary aliasing */
-#define trapframe hw_trapframe
-
 struct sw_trapframe {
        /* TODO */
 };
 
-/* TODO: consider using a user-space specific trapframe, since they don't need
- * all of this information.  Will do that eventually, but til then: */
-#define user_trapframe trapframe
-
 typedef struct ancillary_state
 {
        uint32_t fpr[32] __attribute__((aligned (8)));
index ea1e513..2168b9a 100644 (file)
@@ -107,9 +107,9 @@ struct event_queue_big {
 
 /* Per-core data about preemptions and notifications */
 struct preempt_data {
-       struct user_trapframe           preempt_tf;                     /* slot for vcore ctx */
+       struct user_context                     vcore_ctx;                      /* for preemptions */
        struct ancillary_state          preempt_anc;
-       struct user_trapframe           notif_tf;                       /* slot for uthread ctx */
+       struct user_context                     uthread_ctx;            /* for preempts or notifs */
        uintptr_t                                       transition_stack;       /* advertised by the user */
        atomic_t                                        flags;
        bool                                            notif_disabled;         /* vcore unwilling to recv*/
index 00f46a1..dc443f9 100644 (file)
@@ -481,16 +481,16 @@ void proc_run_s(struct proc *p)
                        assert(!pcpui->owning_proc);
                        pcpui->owning_proc = p;
                        pcpui->owning_vcoreid = 0; /* TODO (VC#) */
-                       /* TODO: (HSS) set silly state here (__startcore does it instantly) */
+                       /* TODO: (HSS) set FP state here (__startcore does it instantly) */
                        /* similar to the old __startcore, start them in vcore context if
                         * they have notifs and aren't already in vcore context.  o/w, start
                         * them wherever they were before (could be either vc ctx or not) */
                        if (!vcpd->notif_disabled && vcpd->notif_pending
                                                  && scp_is_vcctx_ready(vcpd)) {
                                vcpd->notif_disabled = TRUE;
-                               /* save the _S's ctx in the notify slot, build and pop a new one
-                                * in actual/cur_ctx. */
-                               vcpd->notif_tf = p->scp_ctx.tf.hw_tf;   /* TODO CTX */
+                               /* save the _S's ctx in the uthread slot, build and pop a new
+                                * one in actual/cur_ctx. */
+                               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,
@@ -807,14 +807,10 @@ int proc_change_to_m(struct proc *p)
                         * TODO: relies on vcore0 being the caller (VC#) */
                        if ((current != p) || (get_pcoreid(p, 0) != core_id()))
                                panic("We don't handle async RUNNING_S core requests yet.");
-                       /* save the tf so userspace can restart it.  Like in __notify,
-                        * this assumes a user tf is the same as a kernel tf.  We save
-                        * it in the preempt slot so that we can also save the silly
-                        * state. */
                        struct preempt_data *vcpd = &p->procdata->vcore_preempt_data[0];
                        assert(current_ctx);
-                       /* Copy uthread0's context to the notif slot */
-                       vcpd->notif_tf = current_ctx->tf.hw_tf; /* TODO CTX */
+                       /* Copy uthread0's context to VC 0's uthread slot */
+                       vcpd->uthread_ctx = *current_ctx;
                        clear_owning_proc(core_id());   /* so we don't restart */
                        save_fp_state(&vcpd->preempt_anc);
                        /* Userspace needs to not fuck with notif_disabled before
@@ -1701,14 +1697,14 @@ static void __set_curctx_to_vcoreid(struct proc *p, uint32_t vcoreid,
        printd("[kernel] startcore on physical core %d for process %d's vcore %d\n",
               core_id(), p->pid, vcoreid);
        /* If notifs are disabled, the vcore was in vcore context and we need to
-        * restart the preempt_tf.  o/w, we give them a fresh vcore (which is also
+        * restart the vcore_ctx.  o/w, we give them a fresh vcore (which is also
         * what happens the first time a vcore comes online).  No matter what,
         * they'll restart in vcore context.  It's just a matter of whether or not
         * it is the old, interrupted vcore context. */
        if (vcpd->notif_disabled) {
                restore_fp_state(&vcpd->preempt_anc);
                /* copy-in the tf we'll pop, then set all security-related fields */
-               pcpui->actual_ctx.tf.hw_tf = vcpd->preempt_tf;  /* TODO CTX */
+               pcpui->actual_ctx = vcpd->vcore_ctx;
                proc_secure_ctx(&pcpui->actual_ctx);
        } else { /* not restarting from a preemption, use a fresh vcore */
                assert(vcpd->transition_stack);
@@ -1794,12 +1790,12 @@ int proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
        /* enable_my_notif signals how we'll be restarted */
        if (enable_my_notif) {
                /* if they set this flag, then the vcore can just restart from scratch,
-                * and we don't care about either the notif_tf or the preempt_tf. */
+                * and we don't care about either the uthread_ctx or the vcore_ctx. */
                caller_vcpd->notif_disabled = FALSE;
        } else {
                /* need to set up the calling vcore's ctx so that it'll get restarted by
                 * __startcore, to make the caller look like it was preempted. */
-               caller_vcpd->preempt_tf = current_ctx->tf.hw_tf; // TODO CTX
+               caller_vcpd->vcore_ctx = *current_ctx;
                save_fp_state(&caller_vcpd->preempt_anc);
                /* Mark our core as preempted (for userspace recovery). */
                atomic_or(&caller_vcpd->flags, VC_PREEMPTED);
@@ -1923,9 +1919,9 @@ void __notify(uint32_t srcid, long a0, long a1, long a2)
        if (vcpd->notif_disabled)
                return;
        vcpd->notif_disabled = TRUE;
-       /* save the old tf in the notify slot, build and pop a new one.  Note that
+       /* save the old ctx in the uthread slot, build and pop a new one.  Note that
         * silly state isn't our business for a notification. */
-       vcpd->notif_tf = pcpui->cur_ctx->tf.hw_tf; /* TODO CTX */
+       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,
                      vcpd->transition_stack);
@@ -1952,13 +1948,13 @@ void __preempt(uint32_t srcid, long a0, long a1, long a2)
        printd("[kernel] received __preempt for proc %d's vcore %d on pcore %d\n",
               p->procinfo->pid, vcoreid, coreid);
        /* if notifs are disabled, the vcore is in vcore context (as far as we're
-        * concerned), and we save it in the preempt slot. o/w, we save the
-        * process's cur_ctx in the notif slot, and it'll appear to the vcore when
-        * it comes back up that it just took a notification. */
+        * concerned), and we save it in the vcore slot. o/w, we save the process's
+        * cur_ctx in the uthread slot, and it'll appear to the vcore when it comes
+        * back up the uthread just took a notification. */
        if (vcpd->notif_disabled)
-               vcpd->preempt_tf = pcpui->cur_ctx->tf.hw_tf; /* TODO CTX */
+               vcpd->vcore_ctx = *pcpui->cur_ctx;
        else
-               vcpd->notif_tf = pcpui->cur_ctx->tf.hw_tf; /* TODO CTX */
+               vcpd->uthread_ctx = *pcpui->cur_ctx;
        /* either way, we save the silly state (FP) */
        save_fp_state(&vcpd->preempt_anc);
        /* Mark the vcore as preempted and unlock (was locked by the sender). */
index 41ccc40..e31d6a7 100644 (file)
@@ -121,11 +121,11 @@ void vcore_entry(void)
                set_tls_desc(core0_tls, 0);
                assert(__vcoreid == 0); /* in case anyone uses this */
                /* Load silly state (Floating point) too */
-               pop_ros_tf(&vcpd->notif_tf, vcoreid);
+               pop_ros_tf(&vcpd->uthread_ctx.tf.hw_tf, vcoreid);
                printf("should never see me!");
        }       
-       /* unmask notifications once you can let go of the notif_tf and it is okay
-        * to clobber the transition stack.
+       /* unmask notifications once you can let go of the uthread_ctx and it is
+        * okay to clobber the transition stack.
         * 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_disabled = FALSE;
index 23682c1..65a91d1 100644 (file)
@@ -115,7 +115,7 @@ int main(int argc, char** argv)
        udelay(1000000);
        //#endif
 
-       /* test loop for restarting a notif_tf */
+       /* test loop for restarting a uthread_ctx */
        if (vcoreid == 0) {
                int ctr = 0;
                while(1) {
@@ -155,8 +155,8 @@ void ghetto_vcore_entry(void)
                assert(vcoreid == 0);
                run_current_uthread();
        }
-       /* unmask notifications once you can let go of the notif_tf and it is okay
-        * to clobber the transition stack.
+       /* unmask notifications once you can let go of the uthread_ctx and it is
+        * okay to clobber the transition stack.
         * 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) */
        enable_notifs(vcoreid);
index 3fdb406..d23d7d7 100644 (file)
@@ -102,7 +102,7 @@ void vcore_entry(void)
                set_tls_desc(core0_tls, 0);
                assert(__vcoreid == 0); /* in case anyone uses this */
                /* Load silly state (Floating point) too */
-               pop_ros_tf(&vcpd->notif_tf, vcoreid);
+               pop_ros_tf(&vcpd->uthread_ctx.tf.hw_tf, vcoreid);
                panic("should never see me!");
        }       
 /* end: stuff userspace needs to do to handle notifications */
index 5b323f9..7a2e84a 100644 (file)
@@ -103,7 +103,7 @@ void vcore_entry(void)
                set_tls_desc(core0_tls, 0);
                assert(__vcoreid == 0); /* in case anyone uses this */
                /* Load silly state (Floating point) too */
-               pop_ros_tf(&vcpd->notif_tf, vcoreid);
+               pop_ros_tf(&vcpd->uthread_ctx.tf.hw_tf, vcoreid);
                panic("should never see me!");
        }       
 /* end: stuff userspace needs to do to handle notifications */
index 6a2184e..9548798 100644 (file)
@@ -118,8 +118,8 @@ void ghetto_vcore_entry(void)
                run_current_uthread();
                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.
+       /* unmask notifications once you can let go of the uthread_ctx and it is
+        * okay to clobber the transition stack.
         * 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) */
        struct preempt_data *vcpd;
index 71567ad..eed3d4b 100644 (file)
@@ -53,14 +53,14 @@ struct u_context* create_context(thread_t *t, void *entry_pt, void *stack_top)
        uc->thread = t;
 
        /* Initialize the trapframe for this context */
-       init_user_tf(&uc->utf, (uint32_t)entry_pt, (uint32_t)stack_top);
+       init_user_tf(&uc->u_ctx.tf.hw_tf, (uint32_t)entry_pt, (uint32_t)stack_top);
        return uc;
 }
 
 void save_context(struct u_context *uc)
 {
        /* Save the trapframe for this context */
-       save_ros_tf(&uc->utf);
+       save_ros_tf(&uc->u_ctx.tf.hw_tf);
 }
 
 void restore_context(struct u_context *uc)
@@ -75,7 +75,7 @@ void restore_context(struct u_context *uc)
        /* Tell the uthread which vcore it is on */
        __vcoreid = vcoreid;
        /* Pop the trapframe */
-       pop_ros_tf(&uc->utf, vcoreid);
+       pop_ros_tf(&uc->u_ctx.tf.hw_tf, vcoreid);
 }
 
 void destroy_context(struct u_context *uc)
@@ -94,7 +94,8 @@ void destroy_context(struct u_context *uc)
 
 void print_context(struct u_context *uc)
 {
+       printf("GIANT WARNING: this assumes a HW ctx\n");
        /* Just print the trapframe */
-       print_trapframe(&uc->utf);
+       print_trapframe(&uc->u_ctx.tf.hw_tf);
 }
 
index 0a81691..ac32bfa 100644 (file)
@@ -5,7 +5,8 @@
 #include <ros/trapframe.h>
 #include <threadlib_internal.h>
 struct u_context {
-       struct user_trapframe utf;
+       /* this seems rather screwed up, not inheriting a uthread */
+       struct user_context u_ctx;
     void *tls_desc;
        thread_t *thread;
 }; 
index eba3604..a9b7182 100644 (file)
@@ -179,8 +179,8 @@ void __attribute__((noreturn)) vcore_entry()
 
                /* Copy the notification trapframe into the current 
                 * threads trapframe */
-               memcpy(&current_thread->context->utf, &vcpd->notif_tf
-                      sizeof(struct user_trapframe));
+               memcpy(&current_thread->context->u_ctx, &vcpd->uthread_ctx
+                      sizeof(struct user_context));
 
         /* Restore the context from the current_thread's trapframe */
         restore_context(current_thread->context);
index 7ce94cd..ae92e45 100644 (file)
@@ -23,7 +23,7 @@
  * location of notif_disabled, and a clobbered work register) to enable notifs,
  * make sure notif IPIs weren't pending, restore the work reg, and then "ret".
  *
- * This is what the target notif_tf's stack will look like (growing down):
+ * This is what the target uthread's stack will look like (growing down):
  *
  * Target ESP -> |   u_thread's old stuff   | the future %esp, tf->tf_esp
  *               |   new eip                | 0x04 below %esp (one slot is 0x04)
@@ -64,7 +64,7 @@ struct restart_helper {
        uint32_t                                        eip;
 };
 
-static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
+static inline void pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid)
 {
        struct restart_helper *rst;
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
@@ -128,7 +128,7 @@ static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
 
 /* Like the regular pop_ros_tf, but this one doesn't check or clear
  * notif_pending. */
-static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
+static inline void pop_ros_tf_raw(struct hw_trapframe *tf, uint32_t vcoreid)
 {
        struct restart_helper *rst;
        struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
@@ -175,9 +175,9 @@ static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
 /* Save the current context/registers into the given tf, setting the pc of the
  * tf to the end of this function.  You only need to save that which you later
  * restore with pop_ros_tf(). */
-static inline void save_ros_tf(struct user_trapframe *tf)
+static inline void save_ros_tf(struct hw_trapframe *tf)
 {
-       memset(tf, 0, sizeof(struct user_trapframe)); /* sanity */
+       memset(tf, 0, sizeof(struct hw_trapframe)); /* sanity */
        /* set CS and make sure eflags is okay */
        tf->tf_cs = GD_UT | 3;
        tf->tf_eflags = 0x00000200; /* interrupts enabled.  bare minimum eflags. */
@@ -200,9 +200,9 @@ static inline void save_ros_tf(struct user_trapframe *tf)
 
 /* This assumes a user_tf looks like a regular kernel trapframe */
 static __inline void
-init_user_tf(struct user_trapframe *u_tf, uint32_t entry_pt, uint32_t stack_top)
+init_user_tf(struct hw_trapframe *u_tf, uint32_t entry_pt, uint32_t stack_top)
 {
-       memset(u_tf, 0, sizeof(struct user_trapframe));
+       memset(u_tf, 0, sizeof(struct hw_trapframe));
        u_tf->tf_eip = entry_pt;
        u_tf->tf_cs = GD_UT | 3;
        u_tf->tf_esp = stack_top;
@@ -217,7 +217,7 @@ init_user_tf(struct user_trapframe *u_tf, uint32_t entry_pt, uint32_t stack_top)
 
 /* For debugging. */
 #include <stdio.h>
-static __inline void print_trapframe(struct user_trapframe *tf)
+static __inline void print_trapframe(struct hw_trapframe *tf)
 {
        printf("[user] TRAP frame %08p\n", tf);
        printf("  edi  0x%08x\n", tf->tf_regs.reg_edi);
index 542fd9a..3b2d855 100644 (file)
 #endif
 
 /* Register saves and restores happen in asm. */
-typedef void (*helper_fn)(struct user_trapframe*, struct preempt_data*, uint32_t);
-void __pop_ros_tf_regs(struct user_trapframe *tf, struct preempt_data* vcpd,
+typedef void (*helper_fn)(struct hw_trapframe*, struct preempt_data*, uint32_t);
+void __pop_ros_tf_regs(struct hw_trapframe *tf, struct preempt_data* vcpd,
                     uint32_t vcoreid, helper_fn helper) __attribute__((noreturn));
-void __save_ros_tf_regs(struct user_trapframe *tf);
+void __save_ros_tf_regs(struct hw_trapframe *tf);
 
 /* Helper function that may handle notifications after re-enabling them. */
-static void __pop_ros_tf_notifs(struct user_trapframe *tf,
+static void __pop_ros_tf_notifs(struct hw_trapframe *tf,
                                 struct preempt_data* vcpd, uint32_t vcoreid)
 {
        vcpd->notif_disabled = FALSE;
@@ -36,18 +36,18 @@ static void __pop_ros_tf_notifs(struct user_trapframe *tf,
 }
 
 /* Helper function that won't handle notifications after re-enabling them. */
-static void __pop_ros_tf_notifs_raw(struct user_trapframe *tf,
+static void __pop_ros_tf_notifs_raw(struct hw_trapframe *tf,
                                     struct preempt_data* vcpd, uint32_t vcoreid)
 {
        vcpd->notif_disabled = FALSE;
 }
 
-static inline void __pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid,
+static inline void __pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid,
                                 helper_fn helper)
 {
        // since we're changing the stack, move stuff into regs for now
        register uint32_t _vcoreid = vcoreid;
-       register struct user_trapframe* _tf = tf;
+       register struct hw_trapframe* _tf = tf;
 
        set_stack_pointer((void*)tf->gpr[30]);
 
@@ -70,14 +70,14 @@ static inline void __pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid,
  * 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, uint32_t vcoreid)
+static inline void pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid)
 {
        __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs);
 }
 
 /* Like the regular pop_ros_tf, but this one doesn't check or clear
  * notif_pending. */
-static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
+static inline void pop_ros_tf_raw(struct hw_trapframe *tf, uint32_t vcoreid)
 {
        __pop_ros_tf(tf, vcoreid, &__pop_ros_tf_notifs_raw);
 }
@@ -85,14 +85,14 @@ static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
 /* Save the current context/registers into the given tf, setting the pc of the
  * tf to the end of this function.  You only need to save that which you later
  * restore with pop_ros_tf(). */
-static inline void save_ros_tf(struct user_trapframe *tf)
+static inline void save_ros_tf(struct hw_trapframe *tf)
 {
        __save_ros_tf_regs(tf);
 }
 
 /* This assumes a user_tf looks like a regular kernel trapframe */
 static __inline void
-init_user_tf(struct user_trapframe *u_tf, long entry_pt, long stack_top)
+init_user_tf(struct hw_trapframe *u_tf, long entry_pt, long stack_top)
 {
        memset(u_tf, 0, sizeof(*u_tf));
        u_tf->gpr[30] = stack_top;
index d0012a2..c02b4f4 100644 (file)
@@ -36,11 +36,11 @@ static inline void set_tls_desc(void *tls_desc, uint32_t vcoreid)
  * 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, uint32_t vcoreid)
+static inline void pop_ros_tf(struct hw_trapframe *tf, uint32_t vcoreid)
 {
        // since we're changing the stack, move stuff into regs for now
        register uint32_t _vcoreid = vcoreid;
-       register struct user_trapframe* _tf = tf;
+       register struct hw_trapframe* _tf = tf;
 
        set_stack_pointer((void*)tf->gpr[14]);
 
@@ -64,11 +64,11 @@ static inline void pop_ros_tf(struct user_trapframe *tf, uint32_t vcoreid)
 
 /* Like the regular pop_ros_tf, but this one doesn't check or clear
  * notif_pending.  TODO: someone from sparc should look at this. */
-static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
+static inline void pop_ros_tf_raw(struct hw_trapframe *tf, uint32_t vcoreid)
 {
        // since we're changing the stack, move stuff into regs for now
        register uint32_t _vcoreid = vcoreid;
-       register struct user_trapframe* _tf = tf;
+       register struct hw_trapframe* _tf = tf;
 
        set_stack_pointer((void*)tf->gpr[14]);
 
@@ -93,7 +93,7 @@ static inline void pop_ros_tf_raw(struct user_trapframe *tf, uint32_t vcoreid)
 /* Save the current context/registers into the given tf, setting the pc of the
  * tf to the end of this function.  You only need to save that which you later
  * restore with pop_ros_tf(). */
-static inline void save_ros_tf(struct user_trapframe *tf)
+static inline void save_ros_tf(struct hw_trapframe *tf)
 {
        // just do it in the kernel.  since we need to flush windows anyway,
        // this isn't an egregious overhead.
@@ -102,9 +102,9 @@ static inline void save_ros_tf(struct user_trapframe *tf)
 
 /* This assumes a user_tf looks like a regular kernel trapframe */
 static __inline void
-init_user_tf(struct user_trapframe *u_tf, uint32_t entry_pt, uint32_t stack_top)
+init_user_tf(struct hw_trapframe *u_tf, uint32_t entry_pt, uint32_t stack_top)
 {
-       memset(u_tf, 0, sizeof(struct user_trapframe));
+       memset(u_tf, 0, sizeof(struct hw_trapframe));
        u_tf->gpr[14] = stack_top - 96;
        u_tf->pc = entry_pt;
        u_tf->npc = entry_pt + 4;
index 3c26e3d..0fc5562 100644 (file)
@@ -20,7 +20,7 @@
  * cast their threads to uthreads when talking with vcore code.  Vcore/default
  * 2LS code won't touch udata or beyond. */
 struct uthread {
-       struct user_trapframe utf;
+       struct user_context u_ctx;
        struct ancillary_state as;
        void *tls_desc;
        int flags;
@@ -80,10 +80,11 @@ void run_uthread(struct uthread *uthread);
 
 /* Asking for trouble with this API, when we just want stacktop (or whatever
  * the SP will be). */
-static inline void init_uthread_tf(struct uthread *uth, void (*entry)(void),
-                                   void *stack_bottom, uint32_t size)
+static inline void init_uthread_ctx(struct uthread *uth, void (*entry)(void),
+                                    void *stack_bottom, uint32_t size)
 {
-       init_user_tf(&uth->utf, (long)entry, (long)(stack_bottom) + size);
+       init_user_tf(&uth->u_ctx.tf.hw_tf, (long)entry,
+                    (long)(stack_bottom) + size);
 }
 
 #define uthread_set_tls_var(uth, name, val)                                    \
index d77fbed..7415670 100644 (file)
@@ -278,7 +278,7 @@ void uthread_yield(bool save_state, void (*yield_func)(struct uthread*, void*),
        if (save_state) {
                /* TODO: (HSS) Save silly state */
                // save_fp_state(&t->as);
-               save_ros_tf(&uthread->utf);
+               save_ros_tf(&uthread->u_ctx.tf.hw_tf);
        }
        cmb();  /* Force a reread of yielding. Technically save_ros_tf() is enough*/
        /* Restart path doesn't matter if we're dying */
@@ -394,14 +394,14 @@ static void __run_cur_uthread(void)
        set_tls_desc(uthread->tls_desc, vcoreid);
        __vcoreid = vcoreid;    /* setting the uthread's TLS var */
        /* Depending on where it was saved, we pop differently.  This assumes that
-        * if a uthread was not saved, that it was running in the vcpd notif tf.
+        * if a uthread was not saved, that it was running in the vcpd uthread_ctx.
         * There should never be a time that the TF is unsaved and not in the notif
         * TF (or about to be in that TF). */
        if (uthread->flags & UTHREAD_SAVED) {
                uthread->flags &= ~UTHREAD_SAVED;
-               pop_ros_tf(&uthread->utf, vcoreid);
+               pop_ros_tf(&uthread->u_ctx.tf.hw_tf, vcoreid);
        } else  {
-               pop_ros_tf(&vcpd->notif_tf, vcoreid);
+               pop_ros_tf(&vcpd->uthread_ctx.tf.hw_tf, vcoreid);
        }
 }
 
@@ -471,7 +471,7 @@ static void __run_current_uthread_raw(void)
        set_tls_desc(current_uthread->tls_desc, vcoreid);
        __vcoreid = vcoreid;    /* setting the uthread's TLS var */
        /* Pop the user trap frame */
-       pop_ros_tf_raw(&vcpd->notif_tf, vcoreid);
+       pop_ros_tf_raw(&vcpd->uthread_ctx.tf.hw_tf, vcoreid);
        assert(0);
 }
 
@@ -483,7 +483,7 @@ static void copyout_uthread(struct preempt_data *vcpd, struct uthread *uthread)
        assert(uthread);
        /* Copy out the main tf if we need to */
        if (!(uthread->flags & UTHREAD_SAVED)) {
-               uthread->utf = vcpd->notif_tf;
+               uthread->u_ctx = vcpd->uthread_ctx;
                uthread->flags |= UTHREAD_SAVED;
                printd("VC %d copying out uthread %08p\n", vcore_id(), uthread);
        }
index 37ef272..6d938a0 100644 (file)
@@ -432,7 +432,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
        /* Set the u_tf to start up in __pthread_run, which will call the real
         * start_routine and pass it the arg.  Note those aren't set until later in
         * pthread_create(). */
-       init_user_tf(&pthread->uthread.utf, (long)&__pthread_run,
+       init_user_tf(&pthread->uthread.u_ctx.tf.hw_tf, (long)&__pthread_run,
                     (long)(pthread->stacktop));
        pthread->start_routine = start_routine;
        pthread->arg = arg;