Using sys_suspend syscall to halt a core and resume later.
authorGerd Zellweger <mail@gerdzellweger.com>
Wed, 18 Dec 2013 15:46:25 +0000 (16:46 +0100)
committerGerd Zellweger <mail@gerdzellweger.com>
Tue, 14 Oct 2014 06:47:41 +0000 (08:47 +0200)
Also adding user-level part where we do something similar to sys_yield, ie. save
the context for enabled dispatcher while disabled and set the dispatcher to
enabled again in the kernel. This ensures we will jump back to the right part
when scheduling without ever returning from the syscall.

include/barrelfish_kpi/syscalls.h
kernel/arch/x86_64/syscall.c
kernel/include/syscall.h
kernel/syscall.c
lib/barrelfish/arch/x86_64/dispatch.c
lib/barrelfish/arch/x86_64/syscalls.c
usr/monitor/inter.c

index 4ccb385..0c56dcf 100644 (file)
@@ -45,7 +45,7 @@ struct sysret {
 #define SYSCALL_NOP                 5     ///< No operation
 #define SYSCALL_PRINT               6     ///< Write to console
 
-/* Architecture-specific syscalls 
+/* Architecture-specific syscalls
  * FIXME: shouldn't these be in an arch-specific header? -AB */
 #ifdef __ARM_ARCH_7M__  //cortex-m3 on pandaboard
 //overwrite unused syscall instead of creating yet another global one
@@ -56,8 +56,9 @@ struct sysret {
 
 
 #define SYSCALL_X86_RELOAD_LDT      8     ///< Reload the LDT register (x86_64)
+#define SYSCALL_SUSPEND             9     ///< Suspend the CPU
 
-#define SYSCALL_COUNT               9     ///< Number of syscalls [0..SYSCALL_COUNT - 1]
+#define SYSCALL_COUNT               10     ///< Number of syscalls [0..SYSCALL_COUNT - 1]
 
 /*
  * To understand system calls it might be helpful to know that there
index cc98a0b..1f622e0 100644 (file)
@@ -326,6 +326,8 @@ static struct sysret monitor_stop_core(struct capability *kernel_cap,
     //apic_mask_timer();
     //apic_disable();
 
+    //dcb_current->disabled = false;
+
     global->wait[0] = 0x1;
     if (has_monitor_mwait()) {
         printf("%s:%s:%d: before monitor/mwait\n", __FILE__, __FUNCTION__, __LINE__);
@@ -333,6 +335,7 @@ static struct sysret monitor_stop_core(struct capability *kernel_cap,
     }
     else {
         printf("%s:%s:%d: before halt \n", __FILE__, __FUNCTION__, __LINE__);
+
         halt();
     }
 
@@ -1100,6 +1103,11 @@ struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
         maybe_reload_ldt(dcb_current, true);
         break;
 
+        // Temporarily suspend the CPU
+    case SYSCALL_SUSPEND:
+        retval = sys_suspend();
+        break;
+
     case SYSCALL_DEBUG:
         switch(arg0) {
         case DEBUG_CONTEXT_COUNTER_RESET:
index 278fbd6..6a36678 100644 (file)
@@ -23,6 +23,7 @@
 
 errval_t sys_print(const char *str, size_t length);
 struct sysret sys_yield(capaddr_t target);
+struct sysret sys_suspend(void);
 struct sysret
 sys_dispatcher_setup(struct capability *to, capaddr_t cptr, int depth,
                      capaddr_t vptr, capaddr_t dptr, bool run, capaddr_t odptr);
index a8b3616..0b15870 100644 (file)
@@ -523,6 +523,30 @@ struct sysret sys_yield(capaddr_t target)
     panic("Yield returned!");
 }
 
+struct sysret sys_suspend(void)
+{
+    dispatcher_handle_t handle = dcb_current->disp;
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+
+    debug(SUBSYS_DISPATCH, "%.*s suspends%s\n", DISP_NAME_LEN, disp->name);
+
+    if (!disp->disabled) {
+        printk(LOG_ERR, "SYSCALL_SUSPEND while enabled\n");
+        return SYSRET(SYS_ERR_CALLER_ENABLED);
+    }
+
+    disp->disabled = false;
+    dcb_current->disabled = false;
+
+    printf("%s:%s:%d: before halt \n", __FILE__, __FUNCTION__, __LINE__);
+    halt();
+    printf("%s:%s:%d: woken up again...\n", __FILE__, __FUNCTION__, __LINE__);
+
+    panic("Yield returned!");
+}
+
+
 /**
  * The format of the returned ID is:
  *
@@ -545,17 +569,17 @@ struct sysret sys_idcap_identify(struct capability *cap, idcap_id_t *id)
 /**
  * Calls correct handler function to spawn an app core.
  *
- * At the moment spawn_core_handlers is set-up per 
+ * At the moment spawn_core_handlers is set-up per
  * architecture inside text_init() usually found in init.c.
- * 
+ *
  * \note Generally the x86 terms of BSP and APP core are used
  * throughout Barrelfish to distinguish between bootstrap core (BSP)
  * and application cores (APP).
- * 
+ *
  * \param  core_id  Identifier of the core which we want to boot
  * \param  cpu_type Architecture of the core.
  * \param  entry    Entry point for code to start execution.
- * 
+ *
  * \retval SYS_ERR_OK Core successfully booted.
  * \retval SYS_ERR_ARCHITECTURE_NOT_SUPPORTED No handler registered for
  *     the specified cpu_type.
index 613cc65..08b2e2e 100644 (file)
@@ -259,3 +259,54 @@ disp_save(dispatcher_handle_t handle, arch_registers_state_t *state,
 
     __asm volatile ("save_resume:");
 }
+
+
+
+void
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
+__attribute__((optimize(2)))
+#endif
+disp_save_suspend(void)
+{
+    dispatcher_handle_t handle = disp_disable();
+    struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+    arch_registers_state_t *state =
+        dispatcher_get_enabled_save_area(handle);
+
+    assert_disabled(disp_gen->runq != NULL);
+    assert_disabled(disp->haswork);
+
+    struct registers_x86_64 *regs = state;
+
+    // Save resume IP, stack and control registers
+    // See disp_switch above for details
+    // XXX: Using the clobber list here to make the compiler save only
+    // used registers. Be very careful when changing the code below
+    // this asm block! If registers in the clobber list are
+    // subsequently used, they won't be restored at save_resume.
+    __asm volatile ("movq       %%rbp,  6*8(%[regs])    \n\t"
+                    "movq       %%rsp,  7*8(%[regs])    \n\t"
+                    "lea        save_resume(%%rip), %%rcx\n\t"
+                    "movq       %%rcx, 16*8(%[regs])    \n\t"   // RIP
+                    "pushfq                             \n\t"
+                    "popq       17*8(%[regs])           \n\t"   // RFLAGS
+                    "mov        %%fs, %%bx              \n\t"
+                    "mov        %%bx, %[fs]             \n\t"
+                    "mov        %%gs, %%bx              \n\t"
+                    "mov        %%bx, %[gs]             \n\t"
+                    :
+                    : [regs] "a" (regs),
+                      [fs] "m" (regs->fs),
+                      [gs] "m" (regs->gs)
+                    : "rbx", "rcx", "rdx", "rsi", "rdi",
+                      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+                    );
+
+    sys_suspend();
+    assert_disabled(!"This code won't run if the yield succeeded.");
+
+    __asm volatile ("save_resume:");
+    // Instead we go here directly
+}
index b314362..a6ac7ea 100644 (file)
@@ -25,6 +25,11 @@ errval_t sys_yield(capaddr_t target)
     return syscall2(SYSCALL_YIELD, target).error;
 }
 
+errval_t sys_suspend(capaddr_t target)
+{
+    return syscall1(SYSCALL_SUSPEND).error;
+}
+
 errval_t sys_print(const char *string, size_t length)
 {
     return syscall3(SYSCALL_PRINT, (uintptr_t)string, length).error;
index 5a17cf0..11dce48 100644 (file)
@@ -666,10 +666,12 @@ static void stop_core(void* arg)
 {
     printf("%s:%s:%d: execute stop core\n",
            __FILE__, __FUNCTION__, __LINE__);
-    errval_t err = invoke_monitor_stop_core();
-    if (err_is_fail(err)) {
+    //errval_t err = invoke_monitor_stop_core();
+    /*if (err_is_fail(err)) {
         DEBUG_ERR(err, "Can not stop the core.");
-    }
+    }*/
+    void disp_save_suspend(void);
+    disp_save_suspend();
 }
 
 static void power_down_request(struct intermon_binding *b)