From 13c06be399902c9ebda08e092edb1614bb4a3761 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:32:59 -0700 Subject: [PATCH] uml: Use klibc setjmp/longjmp This patch adds an implementation of setjmp and longjmp to UML, allowing access to the inside of a jmpbuf without needing the access macros formerly provided by libc. The implementation is stolen from klibc. I copy the relevant files into arch/um. I have another patch which avoids the copying, but requires klibc be in the tree. setjmp and longjmp users required some tweaking. Includes of were removed and includes of the UML longjmp.h were added where necessary. There are also replacements of siglongjmp with UML_LONGJMP which I somehow missed earlier. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/process.c | 1 - arch/um/os-Linux/skas/process.c | 3 +-- arch/um/os-Linux/sys-i386/registers.c | 10 +++++----- arch/um/os-Linux/sys-x86_64/registers.c | 10 +++++----- arch/um/os-Linux/trap.c | 1 - arch/um/os-Linux/uaccess.c | 3 +-- arch/um/os-Linux/util.c | 5 ++--- 7 files changed, 14 insertions(+), 19 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index b98d3ca2cd1b..3afde92ad2c0 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 7baf90fda58b..50418a5e7134 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "ptrace_user.h" #include @@ -470,7 +469,7 @@ void thread_wait(void *sw, void *fb) *switch_buf = &buf; fork_buf = fb; if(UML_SETJMP(&buf) == 0) - siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK); + UML_LONGJMP(fork_buf, INIT_JMP_REMOVE_SIGSTACK); } void switch_threads(void *me, void *next) diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 516f66dd87e3..1f90a2d71386 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -5,12 +5,12 @@ #include #include -#include #include "sysdep/ptrace_user.h" #include "sysdep/ptrace.h" #include "uml-config.h" #include "skas_ptregs.h" #include "registers.h" +#include "longjmp.h" #include "user.h" /* These are set once at boot time and not changed thereafter */ @@ -132,9 +132,9 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) { - struct __jmp_buf_tag *jmpbuf = buffer; + struct __jmp_buf *jmpbuf = buffer; - UPT_SET(uml_regs, EIP, jmpbuf->__jmpbuf[JB_PC]); - UPT_SET(uml_regs, UESP, jmpbuf->__jmpbuf[JB_SP]); - UPT_SET(uml_regs, EBP, jmpbuf->__jmpbuf[JB_BP]); + UPT_SET(uml_regs, EIP, jmpbuf->__eip); + UPT_SET(uml_regs, UESP, jmpbuf->__esp); + UPT_SET(uml_regs, EBP, jmpbuf->__ebp); } diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c index becd898d9398..e730447d6c02 100644 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ b/arch/um/os-Linux/sys-x86_64/registers.c @@ -5,11 +5,11 @@ #include #include -#include #include "ptrace_user.h" #include "uml-config.h" #include "skas_ptregs.h" #include "registers.h" +#include "longjmp.h" #include "user.h" /* These are set once at boot time and not changed thereafter */ @@ -80,9 +80,9 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) { - struct __jmp_buf_tag *jmpbuf = buffer; + struct __jmp_buf *jmpbuf = buffer; - UPT_SET(uml_regs, RIP, jmpbuf->__jmpbuf[JB_PC]); - UPT_SET(uml_regs, RSP, jmpbuf->__jmpbuf[JB_RSP]); - UPT_SET(uml_regs, RBP, jmpbuf->__jmpbuf[JB_RBP]); + UPT_SET(uml_regs, RIP, jmpbuf->__rip); + UPT_SET(uml_regs, RSP, jmpbuf->__rsp); + UPT_SET(uml_regs, RBP, jmpbuf->__rbp); } diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c index 90b29ae9af46..1df231a26244 100644 --- a/arch/um/os-Linux/trap.c +++ b/arch/um/os-Linux/trap.c @@ -5,7 +5,6 @@ #include #include -#include #include "kern_util.h" #include "user_util.h" #include "os.h" diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c index 865f6a6a2590..bbb73a650370 100644 --- a/arch/um/os-Linux/uaccess.c +++ b/arch/um/os-Linux/uaccess.c @@ -4,8 +4,7 @@ * Licensed under the GPL */ -#include -#include +#include #include "longjmp.h" unsigned long __do_user_copy(void *to, const void *from, int n, diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index c47a2a7ce70e..3f5b1514e8a7 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -107,11 +106,11 @@ int setjmp_wrapper(void (*proc)(void *, void *), ...) jmp_buf buf; int n; - n = sigsetjmp(buf, 1); + n = UML_SETJMP(&buf); if(n == 0){ va_start(args, proc); (*proc)(&buf, &args); } va_end(args); - return(n); + return n; } -- cgit v1.2.2 From 91b165c0594ab78c64f26d26e3174e6dfd60ed9d Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:00 -0700 Subject: [PATCH] uml: Use ARRAY_SIZE more assiduously There were a bunch of missed ARRAY_SIZE opportunities. Also, some formatting fixes in the affected areas of code. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/mem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 560c8063c77c..b170b4704dc4 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -114,14 +114,14 @@ static void which_tmpdir(void) } while(1){ - found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); + found = next(fd, buf, ARRAY_SIZE(buf), ' '); if(found != 1) break; if(!strncmp(buf, "/dev/shm", strlen("/dev/shm"))) goto found; - found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), '\n'); + found = next(fd, buf, ARRAY_SIZE(buf), '\n'); if(found != 1) break; } @@ -135,7 +135,7 @@ err: return; found: - found = next(fd, buf, sizeof(buf) / sizeof(buf[0]), ' '); + found = next(fd, buf, ARRAY_SIZE(buf), ' '); if(found != 1) goto err; -- cgit v1.2.2 From 6b7aaad9ba4f2a059a70014be12a921eceebfc47 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:02 -0700 Subject: [PATCH] uml: Fix handling of failed execs of helpers There were some bugs in handling failures to exec helper programs. errno was passed back from the child with the wrong sign. It was also ignored. In the case where it mattered, the errno from the (successful) read in the parent was used instead. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/helper.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 6987d1d247a2..cd15b9df5b5c 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -42,7 +42,7 @@ static int helper_child(void *arg) if(data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); - errval = errno; + errval = -errno; printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno); os_write_file(data->fd, &errval, sizeof(errval)); kill(os_getpid(), SIGKILL); @@ -62,7 +62,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, stack = *stack_out; else stack = alloc_stack(0, __cant_sleep()); if(stack == 0) - return(-ENOMEM); + return -ENOMEM; ret = os_pipe(fds, 1, 0); if(ret < 0){ @@ -95,16 +95,16 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, /* Read the errno value from the child, if the exec failed, or get 0 if * the exec succeeded because the pipe fd was set as close-on-exec. */ n = os_read_file(fds[0], &ret, sizeof(ret)); - if (n < 0) { - printk("run_helper : read on pipe failed, ret = %d\n", -n); - ret = n; - kill(pid, SIGKILL); - CATCH_EINTR(waitpid(pid, NULL, 0)); - } else if(n != 0){ - CATCH_EINTR(n = waitpid(pid, NULL, 0)); - ret = -errno; - } else { + if(n == 0) ret = pid; + else { + if(n < 0){ + printk("run_helper : read on pipe failed, ret = %d\n", + -n); + ret = n; + kill(pid, SIGKILL); + } + CATCH_EINTR(waitpid(pid, NULL, 0)); } out_close: -- cgit v1.2.2 From 19bdf0409f25a85a45874a5a8da6f3e4edcf4a49 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:04 -0700 Subject: [PATCH] uml: SIGIO cleanups - Various cleanups in the sigio code. - Removed explicit zero-initializations of a few structures. - Improved some error messages. - An API change - there was an asymmetry between reactivate_fd calling maybe_sigio_broken, which goes through all the machinery of figuring out if a file descriptor supports SIGIO and applying the workaround to it if not, and deactivate_fd, which just turns off the descriptor. This is changed so that only activate_fd calls maybe_sigio_broken, when the descriptor is first seen. reactivate_fd now calls add_sigio_fd, which is symmetric with ignore_sigio_fd. This removes a recursion which makes a critical section look more critical than it really was, obsoleting a big comment to that effect. This requires keeping track of all descriptors which are getting the SIGIO treatment, not just the ones being polled at any given moment, so that reactivate_fd, through add_sigio_fd, doesn't try to tell the SIGIO thread about descriptors it doesn't care about. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/sigio.c | 103 ++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 47 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 0ecac563c7b3..f6457765b17d 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -43,17 +43,9 @@ struct pollfds { /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread * synchronizes with it. */ -static struct pollfds current_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; - -static struct pollfds next_poll = { - .poll = NULL, - .size = 0, - .used = 0 -}; +static struct pollfds current_poll; +static struct pollfds next_poll; +static struct pollfds all_sigio_fds; static int write_sigio_thread(void *unused) { @@ -78,7 +70,8 @@ static int write_sigio_thread(void *unused) n = os_read_file(sigio_private[1], &c, sizeof(c)); if(n != sizeof(c)) printk("write_sigio_thread : " - "read failed, err = %d\n", -n); + "read on socket failed, " + "err = %d\n", -n); tmp = current_poll; current_poll = next_poll; next_poll = tmp; @@ -93,35 +86,36 @@ static int write_sigio_thread(void *unused) n = os_write_file(respond_fd, &c, sizeof(c)); if(n != sizeof(c)) - printk("write_sigio_thread : write failed, " - "err = %d\n", -n); + printk("write_sigio_thread : write on socket " + "failed, err = %d\n", -n); } } return 0; } -static int need_poll(int n) +static int need_poll(struct pollfds *polls, int n) { - if(n <= next_poll.size){ - next_poll.used = n; - return(0); + if(n <= polls->size){ + polls->used = n; + return 0; } - kfree(next_poll.poll); - next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); - if(next_poll.poll == NULL){ + kfree(polls->poll); + polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); + if(polls->poll == NULL){ printk("need_poll : failed to allocate new pollfds\n"); - next_poll.size = 0; - next_poll.used = 0; - return(-1); + polls->size = 0; + polls->used = 0; + return -ENOMEM; } - next_poll.size = n; - next_poll.used = n; - return(0); + polls->size = n; + polls->used = n; + return 0; } /* Must be called with sigio_lock held, because it's needed by the marked - * critical section. */ + * critical section. + */ static void update_thread(void) { unsigned long flags; @@ -156,34 +150,39 @@ static void update_thread(void) set_signals(flags); } -static int add_sigio_fd(int fd, int read) +int add_sigio_fd(int fd) { - int err = 0, i, n, events; + struct pollfd *p; + int err = 0, i, n; sigio_lock(); + for(i = 0; i < all_sigio_fds.used; i++){ + if(all_sigio_fds.poll[i].fd == fd) + break; + } + if(i == all_sigio_fds.used) + goto out; + + p = &all_sigio_fds.poll[i]; + for(i = 0; i < current_poll.used; i++){ if(current_poll.poll[i].fd == fd) goto out; } n = current_poll.used + 1; - err = need_poll(n); + err = need_poll(&next_poll, n); if(err) goto out; for(i = 0; i < current_poll.used; i++) next_poll.poll[i] = current_poll.poll[i]; - if(read) events = POLLIN; - else events = POLLOUT; - - next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, - .events = events, - .revents = 0 }); + next_poll.poll[n - 1] = *p; update_thread(); out: sigio_unlock(); - return(err); + return err; } int ignore_sigio_fd(int fd) @@ -205,18 +204,14 @@ int ignore_sigio_fd(int fd) if(i == current_poll.used) goto out; - err = need_poll(current_poll.used - 1); + err = need_poll(&next_poll, current_poll.used - 1); if(err) goto out; for(i = 0; i < current_poll.used; i++){ p = ¤t_poll.poll[i]; - if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; - } - if(n == i){ - printk("ignore_sigio_fd : fd %d not found\n", fd); - err = -1; - goto out; + if(p->fd != fd) + next_poll.poll[n++] = *p; } update_thread(); @@ -234,7 +229,7 @@ static struct pollfd *setup_initial_poll(int fd) printk("setup_initial_poll : failed to allocate poll\n"); return NULL; } - *p = ((struct pollfd) { .fd = fd, + *p = ((struct pollfd) { .fd = fd, .events = POLLIN, .revents = 0 }); return p; @@ -323,6 +318,8 @@ out_close1: void maybe_sigio_broken(int fd, int read) { + int err; + if(!isatty(fd)) return; @@ -330,7 +327,19 @@ void maybe_sigio_broken(int fd, int read) return; write_sigio_workaround(); - add_sigio_fd(fd, read); + + sigio_lock(); + err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); + if(err){ + printk("maybe_sigio_broken - failed to add pollfd\n"); + goto out; + } + all_sigio_fds.poll[all_sigio_fds.used++] = + ((struct pollfd) { .fd = fd, + .events = read ? POLLIN : POLLOUT, + .revents = 0 }); +out: + sigio_unlock(); } static void sigio_cleanup(void) -- cgit v1.2.2 From 4b84c69b5f6c08a540e3683f1360a6cdef2806c7 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:04 -0700 Subject: [PATCH] uml: Move signal handlers to arch code Have most signals go through an arch-provided handler which recovers the sigcontext and then calls a generic handler. This replaces the ARCH_GET_SIGCONTEXT macro, which was somewhat fragile. On x86_64, recovering %rdx (which holds the sigcontext pointer) must be the first thing that happens. sig_handler duly invokes that first, but there is no guarantee that I can see that instructions won't be reordered such that %rdx is used before that. Having the arch provide the handler seems much more robust. Some signals in some parts of UML require their own handlers - these places don't call set_handler any more. They call sigaction or signal themselves. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/irq.c | 2 +- arch/um/os-Linux/main.c | 34 ++++++++++++++++++++++++++++------ arch/um/os-Linux/process.c | 12 +++++++++++- arch/um/os-Linux/signal.c | 31 +++++++++++++------------------ arch/um/os-Linux/skas/process.c | 17 ++++++++++++++--- arch/um/os-Linux/sys-i386/Makefile | 2 +- arch/um/os-Linux/sys-i386/signal.c | 15 +++++++++++++++ arch/um/os-Linux/sys-x86_64/Makefile | 2 +- arch/um/os-Linux/sys-x86_64/signal.c | 16 ++++++++++++++++ arch/um/os-Linux/time.c | 4 ++-- 10 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 arch/um/os-Linux/sys-i386/signal.c create mode 100644 arch/um/os-Linux/sys-x86_64/signal.c (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index 7555bf9c33d9..a97206df5b52 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -132,7 +132,7 @@ void os_set_pollfd(int i, int fd) void os_set_ioignore(void) { - set_handler(SIGIO, SIG_IGN, 0, -1); + signal(SIGIO, SIG_IGN); } void init_irq_signals(int on_sigstack) diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 90912aaca7aa..d1c5670787dc 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -67,13 +67,32 @@ static __init void do_uml_initcalls(void) static void last_ditch_exit(int sig) { - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); uml_cleanup(); exit(1); } +static void install_fatal_handler(int sig) +{ + struct sigaction action; + + /* All signals are enabled in this handler ... */ + sigemptyset(&action.sa_mask); + + /* ... including the signal being handled, plus we want the + * handler reset to the default behavior, so that if an exit + * handler is hanging for some reason, the UML will just die + * after this signal is sent a second time. + */ + action.sa_flags = SA_RESETHAND | SA_NODEFER; + action.sa_restorer = NULL; + action.sa_handler = last_ditch_exit; + if(sigaction(sig, &action, NULL) < 0){ + printf("failed to install handler for signal %d - errno = %d\n", + errno); + exit(1); + } +} + #define UML_LIB_PATH ":/usr/lib/uml" static void setup_env_path(void) @@ -158,9 +177,12 @@ int main(int argc, char **argv, char **envp) } new_argv[argc] = NULL; - set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + /* Allow these signals to bring down a UML if all other + * methods of control fail. + */ + install_fatal_handler(SIGINT); + install_fatal_handler(SIGTERM); + install_fatal_handler(SIGHUP); scan_elf_aux( envp); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 3afde92ad2c0..ff203625a4bd 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -246,7 +246,17 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) set_sigstack(sig_stack, pages * page_size()); flags = SA_ONSTACK; } - if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); + if(usr1_handler){ + struct sigaction sa; + + sa.sa_handler = usr1_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = flags; + sa.sa_restorer = NULL; + if(sigaction(SIGUSR1, &sa, NULL) < 0) + panic("init_new_thread_stack - sigaction failed - " + "errno = %d\n", errno); + } } void init_new_thread_signals(void) diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 60e4faedf254..55b62e2b8f41 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -15,7 +15,6 @@ #include "user.h" #include "signal_kern.h" #include "sysdep/sigcontext.h" -#include "sysdep/signal.h" #include "sigcontext.h" #include "mode.h" #include "os.h" @@ -38,18 +37,10 @@ static int signals_enabled = 1; static int pending = 0; -void sig_handler(ARCH_SIGHDLR_PARAM) +void sig_handler(int sig, struct sigcontext *sc) { - struct sigcontext *sc; int enabled; - /* Must be the first thing that this handler does - x86_64 stores - * the sigcontext in %rdx, and we need to save it before it has a - * chance to get trashed. - */ - - ARCH_GET_SIGCONTEXT(sc, sig); - enabled = signals_enabled; if(!enabled && (sig == SIGIO)){ pending |= SIGIO_MASK; @@ -84,13 +75,10 @@ static void real_alarm_handler(int sig, struct sigcontext *sc) } -void alarm_handler(ARCH_SIGHDLR_PARAM) +void alarm_handler(int sig, struct sigcontext *sc) { - struct sigcontext *sc; int enabled; - ARCH_GET_SIGCONTEXT(sc, sig); - enabled = signals_enabled; if(!signals_enabled){ if(sig == SIGVTALRM) @@ -126,6 +114,10 @@ void remove_sigstack(void) panic("disabling signal stack failed, errno = %d\n", errno); } +void (*handlers[_NSIG])(int sig, struct sigcontext *sc); + +extern void hard_handler(int sig); + void set_handler(int sig, void (*handler)(int), int flags, ...) { struct sigaction action; @@ -133,13 +125,16 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) sigset_t sig_mask; int mask; - va_start(ap, flags); - action.sa_handler = handler; + handlers[sig] = (void (*)(int, struct sigcontext *)) handler; + action.sa_handler = hard_handler; + sigemptyset(&action.sa_mask); - while((mask = va_arg(ap, int)) != -1){ + + va_start(ap, flags); + while((mask = va_arg(ap, int)) != -1) sigaddset(&action.sa_mask, mask); - } va_end(ap); + action.sa_flags = flags; action.sa_restorer = NULL; if(sigaction(sig, &action, NULL) < 0) diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 50418a5e7134..88ff0de95cd3 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -189,14 +189,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()); diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile index b3213613c41c..37806621b25d 100644 --- a/arch/um/os-Linux/sys-i386/Makefile +++ b/arch/um/os-Linux/sys-i386/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o tls.o +obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c new file mode 100644 index 000000000000..0d3eae518352 --- /dev/null +++ b/arch/um/os-Linux/sys-i386/signal.c @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include + +extern void (*handlers[])(int sig, struct sigcontext *sc); + +void hard_handler(int sig) +{ + struct sigcontext *sc = (struct sigcontext *) (&sig + 1); + + (*handlers[sig])(sig, sc); +} diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile index 340ef26f5944..f67842a7735b 100644 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ b/arch/um/os-Linux/sys-x86_64/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o +obj-$(CONFIG_MODE_SKAS) = registers.o signal.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c new file mode 100644 index 000000000000..3f369e5f976b --- /dev/null +++ b/arch/um/os-Linux/sys-x86_64/signal.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include + +extern void (*handlers[])(int sig, struct sigcontext *sc); + +void hard_handler(int sig) +{ + struct ucontext *uc; + asm("movq %%rdx, %0" : "=r" (uc)); + + (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext); +} diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 4ae73c0e5485..7f5ebbadca63 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -40,8 +40,8 @@ void disable_timer(void) printk("disnable_timer - setitimer failed, errno = %d\n", errno); /* If there are signals already queued, after unblocking ignore them */ - set_handler(SIGALRM, SIG_IGN, 0, -1); - set_handler(SIGVTALRM, SIG_IGN, 0, -1); + signal(SIGALRM, SIG_IGN); + signal(SIGVTALRM, SIG_IGN); } void switch_timers(int to_real) -- cgit v1.2.2 From 537ae946e808d0f22d660f7a3500832fe0c07d14 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:05 -0700 Subject: [PATCH] uml: timer cleanups set_interval returns an error instead of panicing if setitimer fails. Some of its callers now check the return. enable_timer is largely tt-mode-specific, so it is marked as such, and the only skas-mode caller is made to call set-interval instead. user_time_init was a no-value-added wrapper around set_interval, so it is gone. Since set_interval is now called from kernel code, callers no longer pass ITIMER_* to it. Instead, they pass a flag which is converted into ITIMER_REAL or ITIMER_VIRTUAL. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/skas/process.c | 6 +++++- arch/um/os-Linux/time.c | 18 +++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 88ff0de95cd3..42e3d1ed802c 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -155,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(); - enable_timer(); + 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 diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 7f5ebbadca63..38be096e750f 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -17,20 +17,25 @@ #include "kern_constants.h" #include "os.h" -static void set_interval(int timer_type) +int set_interval(int is_virtual) { int usec = 1000000/hz(); + int timer_type = is_virtual ? ITIMER_VIRTUAL : ITIMER_REAL; struct itimerval interval = ((struct itimerval) { { 0, usec }, { 0, usec } }); if(setitimer(timer_type, &interval, NULL) == -1) - panic("setitimer failed - errno = %d\n", errno); + return -errno; + + return 0; } +#ifdef CONFIG_MODE_TT void enable_timer(void) { - set_interval(ITIMER_VIRTUAL); + set_interval(1); } +#endif void disable_timer(void) { @@ -74,7 +79,7 @@ void uml_idle_timer(void) set_handler(SIGALRM, (__sighandler_t) alarm_handler, SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_interval(ITIMER_REAL); + set_interval(0); } #endif @@ -94,8 +99,3 @@ void idle_sleep(int secs) ts.tv_nsec = 0; nanosleep(&ts, NULL); } - -void user_time_init(void) -{ - set_interval(ITIMER_VIRTUAL); -} -- cgit v1.2.2 From 602cc2418177a5b80f533f569e5a42c4495988c9 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:06 -0700 Subject: [PATCH] uml: Remove unused variable timer_irq_inited was useless, so it is removed. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/signal.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 55b62e2b8f41..6b81739279d1 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -55,15 +55,8 @@ void sig_handler(int sig, struct sigcontext *sc) set_signals(enabled); } -extern int timer_irq_inited; - static void real_alarm_handler(int sig, struct sigcontext *sc) { - if(!timer_irq_inited){ - signals_enabled = 1; - return; - } - if(sig == SIGALRM) switch_timers(0); -- cgit v1.2.2 From 75e29b18d9a46bf3193278e92dc95609a8cca2ab Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Mon, 25 Sep 2006 23:33:08 -0700 Subject: [PATCH] uml: stack usage reduction The KSTK_* macros used an inordinate amount of stack. In order to overcome an impedance mismatch between their interface, which just returns a single register value, and the interface of get_thread_regs, which took a full pt_regs, the implementation created an on-stack pt_regs, filled it in, and returned one field. do_task_stat calls KSTK_* twice, resulting in two local pt_regs, blowing out the stack. This patch changes the interface (and name) of get_thread_regs to just return a single register from a jmp_buf. The include of archsetjmp.h" in registers.h to get the definition of jmp_buf exposed a bogus include of in start_up.c. shouldn't be used anywhere any more since UML uses the klibc setjmp/longjmp. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/start_up.c | 1 - arch/um/os-Linux/sys-i386/registers.c | 15 +++++++++------ arch/um/os-Linux/sys-x86_64/registers.c | 15 +++++++++------ 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'arch/um/os-Linux') diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 503148504009..7fe92680c7dd 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 1f90a2d71386..7cd0369e02b3 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -130,11 +130,14 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) HOST_FP_SIZE * sizeof(unsigned long)); } -void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) +unsigned long get_thread_reg(int reg, jmp_buf *buf) { - struct __jmp_buf *jmpbuf = buffer; - - UPT_SET(uml_regs, EIP, jmpbuf->__eip); - UPT_SET(uml_regs, UESP, jmpbuf->__esp); - UPT_SET(uml_regs, EBP, jmpbuf->__ebp); + switch(reg){ + case EIP: return buf[0]->__eip; + case UESP: return buf[0]->__esp; + case EBP: return buf[0]->__ebp; + default: + printk("get_thread_regs - unknown register %d\n", reg); + return 0; + } } diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c index e730447d6c02..cb8e8a263280 100644 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ b/arch/um/os-Linux/sys-x86_64/registers.c @@ -78,11 +78,14 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) HOST_FP_SIZE * sizeof(unsigned long)); } -void get_thread_regs(union uml_pt_regs *uml_regs, void *buffer) +unsigned long get_thread_reg(int reg, jmp_buf *buf) { - struct __jmp_buf *jmpbuf = buffer; - - UPT_SET(uml_regs, RIP, jmpbuf->__rip); - UPT_SET(uml_regs, RSP, jmpbuf->__rsp); - UPT_SET(uml_regs, RBP, jmpbuf->__rbp); + switch(reg){ + case RIP: return buf[0]->__rip; + case RSP: return buf[0]->__rsp; + case RBP: return buf[0]->__rbp; + default: + printk("get_thread_regs - unknown register %d\n", reg); + return 0; + } } -- cgit v1.2.2