Use a helper for resetting kernel stacks
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 26 Oct 2016 20:40:37 +0000 (16:40 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 29 Nov 2016 16:27:40 +0000 (11:27 -0500)
It's another arch-specific helper, but I have another case in an
upcoming commit that will need to pass the function pointer.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/riscv/arch.h
kern/arch/x86/arch.h
kern/src/kthread.c
kern/src/smp.c

index fdfaa86..9e6a18a 100644 (file)
@@ -165,3 +165,10 @@ static inline void prefetch(void *addr)
 static inline void prefetchw(void *addr)
 {
 }
+
+/* Resets a stack pointer to sp, then calls f(arg) */
+static inline void __attribute__((noreturn))
+__reset_stack_pointer(void *arg, uintptr_t sp, void (*f)(void *))
+{
+       #error "implement me"
+}
index 264f4cb..e20997e 100644 (file)
@@ -27,6 +27,8 @@ static inline void reboot(void)
 static inline void prefetch(void *addr);
 static inline void prefetchw(void *addr);
 static inline void swap_gs(void);
+static inline void __attribute__((noreturn))
+__reset_stack_pointer(void *arg, uintptr_t sp, void (*f)(void *));
 
 /* in trap.c */
 void send_ipi(uint32_t os_coreid, uint8_t vector);
@@ -182,3 +184,19 @@ static inline void swap_gs(void)
 {
        asm volatile ("swapgs");
 }
+
+/* Resets a stack pointer to sp, then calls f(arg) */
+static inline void __attribute__((noreturn))
+__reset_stack_pointer(void *arg, uintptr_t sp, void (*f)(void *))
+{
+       /* FP must be zeroed before SP.  Ideally, we'd do both atomically.  If we
+        * take an IRQ/NMI in between and set SP first, then a backtrace would be
+        * confused since FP points *below* the SP that the *IRQ handler* is now
+        * using.  By zeroing FP first, at least we won't BT at all (though FP is
+        * still out of sync with SP). */
+       asm volatile ("mov $0x0, %%rbp;"
+                     "mov %0, %%rsp;"
+                     "jmp *%%rdx;"
+                     : : "q"(sp), "D"(arg), "d"(f));
+       while (1);
+}
index d89b44c..afd7544 100644 (file)
@@ -303,33 +303,10 @@ bool sem_trydown(struct semaphore *sem)
        return ret;
 }
 
-/* Helper, pushes the sem pointer on the top of the stack, returning the stack
- * pointer to use. */
-static uintptr_t push_sem_ptr(uintptr_t stack_top, struct semaphore *sem)
-{
-       struct semaphore **sp_ptr;
-
-       sp_ptr = (struct semaphore**)(stack_top - sizeof(struct semaphore*));
-       *sp_ptr = sem;
-       return (uintptr_t)sp_ptr;
-}
-
-/* Helper: gets the sem pointer from the top of the stack.  Note we don't pop
- * from the stack.  We're just using the topmost part of the stack for free
- * storage. */
-static struct semaphore *get_sem_ptr(void)
-{
-       struct semaphore **sp_ptr;
-
-       sp_ptr = (struct semaphore**)(get_stack_top() - sizeof(struct semaphore*));
-       return *sp_ptr;
-}
-
-
 /* Bottom-half of sem_down.  This is called after we jumped to the new stack. */
-static void __attribute__((noinline, noreturn)) __unlock_and_idle(void)
+static void __attribute__((noreturn)) __unlock_and_idle(void *arg)
 {
-       struct semaphore *sem = get_sem_ptr();
+       struct semaphore *sem = (struct semaphore*)arg;
 
        spin_unlock(&sem->lock);
        debug_unlock_semlist();
@@ -437,10 +414,7 @@ void sem_down(struct semaphore *sem)
                 * that doesn't change stacks, unlike x86_64), we'll be using the stack
                 * at the same time as the kthread.  We could just disable IRQs, but
                 * that wouldn't protect us from NMIs that don't change stacks. */
-               new_stacktop = push_sem_ptr(new_stacktop, sem);
-               set_frame_pointer(0);
-               set_stack_pointer(new_stacktop);
-               __unlock_and_idle();
+               __reset_stack_pointer(sem, new_stacktop, __unlock_and_idle);
                assert(0);
        }
        /* We get here if we should not sleep on sem (the signal beat the sleep).
index 08edcc7..bb9233c 100644 (file)
@@ -58,7 +58,7 @@ static void try_run_proc(void)
  * halt and wake up when interrupted, do any work on their work queue, then halt
  * again.  In between, the ksched gets a chance to tell it to do something else,
  * or perhaps to halt in another manner. */
-static void __attribute__((noinline, noreturn)) __smp_idle(void)
+static void __attribute__((noreturn)) __smp_idle(void *arg)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 
@@ -84,14 +84,7 @@ static void __attribute__((noinline, noreturn)) __smp_idle(void)
 
 void smp_idle(void)
 {
-       /* FP must be zeroed before SP.  Ideally, we'd do both atomically.  If we
-        * take an IRQ/NMI in between and set SP first, then a backtrace would be
-        * confused since FP points *below* the SP that the *IRQ handler* is now
-        * using.  By zeroing FP first, at least we won't BT at all (though FP is
-        * still out of sync with SP). */
-       set_frame_pointer(0);
-       set_stack_pointer(get_stack_top());
-       __smp_idle();
+       __reset_stack_pointer(0, get_stack_top(), __smp_idle);
 }
 
 /* Arch-independent per-cpu initialization.  This will call the arch dependent