fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / um / os-Linux / skas / process.c
index 215ef68..c4998cf 100644 (file)
@@ -8,16 +8,14 @@
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
-#include <setjmp.h>
 #include <sched.h>
 #include "ptrace_user.h"
 #include <sys/wait.h>
 #include <sys/mman.h>
 #include <sys/user.h>
 #include <sys/time.h>
-#include <asm/unistd.h>
+#include <sys/syscall.h>
 #include <asm/types.h>
-#include <asm/page.h>
 #include "user.h"
 #include "sysdep/ptrace.h"
 #include "user_util.h"
@@ -69,7 +67,7 @@ void wait_stub_done(int pid, int sig, char * fname)
 
        if((n < 0) || !WIFSTOPPED(status) ||
           (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
-               unsigned long regs[HOST_FRAME_SIZE];
+               unsigned long regs[MAX_REG_NR];
 
                if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
                        printk("Failed to get registers from stub, "
@@ -78,7 +76,7 @@ void wait_stub_done(int pid, int sig, char * fname)
                        int i;
 
                        printk("Stub registers -\n");
-                       for(i = 0; i < HOST_FRAME_SIZE; i++)
+                       for(i = 0; i < ARRAY_SIZE(regs); i++)
                                printk("\t%d - %lx\n", i, regs[i]);
                }
                panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
@@ -157,11 +155,15 @@ extern int __syscall_stub_start;
 static int userspace_tramp(void *stack)
 {
        void *addr;
+       int err;
 
        ptrace(PTRACE_TRACEME, 0, 0, 0);
 
-       init_new_thread_signals(1);
-       enable_timer();
+       init_new_thread_signals();
+       err = set_interval(1);
+       if(err)
+               panic("userspace_tramp - setting timer failed, errno = %d\n",
+                     err);
 
        if(!proc_mm){
                /* This has a pte, but it can't be mapped in with the usual
@@ -191,14 +193,25 @@ static int userspace_tramp(void *stack)
                }
        }
        if(!ptrace_faultinfo && (stack != NULL)){
+               struct sigaction sa;
+
                unsigned long v = UML_CONFIG_STUB_CODE +
                                  (unsigned long) stub_segv_handler -
                                  (unsigned long) &__syscall_stub_start;
 
                set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
-               set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
-                           SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
-                           SIGUSR1, -1);
+               sigemptyset(&sa.sa_mask);
+               sigaddset(&sa.sa_mask, SIGIO);
+               sigaddset(&sa.sa_mask, SIGWINCH);
+               sigaddset(&sa.sa_mask, SIGALRM);
+               sigaddset(&sa.sa_mask, SIGVTALRM);
+               sigaddset(&sa.sa_mask, SIGUSR1);
+               sa.sa_flags = SA_ONSTACK;
+               sa.sa_handler = (void *) v;
+               sa.sa_restorer = NULL;
+               if(sigaction(SIGSEGV, &sa, NULL) < 0)
+                       panic("userspace_tramp - setting SIGSEGV handler "
+                             "failed - errno = %d\n", errno);
        }
 
        os_stop_process(os_getpid());
@@ -266,7 +279,7 @@ void userspace(union uml_pt_regs *regs)
                if(err)
                        panic("userspace - could not resume userspace process, "
                              "pid=%d, ptrace operation = %d, errno = %d\n",
-                             op, errno);
+                             pid, op, errno);
 
                CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
                if(err < 0)
@@ -315,7 +328,7 @@ void userspace(union uml_pt_regs *regs)
 int copy_context_skas0(unsigned long new_stack, int pid)
 {
        int err;
-       unsigned long regs[HOST_FRAME_SIZE];
+       unsigned long regs[MAX_REG_NR];
        unsigned long fp_regs[HOST_FP_SIZE];
        unsigned long current_stack = current_stub_stack();
        struct stub_data *data = (struct stub_data *) current_stack;
@@ -345,12 +358,12 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        err = ptrace_setregs(pid, regs);
        if(err < 0)
                panic("copy_context_skas0 : PTRACE_SETREGS failed, "
-                     "pid = %d, errno = %d\n", pid, errno);
+                     "pid = %d, errno = %d\n", pid, -err);
 
        err = ptrace_setfpregs(pid, fp_regs);
        if(err < 0)
                panic("copy_context_skas0 : PTRACE_SETFPREGS failed, "
-                     "pid = %d, errno = %d\n", pid, errno);
+                     "pid = %d, errno = %d\n", pid, -err);
 
        /* set a well known return code for detection of child write failure */
        child_data->err = 12345678;
@@ -363,14 +376,14 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        pid = data->err;
        if(pid < 0)
                panic("copy_context_skas0 - stub-parent reports error %d\n",
-                     pid);
+                     -pid);
 
        /* Wait, until child has finished too: read child's result from
         * child's stack and check it.
         */
        wait_stub_done(pid, -1, "copy_context_skas0");
        if (child_data->err != UML_CONFIG_STUB_DATA)
-               panic("copy_context_skas0 - stub-child reports error %d\n",
+               panic("copy_context_skas0 - stub-child reports error %ld\n",
                      child_data->err);
 
        if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
@@ -431,89 +444,50 @@ void map_stub_pages(int fd, unsigned long code,
        }
 }
 
-void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
-               void (*handler)(int))
+void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
 {
-       unsigned long flags;
-       sigjmp_buf switch_buf, fork_buf;
-       int enable;
-
-       *switch_buf_ptr = &switch_buf;
-       *fork_buf_ptr = &fork_buf;
-
-       /* Somewhat subtle - siglongjmp restores the signal mask before doing
-        * the longjmp.  This means that when jumping from one stack to another
-        * when the target stack has interrupts enabled, an interrupt may occur
-        * on the source stack.  This is bad when starting up a process because
-        * it's not supposed to get timer ticks until it has been scheduled.
-        * So, we disable interrupts around the sigsetjmp to ensure that
-        * they can't happen until we get back here where they are safe.
-        */
-       flags = get_signals();
-       block_signals();
-       if(UML_SIGSETJMP(&fork_buf, enable) == 0)
-               new_thread_proc(stack, handler);
-
-       remove_sigstack();
-
-       set_signals(flags);
+       (*buf)[0].JB_IP = (unsigned long) handler;
+       (*buf)[0].JB_SP = (unsigned long) stack +
+               (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
 }
 
 #define INIT_JMP_NEW_THREAD 0
-#define INIT_JMP_REMOVE_SIGSTACK 1
-#define INIT_JMP_CALLBACK 2
-#define INIT_JMP_HALT 3
-#define INIT_JMP_REBOOT 4
+#define INIT_JMP_CALLBACK 1
+#define INIT_JMP_HALT 2
+#define INIT_JMP_REBOOT 3
 
-void thread_wait(void *sw, void *fb)
+void switch_threads(jmp_buf *me, jmp_buf *you)
 {
-       sigjmp_buf buf, **switch_buf = sw, *fork_buf;
-       int enable;
-
-       *switch_buf = &buf;
-       fork_buf = fb;
-       if(UML_SIGSETJMP(&buf, enable) == 0)
-               siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
+       if(UML_SETJMP(me) == 0)
+               UML_LONGJMP(you, 1);
 }
 
-void switch_threads(void *me, void *next)
-{
-       sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
-       int enable;
-
-       *me_ptr = &my_buf;
-       if(UML_SIGSETJMP(&my_buf, enable) == 0)
-               UML_SIGLONGJMP(next_buf, 1);
-}
-
-static sigjmp_buf initial_jmpbuf;
+static jmp_buf initial_jmpbuf;
 
 /* XXX Make these percpu */
 static void (*cb_proc)(void *arg);
 static void *cb_arg;
-static sigjmp_buf *cb_back;
+static jmp_buf *cb_back;
 
-int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
+int start_idle_thread(void *stack, jmp_buf *switch_buf)
 {
-       sigjmp_buf **switch_buf = switch_buf_ptr;
-       int n, enable;
+       int n;
 
        set_handler(SIGWINCH, (__sighandler_t) sig_handler,
                    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
                    SIGVTALRM, -1);
 
-       *fork_buf_ptr = &initial_jmpbuf;
-       n = UML_SIGSETJMP(&initial_jmpbuf, enable);
+       n = UML_SETJMP(&initial_jmpbuf);
        switch(n){
        case INIT_JMP_NEW_THREAD:
-               new_thread_proc((void *) stack, new_thread_handler);
-               break;
-       case INIT_JMP_REMOVE_SIGSTACK:
-               remove_sigstack();
+               (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
+               (*switch_buf)[0].JB_SP = (unsigned long) stack +
+                       (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) -
+                       sizeof(void *);
                break;
        case INIT_JMP_CALLBACK:
                (*cb_proc)(cb_arg);
-               UML_SIGLONGJMP(cb_back, 1);
+               UML_LONGJMP(cb_back, 1);
                break;
        case INIT_JMP_HALT:
                kmalloc_ok = 0;
@@ -524,21 +498,20 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
        default:
                panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
        }
-       UML_SIGLONGJMP(*switch_buf, 1);
+       UML_LONGJMP(switch_buf, 1);
 }
 
 void initial_thread_cb_skas(void (*proc)(void *), void *arg)
 {
-       sigjmp_buf here;
-       int enable;
+       jmp_buf here;
 
        cb_proc = proc;
        cb_arg = arg;
        cb_back = &here;
 
        block_signals();
-       if(UML_SIGSETJMP(&here, enable) == 0)
-               UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
+       if(UML_SETJMP(&here) == 0)
+               UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK);
        unblock_signals();
 
        cb_proc = NULL;
@@ -549,13 +522,13 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
 void halt_skas(void)
 {
        block_signals();
-       UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
+       UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
 }
 
 void reboot_skas(void)
 {
        block_signals();
-       UML_SIGLONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
+       UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
 }
 
 void switch_mm_skas(struct mm_id *mm_idp)