Add memory clobber to RISC-V set_stack_pointer
[akaros.git] / user / parlib / syscall.c
index 12157e6..10f46bb 100644 (file)
@@ -1,6 +1,7 @@
 // System call stubs.
 
 #include <parlib.h>
+#include <vcore.h>
 
 int sys_proc_destroy(int pid, int exitcode)
 {
@@ -137,10 +138,43 @@ int sys_block(unsigned int usec)
  * get started from vcore_entry() or not, and whether or not remote cores need
  * to sys_change_vcore to preempt-recover the calling vcore.  Only set this to
  * FALSE if you are unable to handle starting fresh at vcore_entry().  One
- * example of this is in mcs_pdr_locks */
-void sys_change_vcore(uint32_t vcoreid, bool enable_my_notif)
-{
-       ros_syscall(SYS_change_vcore, vcoreid, enable_my_notif, 0, 0, 0, 0);
+ * example of this is in mcs_pdr_locks.
+ *
+ * Will return:
+ *             0 if we successfully changed to the target vcore.
+ *             -EBUSY if the target vcore is already mapped (a good kind of failure)
+ *             -EAGAIN if we failed for some other reason and need to try again.  For
+ *             example, the caller could be preempted, and we never even attempted to
+ *             change.
+ *             -EINVAL some userspace bug */
+int sys_change_vcore(uint32_t vcoreid, bool enable_my_notif)
+{
+       /* Since we might be asking to start up on a fresh stack (if
+        * enable_my_notif), we need to use some non-stack memory for the struct
+        * sysc.  Our vcore could get restarted before the syscall finishes (after
+        * unlocking the proc, before finish_sysc()), and the act of finishing would
+        * write onto our stack.  Thus we use the per-vcore struct. */
+       int flags;
+       /* Need to wait while a previous syscall is not done or locked.  Since this
+        * should only be called from VC ctx, we'll just spin.  Should be extremely
+        * rare.  Note flags is initialized to SC_DONE. */
+       do {
+               cpu_relax();
+               flags = atomic_read(&__vcore_one_sysc.flags);
+       } while (!(flags & SC_DONE) || flags & SC_K_LOCK);
+       __vcore_one_sysc.num = SYS_change_vcore;
+       __vcore_one_sysc.arg0 = vcoreid;
+       __vcore_one_sysc.arg1 = enable_my_notif;
+       /* keep in sync with glibc sysdeps/ros/syscall.c */
+       __ros_arch_syscall((long)&__vcore_one_sysc, 1);
+       /* If we returned, either we wanted to (!enable_my_notif) or we failed.
+        * Need to wait til the sysc is finished to find out why.  Again, its okay
+        * to just spin. */
+       do {
+               cpu_relax();
+               flags = atomic_read(&__vcore_one_sysc.flags);
+       } while (!(flags & SC_DONE) || flags & SC_K_LOCK);
+       return __vcore_one_sysc.retval;
 }
 
 int sys_change_to_m(void)