Slimmer setjmps
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 12 Jun 2014 17:41:43 +0000 (10:41 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 12 Jun 2014 17:41:43 +0000 (10:41 -0700)
AFAIK, the returns_twice tells the compiler to not expect any
caller-saved registers to still be valid.  The handmade asm clobber
tells the compiler not to trust any callee-saved registers either.  The
compiler might be allowed to save and restore the registers across that
asm volatile, but it doesn't seem to do so.

The clobbering of the callee-saved registers was necessary; despite the
language of the returns_twice attribute, which does not make a
distinction between caller-saved and callee-saved.

In addition to faster waserrors, this leads to smaller errbufs, which
leads to kthreads using less stack space.  Ultimately, we'll be able to
go back to single-page kthread stacks.

kern/arch/riscv/setjmp.S
kern/arch/riscv/setjmp.h
kern/arch/x86/setjmp.h
kern/arch/x86/setjmp32.S
kern/arch/x86/setjmp64.S
kern/include/err.h
kern/include/ns.h
kern/include/setjmp.h

index fdcb1f7..56f867d 100644 (file)
@@ -1,4 +1,4 @@
-# Kernel implementations for setjmp/longjmp.
+# Kernel implementations for slim setjmp/longjmp.
 # TODO: Implement for riscv
 #
 # int setjmp(struct jmpbuf *env);
@@ -6,12 +6,12 @@
 
 .text
 .align 4
-.globl setjmp
-.type setjmp, @function
-setjmp:
+.globl slim_setjmp
+.type slim_setjmp, @function
+slim_setjmp:
        ret
        
-.size setjmp,.-setjmp
+.size slim_setjmp,.-slim_setjmp
 
 .text
 .align 4
index bc6adc5..846b11a 100644 (file)
@@ -4,7 +4,11 @@
 #ifndef ROS_ARCH_SETJMP_H
 #define ROS_ARCH_SETJMP_H
 
+#warning "No jmpbuf/setjmp/longjmp!"
 struct jmpbuf {
 };
+static inline void __ros_clobber_callee_regs(void)
+{
+}
 
 #endif /* !ROS_ARCH_SETJMP_H */
index 187eaa0..8326034 100644 (file)
@@ -9,22 +9,26 @@
 struct jmpbuf {
        uintptr_t retaddr; // return address
        uintreg_t rsp;     // post-return rsp
-       uintreg_t rbx;     // callee saved registers
        uintreg_t rbp;
-       uintreg_t r12;
-       uintreg_t r13;
-       uintreg_t r14;
-       uintreg_t r15;
 };
+
+static inline void __ros_clobber_callee_regs(void)
+{
+       asm volatile ("" : : : "rbx", "r12", "r13", "r14", "r15");
+}
+
 #else
+
 struct jmpbuf {
        uintptr_t retaddr; // return address
        uintreg_t esp;     // post-return esp
-       uintreg_t ebx;     // callee saved registers
        uintreg_t ebp;
-       uintreg_t esi;
-       uintreg_t edi;
 };
+
+static inline __ros_clobber_callee_regs(void)
+{
+       asm volatile ("" : : : "ebx", "esi", "edi");
+}
 #endif
 
 #endif /* !ROS_ARCH_SETJMP_H */
index b4172e9..a9b4e87 100644 (file)
@@ -1,4 +1,4 @@
-# Kernel implementations for setjmp/longjmp.
+# Kernel implementations for slim setjmp/longjmp.
 #
 # int setjmp(struct jmpbuf *env);
 # void longjmp(struct jmpbuf *env, int val);
@@ -7,30 +7,24 @@
 # struct jmpbuf {
 #      uintptr_t retaddr; // return address
 #      uintreg_t esp;     // post-return esp
-#      uintreg_t ebx;     // callee saved registers
 #      uintreg_t ebp;
-#      uintreg_t esi;
-#      uintreg_t edi;
 # };
 
 .text
 .align 4
-.globl setjmp
-.type setjmp, @function
-setjmp:
+.globl slim_setjmp
+.type slim_setjmp, @function
+slim_setjmp:
        movl 4(%esp),%edx  # Grab a reference to the jmpbuf passed in
        xorl %eax,%eax     # Zero out the return value for our first return
        popl %ecx          # Temporarily grab the return address and adjust %rsp
        movl %ecx,(%edx)   # Save the return address
        movl %esp,4(%edx)  # The adjusted %esp is the post-return %esp (see longjmp)
-       movl %ebx,8(%edx)  # Save all the callee saved registers into the jmpbuf
-       movl %ebp,12(%edx)
-       movl %esi,16(%edx)
-       movl %edi,20(%edx)
+       movl %ebp,8(%edx)
        pushl %ecx         # Restore stuff to make the call/return stack happy
        ret
  
-.size setjmp,.-setjmp
+.size slim_setjmp,.-slim_setjmp
  
 .text
 .align 4
@@ -39,10 +33,7 @@ setjmp:
 longjmp:
        movl 4(%esp),%edx  # Grab a reference to the jmpbuf passed in
        movl 8(%esp),%eax  # Set the return value to val (32-bit int)
-       movl 20(%edx),%edi # Restore all the callee saved registers from the jmpbuf
-       movl 16(%edx),%esi
-       movl 12(%edx),%ebp
-       movl 8(%edx),%ebx
+       movl 8(%edx),%ebp
        movl 4(%edx),%esp  # Set the post-return %rsp
        jmp *(%edx)        # Jump back to setjmp callsite (no ret necessary)
  
index 93cf0ee..22ce081 100644 (file)
@@ -1,39 +1,32 @@
-# Kernel implementations for setjmp/longjmp.
+# Kernel implementations for a slim setjmp/longjmp.
 #
 # int setjmp(struct jmpbuf *env);
 # void longjmp(struct jmpbuf *env, int val);
+#
+# Callers *must* clobber all callee-saved registers first, e.g.:
+#      asm volatile ("" : : : "rbx", "r12", "r13", "r14", "r15");
 
 # The jmpbuf struct is defined as below:
 # struct jmpbuf {
 #      uintptr_t retaddr; // return address
 #      uintreg_t rsp;     // post-return rsp
-#      uintreg_t rbx;
 #      uintreg_t rbp;
-#      uintreg_t r12;
-#      uintreg_t r13;
-#      uintreg_t r14;
-#      uintreg_t r15;
 # };
 
 .text
 .align 4
-.globl setjmp
-.type setjmp, @function
-setjmp:
+.globl slim_setjmp
+.type slim_setjmp, @function
+slim_setjmp:
        xorl %eax,%eax     # Zero out the return value for our first return
        pop  %rsi          # Temporarily grab the return address and adjust %rsp
        movq %rsi,(%rdi)   # Save the return address
        movq %rsp,8(%rdi)  # The adjusted %rsp is the post-return %rsp (see longjmp)
-       movq %rbx,16(%rdi) # Save all the callee saved registers into the jmpbuf
-       movq %rbp,24(%rdi) 
-       movq %r12,32(%rdi) 
-       movq %r13,40(%rdi) 
-       movq %r14,48(%rdi) 
-       movq %r15,56(%rdi) 
+       movq %rbp,16(%rdi) 
        push %rsi          # Restore stuff to make the call/return stack happy
        ret
        
-.size setjmp,.-setjmp
+.size slim_setjmp,.-slim_setjmp
 
 .text
 .align 4
@@ -41,12 +34,7 @@ setjmp:
 .type longjmp, @function
 longjmp:
        movl %esi,%eax     # Set the return value to val (32-bit int)
-       movq 56(%rdi),%r15 # Restore all the callee saved registers from the jmpbuf
-       movq 48(%rdi),%r14  
-       movq 40(%rdi),%r13
-       movq 32(%rdi),%r12
-       movq 24(%rdi),%rbp
-       movq 16(%rdi),%rbx
+       movq 16(%rdi),%rbp
        movq 8(%rdi),%rsp  # Set the post-return %rsp
        jmp *(%rdi)        # Jump back to setjmp callsite (no ret necessary)
        
index c710032..e42ec69 100644 (file)
@@ -10,7 +10,6 @@ struct errbuf {
        struct jmpbuf jmpbuf;
 };
 
-/* add 1 in case they forget they need an entry for the passed-in errbuf */
 #define ERRSTACK(x) struct errbuf *prev_errbuf; struct errbuf errstack[(x)];   \
                     int curindex = 0;
 #define waserror() (errpush(errstack, ARRAY_SIZE(errstack), &curindex,         \
index 1f87548..612ff38 100644 (file)
@@ -923,12 +923,6 @@ extern char Enofd[];                       /* no free file descriptors */
 extern char Enoctl[];                  /* unknown control request */
 extern char Eprocdied[];               /* process died */
 
-/* kern/src/err.c */
-int errpush(struct errbuf *errstack, int stacksize, int *curindex,
-                       struct errbuf **prev_errbuf);
-void errpop(struct errbuf *errstack, int stacksize, int *curindex,
-                       struct errbuf *prev_errbuf);
-/* */
 char *get_cur_genbuf(void);
 
 /* hack for now. */
index 88f7ccd..fd7f28e 100644 (file)
@@ -5,7 +5,12 @@
 
 #include <arch/setjmp.h>
 
-int setjmp(struct jmpbuf *env) __attribute__((returns_twice));
+int slim_setjmp(struct jmpbuf *env) __attribute__((returns_twice));
 void longjmp(struct jmpbuf *env, int val) __attribute__((noreturn));
 
+#define setjmp(jb) ({bool err;                                                 \
+                    __ros_clobber_callee_regs();                               \
+                    err = slim_setjmp(jb);                                     \
+                    err;})
+
 #endif /* !ROS_SETJMP_H */