vserver 2.0 rc7
[linux-2.6.git] / arch / um / kernel / skas / process.c
index db53368..773cd2b 100644 (file)
@@ -4,14 +4,13 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
 #include <setjmp.h>
 #include <sched.h>
 #include <sys/wait.h>
-#include <sys/ptrace.h>
-#include <linux/ptrace.h>
 #include <sys/mman.h>
 #include <sys/user.h>
 #include <asm/unistd.h>
 #include "chan_user.h"
 #include "signal_user.h"
 #include "registers.h"
+#include "process.h"
 
 int is_skas_winch(int pid, int fd, void *data)
 {
-       if(pid != os_getpid())
+        if(pid != os_getpgrp())
                return(0);
 
        register_winch_irq(-1, fd, -1, data);
        return(1);
 }
 
-static void handle_segv(int pid)
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
 {
-       struct ptrace_faultinfo fault;
        int err;
 
-       err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault);
+        err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
        if(err)
-               panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n",
-                     errno);
+                panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+                      "errno = %d\n", errno);
+
+        /* Special handling for i386, which has different structs */
+        if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+                memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+                       sizeof(struct faultinfo) -
+                       sizeof(struct ptrace_faultinfo));
+}
 
-       segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL);
+static void handle_segv(int pid, union uml_pt_regs * regs)
+{
+        get_skas_faultinfo(pid, &regs->skas.faultinfo);
+        segv(regs->skas.faultinfo, 0, 1, NULL);
 }
 
 /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/
@@ -62,7 +71,7 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
 
        if (!local_using_sysemu)
        {
-               err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+               err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
                if(err < 0)
                        panic("handle_trap - nullifying syscall failed errno = %d\n",
                              errno);
@@ -139,17 +148,20 @@ void userspace(union uml_pt_regs *regs)
        int err, status, op, pid = userspace_pid[0];
        int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
 
-       restore_registers(pid, regs);
-               
-       local_using_sysemu = get_using_sysemu();
+       while(1){
+               restore_registers(pid, regs);
 
-       op = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL;
-       err = ptrace(op, pid, 0, 0);
+               /* Now we set local_using_sysemu to be used for one loop */
+               local_using_sysemu = get_using_sysemu();
+
+               op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+
+               err = ptrace(op, pid, 0, 0);
+               if(err)
+                       panic("userspace - could not resume userspace process, "
+                             "pid=%d, ptrace operation = %d, errno = %d\n",
+                             op, errno);
 
-       if(err)
-               panic("userspace - PTRACE_%s failed, errno = %d\n",
-                      local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
-       while(1){
                CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
                if(err < 0)
                        panic("userspace - waitpid failed, errno = %d\n", 
@@ -162,7 +174,7 @@ void userspace(union uml_pt_regs *regs)
                if(WIFSTOPPED(status)){
                        switch(WSTOPSIG(status)){
                        case SIGSEGV:
-                               handle_segv(pid);
+                                handle_segv(pid, regs);
                                break;
                        case SIGTRAP + 0x80:
                                handle_trap(pid, regs, local_using_sysemu);
@@ -176,7 +188,7 @@ void userspace(union uml_pt_regs *regs)
                        case SIGBUS:
                        case SIGFPE:
                        case SIGWINCH:
-                               user_signal(WSTOPSIG(status), regs);
+                                user_signal(WSTOPSIG(status), regs, pid);
                                break;
                        default:
                                printk("userspace - child stopped with signal "
@@ -187,21 +199,13 @@ void userspace(union uml_pt_regs *regs)
                        /* Avoid -ERESTARTSYS handling in host */
                        PT_SYSCALL_NR(regs->skas.regs) = -1;
                }
-
-               restore_registers(pid, regs);
-
-               /*Now we ended the syscall, so re-read local_using_sysemu.*/
-               local_using_sysemu = get_using_sysemu();
-
-               op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
-
-               err = ptrace(op, pid, 0, 0);
-               if(err)
-                       panic("userspace - PTRACE_%s failed, "
-                             "errno = %d\n",
-                             local_using_sysemu ? "SYSEMU" : "SYSCALL", errno);
        }
 }
+#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
 
 void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
                void (*handler)(int))
@@ -237,7 +241,7 @@ void thread_wait(void *sw, void *fb)
        *switch_buf = &buf;
        fork_buf = fb;
        if(sigsetjmp(buf, 1) == 0)
-               siglongjmp(*fork_buf, 1);
+               siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK);
 }
 
 void switch_threads(void *me, void *next)
@@ -261,23 +265,31 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
        sigjmp_buf **switch_buf = switch_buf_ptr;
        int n;
 
+       set_handler(SIGWINCH, (__sighandler_t) sig_handler,
+                   SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
+                   SIGVTALRM, -1);
+
        *fork_buf_ptr = &initial_jmpbuf;
        n = sigsetjmp(initial_jmpbuf, 1);
-       if(n == 0)
-               new_thread_proc((void *) stack, new_thread_handler);
-       else if(n == 1)
-               remove_sigstack();
-       else if(n == 2){
+        switch(n){
+        case INIT_JMP_NEW_THREAD:
+                new_thread_proc((void *) stack, new_thread_handler);
+                break;
+        case INIT_JMP_REMOVE_SIGSTACK:
+                remove_sigstack();
+                break;
+        case INIT_JMP_CALLBACK:
                (*cb_proc)(cb_arg);
                siglongjmp(*cb_back, 1);
-       }
-       else if(n == 3){
+                break;
+        case INIT_JMP_HALT:
                kmalloc_ok = 0;
                return(0);
-       }
-       else if(n == 4){
+        case INIT_JMP_REBOOT:
                kmalloc_ok = 0;
                return(1);
+        default:
+                panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
        }
        siglongjmp(**switch_buf, 1);
 }
@@ -302,7 +314,7 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
 
        block_signals();
        if(sigsetjmp(here, 1) == 0)
-               siglongjmp(initial_jmpbuf, 2);
+               siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK);
        unblock_signals();
 
        cb_proc = NULL;
@@ -313,13 +325,13 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg)
 void halt_skas(void)
 {
        block_signals();
-       siglongjmp(initial_jmpbuf, 3);
+       siglongjmp(initial_jmpbuf, INIT_JMP_HALT);
 }
 
 void reboot_skas(void)
 {
        block_signals();
-       siglongjmp(initial_jmpbuf, 4);
+       siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
 }
 
 void switch_mm_skas(int mm_fd)