diff options
Diffstat (limited to 'arch/um/os-Linux')
42 files changed, 586 insertions, 1145 deletions
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 8a48d6a3006..08ff5094fcd 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,18 +3,15 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ - registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ - umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ +obj-y = aio.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ + registers.o sigio.o signal.o start_up.o time.o tty.o \ + umid.o user_syms.o util.o drivers/ skas/ -obj-$(CONFIG_TTY_LOG) += tty_log.o -user-objs-$(CONFIG_TTY_LOG) += tty_log.o +obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ - tty.o tls.o uaccess.o umid.o util.o - -CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) + tty.o umid.o util.o HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ echo -DHAVE_AIO_ABI ) diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index 57e3d46c989..014eb35fd13 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -9,12 +9,10 @@ #include <errno.h> #include <sys/time.h> #include <asm/unistd.h> -#include "aio.h" -#include "init.h" -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "user.h" +#include <aio.h> +#include <init.h> +#include <kern_util.h> +#include <os.h> struct aio_thread_req { enum aio_type type; @@ -106,8 +104,7 @@ static int aio_thread(void *arg) struct io_event event; int err, n, reply_fd; - signal(SIGWINCH, SIG_IGN); - + os_fix_helper_signals(); while (1) { n = io_getevents(ctx, 1, 1, &event, NULL); if (n < 0) { @@ -175,7 +172,7 @@ static int not_aio_thread(void *arg) struct aio_thread_reply reply; int err; - signal(SIGWINCH, SIG_IGN); + os_fix_helper_signals(); while (1) { err = read(aio_req_fd_r, &req, sizeof(req)); if (err != sizeof(req)) { diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h index ddffd41c3f3..54183a679fd 100644 --- a/arch/um/os-Linux/drivers/etap.h +++ b/arch/um/os-Linux/drivers/etap.h @@ -6,7 +6,7 @@ #ifndef __DRIVERS_ETAP_H #define __DRIVERS_ETAP_H -#include "net_user.h" +#include <net_user.h> struct ethertap_data { char *dev_name; diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 046a131f610..f424600a583 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -9,7 +9,7 @@ #include <linux/init.h> #include <linux/netdevice.h> #include "etap.h" -#include "net_kern.h" +#include <net_kern.h> struct ethertap_init { char *dev_name; @@ -22,7 +22,7 @@ static void etap_init(struct net_device *dev, void *data) struct ethertap_data *epri; struct ethertap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); epri = (struct ethertap_data *) pri->user; epri->dev_name = init->dev_name; epri->gate_addr = init->gate_addr; diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 6fb0b174f53..b39b6696ac5 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -13,11 +13,9 @@ #include <sys/socket.h> #include <sys/wait.h> #include "etap.h" -#include "kern_constants.h" -#include "os.h" -#include "net_user.h" -#include "um_malloc.h" -#include "user.h" +#include <os.h> +#include <net_user.h> +#include <um_malloc.h> #define MAX_PACKET ETH_MAX_PACKET @@ -52,7 +50,7 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, return; } - output = kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); + output = uml_kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); if (output == NULL) printk(UM_KERN_ERR "etap_change : Failed to allocate output " "buffer\n"); @@ -165,7 +163,7 @@ static int etap_open(void *data) err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], control_fds[1], data_fds[0], data_fds[1]); output_len = UM_KERN_PAGE_SIZE; - output = kmalloc(output_len, UM_GFP_KERNEL); + output = uml_kmalloc(output_len, UM_GFP_KERNEL); read_output(control_fds[0], output, output_len); if (output == NULL) diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h index f17c31586c8..7367354ac8d 100644 --- a/arch/um/os-Linux/drivers/tuntap.h +++ b/arch/um/os-Linux/drivers/tuntap.h @@ -6,7 +6,7 @@ #ifndef __UM_TUNTAP_H #define __UM_TUNTAP_H -#include "net_user.h" +#include <net_user.h> struct tuntap_data { char *dev_name; diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 6b9e33d5de2..d9d56e5810f 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -7,7 +7,7 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <asm/errno.h> -#include "net_kern.h" +#include <net_kern.h> #include "tuntap.h" struct tuntap_init { @@ -21,7 +21,7 @@ static void tuntap_init(struct net_device *dev, void *data) struct tuntap_data *tpri; struct tuntap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); tpri = (struct tuntap_data *) pri->user; tpri->dev_name = init->dev_name; tpri->fixed_config = (init->dev_name != NULL); diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 2448be03fd7..14126d9176a 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -13,11 +13,9 @@ #include <sys/socket.h> #include <sys/wait.h> #include <sys/uio.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> #include "tuntap.h" -#include "user.h" static int tuntap_user_init(void *data, void *dev) { diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 608784d4ec5..1a365ddc4d0 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -9,21 +9,15 @@ */ #include <elf.h> #include <stddef.h> -#include "init.h" -#include "elf_user.h" -#include "mem_user.h" -#include <kern_constants.h> +#include <init.h> +#include <elf_user.h> +#include <mem_user.h> -/* Use the one from the kernel - the host may miss it, if having old headers. */ -#if UM_ELF_CLASS == UM_ELFCLASS32 typedef Elf32_auxv_t elf_auxv_t; -#else -typedef Elf64_auxv_t elf_auxv_t; -#endif /* These are initialized very early in boot and never changed */ char * elf_aux_platform; -long elf_aux_hwcap; +extern long elf_aux_hwcap; unsigned long vsyscall_ehdr; unsigned long vsyscall_end; unsigned long __kernel_vsyscall; diff --git a/arch/um/os-Linux/execvp.c b/arch/um/os-Linux/execvp.c index 66e583a4031..8fb25ca07c4 100644 --- a/arch/um/os-Linux/execvp.c +++ b/arch/um/os-Linux/execvp.c @@ -27,12 +27,12 @@ #include <limits.h> #ifndef TEST -#include "um_malloc.h" +#include <um_malloc.h> #else #include <stdio.h> #define um_kmalloc malloc #endif -#include "os.h" +#include <os.h> /* Execute FILE, searching in the `PATH' environment variable if it contains no slashes, with arguments ARGV and environment from `environ'. */ diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index b5afcfd0f86..08d90fba952 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -13,9 +13,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/un.h> -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <os.h> static void copy_stat(struct uml_stat *dst, const struct stat64 *src) { @@ -239,6 +237,12 @@ void os_close_file(int fd) { close(fd); } +int os_fsync_file(int fd) +{ + if (fsync(fd) < 0) + return -errno; + return 0; +} int os_seek_file(int fd, unsigned long long offset) { @@ -268,6 +272,15 @@ int os_write_file(int fd, const void *buf, int len) return n; } +int os_sync_file(int fd) +{ + int n = fsync(fd); + + if (n < 0) + return -errno; + return n; +} + int os_file_size(const char *file, unsigned long long *size_out) { struct uml_stat buf; @@ -561,3 +574,18 @@ int os_lock_file(int fd, int excl) out: return err; } + +unsigned os_major(unsigned long long dev) +{ + return major(dev); +} + +unsigned os_minor(unsigned long long dev) +{ + return minor(dev); +} + +unsigned long long os_makedev(unsigned major, unsigned minor) +{ + return makedev(major, minor); +} diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index f4bd349d441..e3ee4a51ef6 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -7,13 +7,12 @@ #include <unistd.h> #include <errno.h> #include <sched.h> +#include <linux/limits.h> #include <sys/socket.h> #include <sys/wait.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "um_malloc.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> struct helper_data { void (*pre_exec)(void*); @@ -27,14 +26,14 @@ static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; - int err; + int err, ret; if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); err = execvp_noalloc(data->buf, argv[0], argv); /* If the exec succeeds, we don't get here */ - write(data->fd, &err, sizeof(err)); + CATCH_EINTR(ret = write(data->fd, &err, sizeof(err))); return 0; } @@ -70,8 +69,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; - data.buf = __cant_sleep() ? kmalloc(PATH_MAX, UM_GFP_ATOMIC) : - kmalloc(PATH_MAX, UM_GFP_KERNEL); + data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); pid = clone(helper_child, (void *) sp, CLONE_VM, &data); if (pid < 0) { ret = -errno; diff --git a/arch/um/os-Linux/include/file.h b/arch/um/os-Linux/include/file.h deleted file mode 100644 index fe71be24bd5..00000000000 --- a/arch/um/os-Linux/include/file.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#ifndef __OS_FILE_H__ -#define __OS_FILE_H__ - -#define DEV_NULL "/dev/null" - -#endif diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h new file mode 100644 index 00000000000..0dc2c9f135f --- /dev/null +++ b/arch/um/os-Linux/internal.h @@ -0,0 +1 @@ +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc); diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index 0348b975e81..b9afb74b79a 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -8,12 +8,9 @@ #include <poll.h> #include <signal.h> #include <string.h> -#include "irq_user.h" -#include "kern_constants.h" -#include "os.h" -#include "process.h" -#include "um_malloc.h" -#include "user.h" +#include <irq_user.h> +#include <os.h> +#include <um_malloc.h> /* * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index abb9b0ffd96..df9191acd92 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -10,17 +10,18 @@ #include <signal.h> #include <string.h> #include <sys/resource.h> -#include "as-layout.h" -#include "init.h" -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "um_malloc.h" +#include <as-layout.h> +#include <init.h> +#include <kern_util.h> +#include <os.h> +#include <um_malloc.h> #define PGD_BOUND (4 * 1024 * 1024) #define STACKSIZE (8 * 1024 * 1024) #define THREAD_NAME_LEN (256) +long elf_aux_hwcap; + static void set_stklim(void) { struct rlimit lim; @@ -78,7 +79,7 @@ static void install_fatal_handler(int sig) } } -#define UML_LIB_PATH ":/usr/lib/uml" +#define UML_LIB_PATH ":" OS_LIB_PATH "/uml" static void setup_env_path(void) { @@ -122,6 +123,8 @@ int __init main(int argc, char **argv, char **envp) setup_env_path(); + setsid(); + new_argv = malloc((argc + 1) * sizeof(char *)); if (new_argv == NULL) { perror("Mallocing argv"); @@ -142,11 +145,13 @@ int __init main(int argc, char **argv, char **envp) */ install_fatal_handler(SIGINT); install_fatal_handler(SIGTERM); - install_fatal_handler(SIGHUP); +#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA scan_elf_aux(envp); +#endif do_uml_initcalls(); + change_sig(SIGPIPE, 0); ret = linux_main(argc, argv); /* @@ -199,7 +204,7 @@ void *__wrap_malloc(int size) return __real_malloc(size); else if (size <= UM_KERN_PAGE_SIZE) /* finding contiguous pages can be hard*/ - ret = kmalloc(size, UM_GFP_KERNEL); + ret = uml_kmalloc(size, UM_GFP_KERNEL); else ret = vmalloc(size); /* diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 93a11d7edfa..897e9ad0c10 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -10,206 +10,135 @@ #include <errno.h> #include <fcntl.h> #include <string.h> +#include <sys/stat.h> #include <sys/mman.h> -#include <sys/param.h> -#include "init.h" -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <sys/vfs.h> +#include <linux/magic.h> +#include <init.h> +#include <os.h> -/* Modified by which_tmpdir, which is called during early boot */ -static char *default_tmpdir = "/tmp"; - -/* - * Modified when creating the physical memory file and when checking - * the tmp filesystem for usability, both happening during early boot. - */ +/* Set by make_tempfile() during early boot. */ static char *tempdir = NULL; -static void __init find_tempdir(void) +/* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */ +static int __init check_tmpfs(const char *dir) { - const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; - int i; - char *dir = NULL; - - if (tempdir != NULL) - /* We've already been called */ - return; - for (i = 0; dirs[i]; i++) { - dir = getenv(dirs[i]); - if ((dir != NULL) && (*dir != '\0')) - break; + struct statfs st; + + printf("Checking if %s is on tmpfs...", dir); + if (statfs(dir, &st) < 0) { + printf("%s\n", strerror(errno)); + } else if (st.f_type != TMPFS_MAGIC) { + printf("no\n"); + } else { + printf("OK\n"); + return 0; } - if ((dir == NULL) || (*dir == '\0')) - dir = default_tmpdir; - - tempdir = malloc(strlen(dir) + 2); - if (tempdir == NULL) { - fprintf(stderr, "Failed to malloc tempdir, " - "errno = %d\n", errno); - return; - } - strcpy(tempdir, dir); - strcat(tempdir, "/"); + return -1; } /* - * This will return 1, with the first character in buf being the - * character following the next instance of c in the file. This will - * read the file as needed. If there's an error, -errno is returned; - * if the end of the file is reached, 0 is returned. + * Choose the tempdir to use. We want something on tmpfs so that our memory is + * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the + * environment, we use that even if it's not on tmpfs, but we warn the user. + * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found + * then we fall back to /tmp. */ -static int next(int fd, char *buf, size_t size, char c) +static char * __init choose_tempdir(void) { - ssize_t n; - size_t len; - char *ptr; - - while ((ptr = strchr(buf, c)) == NULL) { - n = read(fd, buf, size - 1); - if (n == 0) - return 0; - else if (n < 0) - return -errno; - - buf[n] = '\0'; + static const char * const vars[] = { + "TMPDIR", + "TMP", + "TEMP", + NULL + }; + static const char fallback_dir[] = "/tmp"; + static const char * const tmpfs_dirs[] = { + "/dev/shm", + fallback_dir, + NULL + }; + int i; + const char *dir; + + printf("Checking environment variables for a tempdir..."); + for (i = 0; vars[i]; i++) { + dir = getenv(vars[i]); + if ((dir != NULL) && (*dir != '\0')) { + printf("%s\n", dir); + if (check_tmpfs(dir) >= 0) + goto done; + else + goto warn; + } } + printf("none found\n"); - ptr++; - len = strlen(ptr); - memmove(buf, ptr, len + 1); - - /* - * Refill the buffer so that if there's a partial string that we care - * about, it will be completed, and we can recognize it. - */ - n = read(fd, &buf[len], size - len - 1); - if (n < 0) - return -errno; + for (i = 0; tmpfs_dirs[i]; i++) { + dir = tmpfs_dirs[i]; + if (check_tmpfs(dir) >= 0) + goto done; + } - buf[len + n] = '\0'; - return 1; + dir = fallback_dir; +warn: + printf("Warning: tempdir %s is not on tmpfs\n", dir); +done: + /* Make a copy since getenv results may not remain valid forever. */ + return strdup(dir); } -/* which_tmpdir is called only during early boot */ -static int checked_tmpdir = 0; - /* - * Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner - * way to do this than to parse /proc/mounts. statfs will return the - * same filesystem magic number and fs id for both /dev and /dev/shm - * when they are both tmpfs, so you can't tell if they are different - * filesystems. Also, there seems to be no other way of finding the - * mount point of a filesystem from within it. - * - * If a /dev/shm tmpfs entry is found, then we switch to using it. - * Otherwise, we stay with the default /tmp. + * Create an unlinked tempfile in a suitable tempdir. template must be the + * basename part of the template with a leading '/'. */ -static void which_tmpdir(void) -{ - int fd, found; - char buf[128] = { '\0' }; - - if (checked_tmpdir) - return; - - checked_tmpdir = 1; - - printf("Checking for tmpfs mount on /dev/shm..."); - - fd = open("/proc/mounts", O_RDONLY); - if (fd < 0) { - printf("failed to open /proc/mounts, errno = %d\n", errno); - return; - } - - while (1) { - 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, ARRAY_SIZE(buf), '\n'); - if (found != 1) - break; - } - -err: - if (found == 0) - printf("nothing mounted on /dev/shm\n"); - else if (found < 0) - printf("read returned errno %d\n", -found); - -out: - close(fd); - - return; - -found: - found = next(fd, buf, ARRAY_SIZE(buf), ' '); - if (found != 1) - goto err; - - if (strncmp(buf, "tmpfs", strlen("tmpfs"))) { - printf("not tmpfs\n"); - goto out; - } - - printf("OK\n"); - default_tmpdir = "/dev/shm"; - goto out; -} - -static int __init make_tempfile(const char *template, char **out_tempname, - int do_unlink) +static int __init make_tempfile(const char *template) { char *tempname; int fd; - which_tmpdir(); - tempname = malloc(MAXPATHLEN); - if (tempname == NULL) - return -1; + if (tempdir == NULL) { + tempdir = choose_tempdir(); + if (tempdir == NULL) { + fprintf(stderr, "Failed to choose tempdir: %s\n", + strerror(errno)); + return -1; + } + } - find_tempdir(); - if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN)) + tempname = malloc(strlen(tempdir) + strlen(template) + 1); + if (tempname == NULL) return -1; - if (template[0] != '/') - strcpy(tempname, tempdir); - else - tempname[0] = '\0'; - strncat(tempname, template, MAXPATHLEN-1-strlen(tempname)); + strcpy(tempname, tempdir); + strcat(tempname, template); fd = mkstemp(tempname); if (fd < 0) { fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); goto out; } - if (do_unlink && (unlink(tempname) < 0)) { + if (unlink(tempname) < 0) { perror("unlink"); - goto out; + goto close; } - if (out_tempname) { - *out_tempname = tempname; - } else - free(tempname); + free(tempname); return fd; +close: + close(fd); out: free(tempname); return -1; } -#define TEMPNAME_TEMPLATE "vm_file-XXXXXX" +#define TEMPNAME_TEMPLATE "/vm_file-XXXXXX" static int __init create_tmp_file(unsigned long long len) { int fd, err; char zero; - fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); + fd = make_tempfile(TEMPNAME_TEMPLATE); if (fd < 0) exit(1); @@ -253,7 +182,6 @@ int __init create_mem_file(unsigned long long len) return fd; } - void __init check_tmpexec(void) { void *addr; @@ -261,14 +189,13 @@ void __init check_tmpexec(void) addr = mmap(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); - printf("Checking PROT_EXEC mmap in %s...",tempdir); - fflush(stdout); + printf("Checking PROT_EXEC mmap in %s...", tempdir); if (addr == MAP_FAILED) { err = errno; - perror("failed"); + printf("%s\n", strerror(err)); close(fd); if (err == EPERM) - printf("%s must be not mounted noexec\n",tempdir); + printf("%s must be not mounted noexec\n", tempdir); exit(1); } printf("OK\n"); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index e0477c3ee89..33496fe2bb5 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -4,6 +4,7 @@ */ #include <stdio.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> @@ -12,13 +13,10 @@ #include <sys/ptrace.h> #include <sys/wait.h> #include <asm/unistd.h> -#include "init.h" -#include "kern_constants.h" -#include "longjmp.h" -#include "os.h" -#include "process.h" -#include "skas_ptrace.h" -#include "user.h" +#include <init.h> +#include <longjmp.h> +#include <os.h> +#include <skas_ptrace.h> #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -235,35 +233,65 @@ out: return ok; } -void init_new_thread_signals(void) +static int os_page_mincore(void *addr) { - set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGTRAP, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGFPE, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGILL, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - set_handler(SIGBUS, (__sighandler_t) sig_handler, SA_ONSTACK, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - signal(SIGHUP, SIG_IGN); + char vec[2]; + int ret; - set_handler(SIGIO, (__sighandler_t) sig_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, - SIGVTALRM, -1); - signal(SIGWINCH, SIG_IGN); + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + return 0; + else + return -errno; + } + + return vec[0] & 1; } -int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) +int os_mincore(void *addr, unsigned long len) { - jmp_buf buf; - int n; - - *jmp_ptr = &buf; - n = UML_SETJMP(&buf); - if (n != 0) - return n; - (*fn)(arg); - return 0; + char *vec; + int ret, i; + + if (len <= UM_KERN_PAGE_SIZE) + return os_page_mincore(addr); + + vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); + if (!vec) + return -ENOMEM; + + ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); + if (ret < 0) { + if (errno == ENOMEM || errno == EINVAL) + ret = 0; + else + ret = -errno; + + goto out; + } + + for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) { + if (!(vec[i] & 1)) { + ret = 0; + goto out; + } + } + + ret = 1; +out: + free(vec); + return ret; +} + +void init_new_thread_signals(void) +{ + set_handler(SIGSEGV); + set_handler(SIGTRAP); + set_handler(SIGFPE); + set_handler(SIGILL); + set_handler(SIGBUS); + signal(SIGHUP, SIG_IGN); + set_handler(SIGIO); + signal(SIGWINCH, SIG_IGN); } diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index 830fe6a1518..2ff8d4fe83c 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c @@ -7,7 +7,9 @@ #include <errno.h> #include <string.h> #include <sys/ptrace.h> -#include "sysdep/ptrace.h" +#include <sysdep/ptrace.h> +#include <sysdep/ptrace_user.h> +#include <registers.h> int save_registers(int pid, struct uml_pt_regs *regs) { @@ -32,6 +34,7 @@ int restore_registers(int pid, struct uml_pt_regs *regs) /* This is set once at boot time and not changed thereafter */ static unsigned long exec_regs[MAX_REG_NR]; +static unsigned long exec_fp_regs[FP_SIZE]; int init_registers(int pid) { @@ -42,10 +45,14 @@ int init_registers(int pid) return -errno; arch_init_registers(pid); + get_fp_registers(pid, exec_fp_regs); return 0; } -void get_safe_registers(unsigned long *regs) +void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) { memcpy(regs, exec_regs, sizeof(exec_regs)); + + if (fp_regs) + memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); } diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index abf47a7c4ab..46e762f926e 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -11,13 +11,11 @@ #include <sched.h> #include <signal.h> #include <string.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "init.h" -#include "os.h" -#include "sigio.h" -#include "um_malloc.h" -#include "user.h" +#include <kern_util.h> +#include <init.h> +#include <os.h> +#include <sigio.h> +#include <um_malloc.h> /* * Protected by sigio_lock(), also used by sigio_cleanup, which is an @@ -57,7 +55,7 @@ static int write_sigio_thread(void *unused) int i, n, respond_fd; char c; - signal(SIGWINCH, SIG_IGN); + os_fix_helper_signals(); fds = ¤t_poll; while (1) { n = poll(fds->poll, fds->used, -1); @@ -109,7 +107,7 @@ static int need_poll(struct pollfds *polls, int n) if (n <= polls->size) return 0; - new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); + new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); if (new == NULL) { printk(UM_KERN_ERR "need_poll : failed to allocate new " "pollfds\n"); @@ -243,7 +241,7 @@ static struct pollfd *setup_initial_poll(int fd) { struct pollfd *p; - p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); + p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); if (p == NULL) { printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " "poll\n"); @@ -338,20 +336,10 @@ out_close1: close(l_write_sigio_fds[1]); } -/* Changed during early boot */ -static int pty_output_sigio = 0; -static int pty_close_sigio = 0; - -void maybe_sigio_broken(int fd, int read) +void sigio_broken(int fd, int read) { int err; - if (!isatty(fd)) - return; - - if ((read || pty_output_sigio) && (!read || pty_close_sigio)) - return; - write_sigio_workaround(); sigio_lock(); @@ -370,6 +358,21 @@ out: sigio_unlock(); } +/* Changed during early boot */ +static int pty_output_sigio; +static int pty_close_sigio; + +void maybe_sigio_broken(int fd, int read) +{ + if (!isatty(fd)) + return; + + if ((read || pty_output_sigio) && (!read || pty_close_sigio)) + return; + + sigio_broken(fd, read); +} + static void sigio_cleanup(void) { if (write_sigio_pid == -1) @@ -383,7 +386,7 @@ static void sigio_cleanup(void) __uml_exitcall(sigio_cleanup); /* Used as a flag during SIGIO testing early in boot */ -static volatile int got_sigio = 0; +static int got_sigio; static void __init handler(int sig) { @@ -498,7 +501,8 @@ static void tty_output(int master, int slave) if (errno != EAGAIN) printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", errno); - while (((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) + while (((n = read(slave, buf, sizeof(buf))) > 0) && + !({ barrier(); got_sigio; })) ; if (got_sigio) { @@ -523,7 +527,7 @@ static void tty_close(int master, int slave) printk(UM_KERN_CONT "No, enabling workaround\n"); } -void __init check_sigio(void) +static void __init check_sigio(void) { if ((access("/dev/ptmx", R_OK) < 0) && (access("/dev/ptyp0", R_OK) < 0)) { diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 3f1694b134c..7b605e4dfff 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -9,17 +9,13 @@ #include <errno.h> #include <signal.h> #include <strings.h> -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "sysdep/barrier.h" -#include "sysdep/sigcontext.h" -#include "user.h" +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <sysdep/mcontext.h> +#include "internal.h" -/* Copied from linux/compiler-gcc.h since we can't include it directly */ -#define barrier() __asm__ __volatile__("": : :"memory") - -void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { +void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, [SIGFPE] = relay_signal, [SIGILL] = relay_signal, @@ -29,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { [SIGIO] = sigio_handler, [SIGVTALRM] = timer_handler }; -static void sig_handler_common(int sig, struct sigcontext *sc) +static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { struct uml_pt_regs r; int save_errno = errno; @@ -37,15 +33,15 @@ static void sig_handler_common(int sig, struct sigcontext *sc) r.is_user = 0; if (sig == SIGSEGV) { /* For segfaults, we want the data from the sigcontext. */ - copy_sc(&r, sc); - GET_FAULTINFO_FROM_SC(r.faultinfo, sc); + get_regs_from_mc(&r, mc); + GET_FAULTINFO_FROM_MC(r.faultinfo, mc); } /* enable signals if sig isn't IRQ signal */ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) unblock_signals(); - (*sig_info[sig])(sig, &r); + (*sig_info[sig])(sig, si, &r); errno = save_errno; } @@ -65,7 +61,7 @@ static void sig_handler_common(int sig, struct sigcontext *sc) static int signals_enabled; static unsigned int signals_pending; -void sig_handler(int sig, struct sigcontext *sc) +void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { int enabled; @@ -77,23 +73,23 @@ void sig_handler(int sig, struct sigcontext *sc) block_signals(); - sig_handler_common(sig, sc); + sig_handler_common(sig, si, mc); set_signals(enabled); } -static void real_alarm_handler(struct sigcontext *sc) +static void real_alarm_handler(mcontext_t *mc) { struct uml_pt_regs regs; - if (sc != NULL) - copy_sc(®s, sc); + if (mc != NULL) + get_regs_from_mc(®s, mc); regs.is_user = 0; unblock_signals(); - timer_handler(SIGVTALRM, ®s); + timer_handler(SIGVTALRM, NULL, ®s); } -void alarm_handler(int sig, struct sigcontext *sc) +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; @@ -105,14 +101,13 @@ void alarm_handler(int sig, struct sigcontext *sc) block_signals(); - real_alarm_handler(sc); + real_alarm_handler(mc); set_signals(enabled); } void timer_init(void) { - set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1); + set_handler(SIGVTALRM); } void set_sigstack(void *sig_stack, int size) @@ -125,10 +120,23 @@ void set_sigstack(void *sig_stack, int size) panic("enabling signal stack failed, errno = %d\n", errno); } -void (*handlers[_NSIG])(int sig, struct sigcontext *sc); +static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { + [SIGSEGV] = sig_handler, + [SIGBUS] = sig_handler, + [SIGILL] = sig_handler, + [SIGFPE] = sig_handler, + [SIGTRAP] = sig_handler, + + [SIGIO] = sig_handler, + [SIGWINCH] = sig_handler, + [SIGVTALRM] = alarm_handler +}; + -void handle_signal(int sig, struct sigcontext *sc) +static void hard_handler(int sig, siginfo_t *si, void *p) { + struct ucontext *uc = p; + mcontext_t *mc = &uc->uc_mcontext; unsigned long pending = 1UL << sig; do { @@ -154,7 +162,7 @@ void handle_signal(int sig, struct sigcontext *sc) while ((sig = ffs(pending)) != 0){ sig--; pending &= ~(1 << sig); - (*handlers[sig])(sig, sc); + (*handlers[sig])(sig, (struct siginfo *)si, mc); } /* @@ -168,28 +176,26 @@ void handle_signal(int sig, struct sigcontext *sc) } while (pending); } -extern void hard_handler(int sig); - -void set_handler(int sig, void (*handler)(int), int flags, ...) +void set_handler(int sig) { struct sigaction action; - va_list ap; + int flags = SA_SIGINFO | SA_ONSTACK; sigset_t sig_mask; - int mask; - handlers[sig] = (void (*)(int, struct sigcontext *)) handler; - action.sa_handler = hard_handler; + action.sa_sigaction = hard_handler; + /* block irq ones */ sigemptyset(&action.sa_mask); - - va_start(ap, flags); - while ((mask = va_arg(ap, int)) != -1) - sigaddset(&action.sa_mask, mask); - va_end(ap); + sigaddset(&action.sa_mask, SIGVTALRM); + sigaddset(&action.sa_mask, SIGIO); + sigaddset(&action.sa_mask, SIGWINCH); if (sig == SIGSEGV) flags |= SA_NODEFER; + if (sigismember(&action.sa_mask, sig)) + flags |= SA_RESTART; /* if it's an irq signal */ + action.sa_flags = flags; action.sa_restorer = NULL; if (sigaction(sig, &action, NULL) < 0) @@ -268,9 +274,12 @@ void unblock_signals(void) * Deal with SIGIO first because the alarm handler might * schedule, leaving the pending SIGIO stranded until we come * back here. + * + * SIGIO's handler doesn't use siginfo or mcontext, + * so they can be NULL. */ if (save_pending & SIGIO_MASK) - sig_handler_common(SIGIO, NULL); + sig_handler_common(SIGIO, NULL, NULL); if (save_pending & SIGVTALRM_MASK) real_alarm_handler(NULL); @@ -295,3 +304,11 @@ int set_signals(int enable) return ret; } + +int os_is_signal_stack(void) +{ + stack_t ss; + sigaltstack(NULL, &ss); + + return ss.ss_flags & SS_ONSTACK; +} diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index 484e68f9f7a..689b18db798 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c @@ -8,19 +8,16 @@ #include <errno.h> #include <string.h> #include <sys/mman.h> -#include "init.h" -#include "kern_constants.h" -#include "as-layout.h" -#include "mm_id.h" -#include "os.h" -#include "proc_mm.h" -#include "ptrace_user.h" -#include "registers.h" -#include "skas.h" -#include "user.h" -#include "sysdep/ptrace.h" -#include "sysdep/stub.h" -#include "uml-config.h" +#include <init.h> +#include <as-layout.h> +#include <mm_id.h> +#include <os.h> +#include <proc_mm.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <sysdep/ptrace.h> +#include <sysdep/stub.h> extern unsigned long batch_syscall_stub, __syscall_stub_start; @@ -40,7 +37,7 @@ static unsigned long syscall_regs[MAX_REG_NR]; static int __init init_syscall_regs(void) { - get_safe_registers(syscall_regs); + get_safe_registers(syscall_regs, NULL); syscall_regs[REGS_IP_INDEX] = STUB_CODE + ((unsigned long) &batch_syscall_stub - (unsigned long) &__syscall_stub_start); @@ -51,10 +48,6 @@ __initcall(init_syscall_regs); extern int proc_mm; -int single_count = 0; -int multi_count = 0; -int multi_op_count = 0; - static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) { int n, i; @@ -67,8 +60,6 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) /* FIXME: Need to look up userspace_pid by cpu */ pid = userspace_pid[0]; - multi_count++; - n = ptrace_setregs(pid, syscall_regs); if (n < 0) { printk(UM_KERN_ERR "Registers - \n"); @@ -129,9 +120,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall, { unsigned long *stack = check_init_stack(mm_idp, *addr); - if (done && *addr == NULL) - single_count++; - *stack += sizeof(long); stack += *stack / sizeof(long); @@ -144,7 +132,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall, *stack++ = args[5]; *stack++ = expected; *stack = 0; - multi_op_count++; if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 1e8cba6550a..908579f2b0a 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -9,31 +9,23 @@ #include <errno.h> #include <string.h> #include <sys/mman.h> -#include <sys/ptrace.h> #include <sys/wait.h> #include <asm/unistd.h> -#include "as-layout.h" -#include "chan_user.h" -#include "kern_constants.h" -#include "kern_util.h" -#include "mem.h" -#include "os.h" -#include "process.h" -#include "proc_mm.h" -#include "ptrace_user.h" -#include "registers.h" -#include "skas.h" -#include "skas_ptrace.h" -#include "user.h" -#include "sysdep/stub.h" +#include <as-layout.h> +#include <init.h> +#include <kern_util.h> +#include <mem.h> +#include <os.h> +#include <proc_mm.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <skas_ptrace.h> +#include <sysdep/stub.h> int is_skas_winch(int pid, int fd, void *data) { - if (pid != getpgrp()) - return 0; - - register_winch_irq(-1, fd, -1, data, 0); - return 1; + return pid == getpgrp(); } static int ptrace_dump_regs(int pid) @@ -55,7 +47,7 @@ static int ptrace_dump_regs(int pid) * Signals that are OK to receive in the stub - we'll just continue it. * SIGWINCH will happen when UML is inside a detached screen. */ -#define STUB_SIG_MASK (1 << SIGVTALRM) +#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) /* Signals that the stub will finish with - anything else is an error */ #define STUB_DONE_MASK (1 << SIGTRAP) @@ -96,7 +88,7 @@ bad_wait: extern unsigned long current_stub_stack(void); -void get_skas_faultinfo(int pid, struct faultinfo * fi) +static void get_skas_faultinfo(int pid, struct faultinfo *fi) { int err; @@ -169,7 +161,7 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, if (!local_using_sysemu) { - err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); if (err < 0) { printk(UM_KERN_ERR "handle_trap - nullifying syscall " @@ -257,8 +249,8 @@ static int userspace_tramp(void *stack) set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_ONSTACK | SA_NODEFER; - sa.sa_handler = (void *) v; + sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; + sa.sa_sigaction = (void *) v; sa.sa_restorer = NULL; if (sigaction(SIGSEGV, &sa, NULL) < 0) { printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV " @@ -354,6 +346,10 @@ void userspace(struct uml_pt_regs *regs) int err, status, op, pid = userspace_pid[0]; /* To prevent races if using_sysemu changes under us.*/ int local_using_sysemu; + siginfo_t si; + + /* Handle any immediate reschedules or signals */ + interrupt_end(); if (getitimer(ITIMER_VIRTUAL, &timer)) printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno); @@ -373,6 +369,9 @@ void userspace(struct uml_pt_regs *regs) if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) fatal_sigsegv(); + if (put_fp_registers(pid, regs->fp)) + fatal_sigsegv(); + /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); @@ -399,17 +398,27 @@ void userspace(struct uml_pt_regs *regs) fatal_sigsegv(); } + if (get_fp_registers(pid, regs->fp)) { + printk(UM_KERN_ERR "userspace - get_fp_registers failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if (WIFSTOPPED(status)) { int sig = WSTOPSIG(status); + + ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si); + switch (sig) { case SIGSEGV: if (PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) { get_skas_faultinfo(pid, ®s->faultinfo); - (*sig_info[SIGSEGV])(SIGSEGV, regs); + (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, + regs); } else handle_segv(pid, regs); break; @@ -417,14 +426,14 @@ void userspace(struct uml_pt_regs *regs) handle_trap(pid, regs, local_using_sysemu); break; case SIGTRAP: - relay_signal(SIGTRAP, regs); + relay_signal(SIGTRAP, (struct siginfo *)&si, regs); break; case SIGVTALRM: now = os_nsecs(); if (now < nsecs) break; block_signals(); - (*sig_info[sig])(sig, regs); + (*sig_info[sig])(sig, (struct siginfo *)&si, regs); unblock_signals(); nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + @@ -438,11 +447,11 @@ void userspace(struct uml_pt_regs *regs) case SIGFPE: case SIGWINCH: block_signals(); - (*sig_info[sig])(sig, regs); + (*sig_info[sig])(sig, (struct siginfo *)&si, regs); unblock_signals(); break; default: - printk(UM_KERN_ERR "userspace - child stopped " + printk(UM_KERN_ERR "userspace - child stopped " "with signal %d\n", sig); fatal_sigsegv(); } @@ -457,10 +466,11 @@ void userspace(struct uml_pt_regs *regs) } static unsigned long thread_regs[MAX_REG_NR]; +static unsigned long thread_fp_regs[FP_SIZE]; static int __init init_thread_regs(void) { - get_safe_registers(thread_regs); + get_safe_registers(thread_regs, thread_fp_regs); /* Set parent's instruction pointer to start of clone-stub */ thread_regs[REGS_IP_INDEX] = STUB_CODE + (unsigned long) stub_clone_handler - @@ -503,6 +513,13 @@ int copy_context_skas0(unsigned long new_stack, int pid) return err; } + err = put_fp_registers(pid, thread_fp_regs); + if (err < 0) { + printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers " + "failed, pid = %d, err = %d\n", pid, err); + return err; + } + /* set a well known return code for detection of child write failure */ child_data->err = 12345678; @@ -644,8 +661,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) { int n; - set_handler(SIGWINCH, (__sighandler_t) sig_handler, - SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGVTALRM, -1); + set_handler(SIGWINCH); /* * Can't use UML_SETJMP or UML_LONGJMP here because they save diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b616e15638f..337518c5042 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -13,27 +13,28 @@ #include <signal.h> #include <string.h> #include <sys/mman.h> -#include <sys/ptrace.h> #include <sys/stat.h> #include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> #include <asm/unistd.h> -#include "init.h" -#include "kern_constants.h" -#include "os.h" -#include "mem_user.h" -#include "ptrace_user.h" -#include "registers.h" -#include "skas_ptrace.h" - -static int ptrace_child(void) +#include <init.h> +#include <os.h> +#include <mem_user.h> +#include <ptrace_user.h> +#include <registers.h> +#include <skas.h> +#include <skas_ptrace.h> + +static void ptrace_child(void) { int ret; /* Calling os_getpid because some libcs cached getpid incorrectly */ int pid = os_getpid(), ppid = getppid(); int sc_result; - change_sig(SIGWINCH, 0); - if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { + if (change_sig(SIGWINCH, 0) < 0 || + ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { perror("ptrace"); kill(pid, SIGKILL); } @@ -75,9 +76,8 @@ static void fatal(char *fmt, ...) va_list list; va_start(list, fmt); - vprintf(fmt, list); + vfprintf(stderr, fmt, list); va_end(list); - fflush(stdout); exit(1); } @@ -87,9 +87,8 @@ static void non_fatal(char *fmt, ...) va_list list; va_start(list, fmt); - vprintf(fmt, list); + vfprintf(stderr, fmt, list); va_end(list); - fflush(stdout); } static int start_ptraced_child(void) @@ -122,8 +121,10 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit) { int status, n, ret = 0; - if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) - fatal_perror("stop_ptraced_child : ptrace failed"); + if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { + perror("stop_ptraced_child : ptrace failed"); + return -1; + } CATCH_EINTR(n = waitpid(pid, &status, 0)); if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); @@ -142,14 +143,27 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit) } /* Changed only during early boot */ -int ptrace_faultinfo = 1; -int ptrace_ldt = 1; -int proc_mm = 1; -int skas_needs_stub = 0; +int ptrace_faultinfo; +static int disable_ptrace_faultinfo; + +int ptrace_ldt; +static int disable_ptrace_ldt; + +int proc_mm; +static int disable_proc_mm; + +int have_switch_mm; +static int disable_switch_mm; + +int skas_needs_stub; static int __init skas0_cmd_param(char *str, int* add) { - ptrace_faultinfo = proc_mm = 0; + disable_ptrace_faultinfo = 1; + disable_ptrace_ldt = 1; + disable_proc_mm = 1; + disable_switch_mm = 1; + return 0; } @@ -159,15 +173,12 @@ static int __init mode_skas0_cmd_param(char *str, int* add) __attribute__((alias("skas0_cmd_param"))); __uml_setup("skas0", skas0_cmd_param, - "skas0\n" - " Disables SKAS3 usage, so that SKAS0 is used, unless \n" - " you specify mode=tt.\n\n"); +"skas0\n" +" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used\n\n"); __uml_setup("mode=skas0", mode_skas0_cmd_param, - "mode=skas0\n" - " Disables SKAS3 usage, so that SKAS0 is used, unless you \n" - " specify mode=tt. Note that this was recently added - on \n" - " older kernels you must use simply \"skas0\".\n\n"); +"mode=skas0\n" +" Disables SKAS3 and SKAS4 usage, so that SKAS0 is used.\n\n"); /* Changed only during early boot */ static int force_sysemu_disabled = 0; @@ -203,7 +214,7 @@ static void __init check_sysemu(void) if (n < 0) fatal_perror("check_sysemu : wait failed"); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - fatal("check_sysemu : expected SIGTRAP, got status = %d", + fatal("check_sysemu : expected SIGTRAP, got status = %d\n", status); if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) @@ -214,7 +225,7 @@ static void __init check_sysemu(void) goto fail; } - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) { non_fatal("check_sysemu : failed to modify system call " "return"); @@ -233,7 +244,7 @@ static void __init check_sysemu(void) if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *) PTRACE_O_TRACESYSGOOD) < 0)) - fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); + fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); while (1) { count++; @@ -241,14 +252,16 @@ static void __init check_sysemu(void) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) - fatal_perror("check_ptrace : wait failed"); + fatal_perror("check_sysemu: wait failed"); if (WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))) { - if (!count) - fatal("check_ptrace : SYSEMU_SINGLESTEP " - "doesn't singlestep"); - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, + if (!count) { + non_fatal("check_sysemu: SYSEMU_SINGLESTEP " + "doesn't singlestep"); + goto fail; + } + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) fatal_perror("check_sysemu : failed to modify " @@ -257,9 +270,12 @@ static void __init check_sysemu(void) } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; - else - fatal("check_ptrace : expected SIGTRAP or " - "(SIGTRAP | 0x80), got status = %d", status); + else { + non_fatal("check_sysemu: expected SIGTRAP or " + "(SIGTRAP | 0x80), got status = %d\n", + status); + goto fail; + } } if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; @@ -301,10 +317,10 @@ static void __init check_ptrace(void) fatal("check_ptrace : expected (SIGTRAP|0x80), " "got status = %d", status); - syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, + syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0); if (syscall == __NR_getpid) { - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, + n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getppid); if (n < 0) fatal_perror("check_ptrace : failed to modify " @@ -362,7 +378,7 @@ void __init os_early_checks(void) static int __init noprocmm_cmd_param(char *str, int* add) { - proc_mm = 0; + disable_proc_mm = 1; return 0; } @@ -374,7 +390,7 @@ __uml_setup("noprocmm", noprocmm_cmd_param, static int __init noptracefaultinfo_cmd_param(char *str, int* add) { - ptrace_faultinfo = 0; + disable_ptrace_faultinfo = 1; return 0; } @@ -386,7 +402,7 @@ __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, static int __init noptraceldt_cmd_param(char *str, int* add) { - ptrace_ldt = 0; + disable_ptrace_ldt = 1; return 0; } @@ -406,17 +422,15 @@ static inline void check_skas3_ptrace_faultinfo(void) n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); if (n < 0) { - ptrace_faultinfo = 0; if (errno == EIO) non_fatal("not found\n"); else perror("not found"); - } + } else if (disable_ptrace_faultinfo) + non_fatal("found but disabled on command line\n"); else { - if (!ptrace_faultinfo) - non_fatal("found but disabled on command line\n"); - else - non_fatal("found\n"); + ptrace_faultinfo = 1; + non_fatal("found\n"); } stop_ptraced_child(pid, 1, 1); @@ -439,38 +453,30 @@ static inline void check_skas3_ptrace_ldt(void) if (n < 0) { if (errno == EIO) non_fatal("not found\n"); - else { + else perror("not found"); - } - ptrace_ldt = 0; - } + } else if (disable_ptrace_ldt) + non_fatal("found, but use is disabled\n"); else { - if (ptrace_ldt) - non_fatal("found\n"); - else - non_fatal("found, but use is disabled\n"); + ptrace_ldt = 1; + non_fatal("found\n"); } stop_ptraced_child(pid, 1, 1); -#else - /* PTRACE_LDT might be disabled via cmdline option. - * We want to override this, else we might use the stub - * without real need - */ - ptrace_ldt = 1; #endif } static inline void check_skas3_proc_mm(void) { non_fatal(" - /proc/mm..."); - if (access("/proc/mm", W_OK) < 0) { - proc_mm = 0; + if (access("/proc/mm", W_OK) < 0) perror("not found"); - } - else if (!proc_mm) + else if (disable_proc_mm) non_fatal("found but disabled on command line\n"); - else non_fatal("found\n"); + else { + proc_mm = 1; + non_fatal("found\n"); + } } void can_do_skas(void) @@ -495,7 +501,7 @@ int __init parse_iomem(char *str, int *add) driver = str; file = strchr(str,','); if (file == NULL) { - printf("parse_iomem : failed to parse iomem\n"); + fprintf(stderr, "parse_iomem : failed to parse iomem\n"); goto out; } *file = '\0'; diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile deleted file mode 100644 index b4bc6ac4f30..00000000000 --- a/arch/um/os-Linux/sys-i386/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) -# Licensed under the GPL -# - -obj-y = registers.o signal.o task_size.o tls.o - -USER_OBJS := $(obj-y) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c deleted file mode 100644 index b613473b3ec..00000000000 --- a/arch/um/os-Linux/sys-i386/registers.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2004 PathScale, Inc - * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <errno.h> -#include "kern_constants.h" -#include "longjmp.h" -#include "user.h" -#include "sysdep/ptrace_user.h" - -int save_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int restore_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int save_fpx_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int restore_fpx_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -unsigned long get_thread_reg(int reg, jmp_buf *buf) -{ - switch (reg) { - case EIP: - return buf[0]->__eip; - case UESP: - return buf[0]->__esp; - case EBP: - return buf[0]->__ebp; - default: - printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", - reg); - return 0; - } -} - -int have_fpx_regs = 1; - -int get_fp_registers(int pid, unsigned long *regs) -{ - if (have_fpx_regs) - return save_fpx_registers(pid, regs); - else - return save_fp_registers(pid, regs); -} - -int put_fp_registers(int pid, unsigned long *regs) -{ - if (have_fpx_regs) - return restore_fpx_registers(pid, regs); - else - return restore_fp_registers(pid, regs); -} - -void arch_init_registers(int pid) -{ - unsigned long fpx_regs[HOST_XFP_SIZE]; - int err; - - err = ptrace(PTRACE_GETFPXREGS, pid, 0, fpx_regs); - if (!err) - return; - - if (errno != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - errno); - - have_fpx_regs = 0; -} diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c deleted file mode 100644 index f311609f93d..00000000000 --- a/arch/um/os-Linux/sys-i386/signal.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> - -extern void handle_signal(int sig, struct sigcontext *sc); - -void hard_handler(int sig) -{ - handle_signal(sig, (struct sigcontext *) (&sig + 1)); -} diff --git a/arch/um/os-Linux/sys-i386/task_size.c b/arch/um/os-Linux/sys-i386/task_size.c deleted file mode 100644 index 48d211b3d9a..00000000000 --- a/arch/um/os-Linux/sys-i386/task_size.c +++ /dev/null @@ -1,120 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/mman.h> -#include "longjmp.h" -#include "kern_constants.h" - -static jmp_buf buf; - -static void segfault(int sig) -{ - longjmp(buf, 1); -} - -static int page_ok(unsigned long page) -{ - unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT); - unsigned long n = ~0UL; - void *mapped = NULL; - int ok = 0; - - /* - * First see if the page is readable. If it is, it may still - * be a VDSO, so we go on to see if it's writable. If not - * then try mapping memory there. If that fails, then we're - * still in the kernel area. As a sanity check, we'll fail if - * the mmap succeeds, but gives us an address different from - * what we wanted. - */ - if (setjmp(buf) == 0) - n = *address; - else { - mapped = mmap(address, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mapped == MAP_FAILED) - return 0; - if (mapped != address) - goto out; - } - - /* - * Now, is it writeable? If so, then we're in user address - * space. If not, then try mprotecting it and try the write - * again. - */ - if (setjmp(buf) == 0) { - *address = n; - ok = 1; - goto out; - } else if (mprotect(address, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE) != 0) - goto out; - - if (setjmp(buf) == 0) { - *address = n; - ok = 1; - } - - out: - if (mapped != NULL) - munmap(mapped, UM_KERN_PAGE_SIZE); - return ok; -} - -unsigned long os_get_task_size(void) -{ - struct sigaction sa, old; - unsigned long bottom = 0; - /* - * A 32-bit UML on a 64-bit host gets confused about the VDSO at - * 0xffffe000. It is mapped, is readable, can be reprotected writeable - * and written. However, exec discovers later that it can't be - * unmapped. So, just set the highest address to be checked to just - * below it. This might waste some address space on 4G/4G 32-bit - * hosts, but shouldn't hurt otherwise. - */ - unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT; - unsigned long test; - - printf("Locating the top of the address space ... "); - fflush(stdout); - - /* - * We're going to be longjmping out of the signal handler, so - * SA_DEFER needs to be set. - */ - sa.sa_handler = segfault; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NODEFER; - sigaction(SIGSEGV, &sa, &old); - - if (!page_ok(bottom)) { - fprintf(stderr, "Address 0x%x no good?\n", - bottom << UM_KERN_PAGE_SHIFT); - exit(1); - } - - /* This could happen with a 4G/4G split */ - if (page_ok(top)) - goto out; - - do { - test = bottom + (top - bottom) / 2; - if (page_ok(test)) - bottom = test; - else - top = test; - } while (top - bottom > 1); - -out: - /* Restore the old SIGSEGV handling */ - sigaction(SIGSEGV, &old, NULL); - - top <<= UM_KERN_PAGE_SHIFT; - printf("0x%x\n", top); - fflush(stdout); - - return top; -} diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c deleted file mode 100644 index 32ed41ec1a3..00000000000 --- a/arch/um/os-Linux/sys-i386/tls.c +++ /dev/null @@ -1,36 +0,0 @@ -#include <errno.h> -#include <linux/unistd.h> - -#include <sys/syscall.h> -#include <unistd.h> - -#include "sysdep/tls.h" -#include "user.h" - -/* Checks whether host supports TLS, and sets *tls_min according to the value - * valid on the host. - * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ -void check_host_supports_tls(int *supports_tls, int *tls_min) { - /* Values for x86 and x86_64.*/ - int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; - int i; - - for (i = 0; i < ARRAY_SIZE(val); i++) { - user_desc_t info; - info.entry_number = val[i]; - - if (syscall(__NR_get_thread_area, &info) == 0) { - *tls_min = val[i]; - *supports_tls = 1; - return; - } else { - if (errno == EINVAL) - continue; - else if (errno == ENOSYS) - *supports_tls = 0; - return; - } - } - - *supports_tls = 0; -} diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile deleted file mode 100644 index a44a47f8f57..00000000000 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) -# Licensed under the GPL -# - -obj-y = registers.o prctl.o signal.o task_size.o - -USER_OBJS := $(obj-y) - -include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/sys-x86_64/prctl.c b/arch/um/os-Linux/sys-x86_64/prctl.c deleted file mode 100644 index 9d34eddb517..00000000000 --- a/arch/um/os-Linux/sys-x86_64/prctl.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com}) - * Licensed under the GPL - */ - -#include <sys/ptrace.h> -#include <linux/ptrace.h> - -int os_arch_prctl(int pid, int code, unsigned long *addr) -{ - return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) addr, code); -} diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c deleted file mode 100644 index 594d97ad02b..00000000000 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2006 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <errno.h> -#include <sys/ptrace.h> -#define __FRAME_OFFSETS -#include <asm/ptrace.h> -#include "kern_constants.h" -#include "longjmp.h" -#include "user.h" - -int save_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int restore_fp_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -unsigned long get_thread_reg(int reg, jmp_buf *buf) -{ - switch (reg) { - case RIP: - return buf[0]->__rip; - case RSP: - return buf[0]->__rsp; - case RBP: - return buf[0]->__rbp; - default: - printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n", - reg); - return 0; - } -} - -int get_fp_registers(int pid, unsigned long *regs) -{ - return save_fp_registers(pid, regs); -} - -int put_fp_registers(int pid, unsigned long *regs) -{ - return restore_fp_registers(pid, regs); -} diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c deleted file mode 100644 index 82a388822cd..00000000000 --- a/arch/um/os-Linux/sys-x86_64/signal.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> - -extern void handle_signal(int sig, struct sigcontext *sc); - -void hard_handler(int sig) -{ - struct ucontext *uc; - asm("movq %%rdx, %0" : "=r" (uc)); - - handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext); -} diff --git a/arch/um/os-Linux/sys-x86_64/task_size.c b/arch/um/os-Linux/sys-x86_64/task_size.c deleted file mode 100644 index fad6f57f8ee..00000000000 --- a/arch/um/os-Linux/sys-x86_64/task_size.c +++ /dev/null @@ -1,5 +0,0 @@ -unsigned long os_get_task_size(unsigned long shift) -{ - /* The old value of CONFIG_TOP_ADDR */ - return 0x7fc0000000; -} diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index e4928059946..e9824d5dd7d 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -8,9 +8,9 @@ #include <signal.h> #include <time.h> #include <sys/time.h> -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> +#include "internal.h" int set_interval(void) { @@ -58,12 +58,17 @@ static inline long long timeval_to_ns(const struct timeval *tv) long long disable_timer(void) { struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); + long long remain, max = UM_NSEC_PER_SEC / UM_HZ; if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) printk(UM_KERN_ERR "disable_timer - setitimer failed, " "errno = %d\n", errno); - return timeval_to_ns(&time.it_value); + remain = timeval_to_ns(&time.it_value); + if (remain > max) + remain = max; + + return remain; } long long os_nsecs(void) @@ -74,12 +79,53 @@ long long os_nsecs(void) return timeval_to_ns(&tv); } -#ifdef UML_CONFIG_NO_HZ +#ifdef UML_CONFIG_NO_HZ_COMMON static int after_sleep_interval(struct timespec *ts) { return 0; } + +static void deliver_alarm(void) +{ + alarm_handler(SIGVTALRM, NULL, NULL); +} + +static unsigned long long sleep_time(unsigned long long nsecs) +{ + return nsecs; +} + #else +unsigned long long last_tick; +unsigned long long skew; + +static void deliver_alarm(void) +{ + unsigned long long this_tick = os_nsecs(); + int one_tick = UM_NSEC_PER_SEC / UM_HZ; + + /* Protection against the host's time going backwards */ + if ((last_tick != 0) && (this_tick < last_tick)) + this_tick = last_tick; + + if (last_tick == 0) + last_tick = this_tick - one_tick; + + skew += this_tick - last_tick; + + while (skew >= one_tick) { + alarm_handler(SIGVTALRM, NULL, NULL); + skew -= one_tick; + } + + last_tick = this_tick; +} + +static unsigned long long sleep_time(unsigned long long nsecs) +{ + return nsecs > skew ? nsecs - skew : 0; +} + static inline long long timespec_to_us(const struct timespec *ts) { return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + @@ -102,6 +148,11 @@ static int after_sleep_interval(struct timespec *ts) */ if (start_usecs > usec) start_usecs = usec; + + start_usecs -= skew / UM_NSEC_PER_USEC; + if (start_usecs < 0) + start_usecs = 0; + tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, .tv_usec = start_usecs % UM_USEC_PER_SEC }); interval = ((struct itimerval) { { 0, usec }, tv }); @@ -113,8 +164,6 @@ static int after_sleep_interval(struct timespec *ts) } #endif -extern void alarm_handler(int sig, struct sigcontext *sc); - void idle_sleep(unsigned long long nsecs) { struct timespec ts; @@ -126,10 +175,12 @@ void idle_sleep(unsigned long long nsecs) */ if (nsecs == 0) nsecs = UM_NSEC_PER_SEC / UM_HZ; + + nsecs = sleep_time(nsecs); ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, .tv_nsec = nsecs % UM_NSEC_PER_SEC }); if (nanosleep(&ts, &ts) == 0) - alarm_handler(SIGVTALRM, NULL); + deliver_alarm(); after_sleep_interval(&ts); } diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c deleted file mode 100644 index 73277801ef1..00000000000 --- a/arch/um/os-Linux/tls.c +++ /dev/null @@ -1,35 +0,0 @@ -#include <errno.h> -#include <sys/ptrace.h> -#include "sysdep/tls.h" - -/* TLS support - we basically rely on the host's one.*/ - -#ifndef PTRACE_GET_THREAD_AREA -#define PTRACE_GET_THREAD_AREA 25 -#endif - -#ifndef PTRACE_SET_THREAD_AREA -#define PTRACE_SET_THREAD_AREA 26 -#endif - -int os_set_thread_area(user_desc_t *info, int pid) -{ - int ret; - - ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, - (unsigned long) info); - if (ret < 0) - ret = -errno; - return ret; -} - -int os_get_thread_area(user_desc_t *info, int pid) -{ - int ret; - - ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, - (unsigned long) info); - if (ret < 0) - ret = -errno; - return ret; -} diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index b09ff66a77e..721d8afa329 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -7,10 +7,8 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> -#include "kern_constants.h" -#include "kern_util.h" -#include "os.h" -#include "user.h" +#include <kern_util.h> +#include <os.h> struct grantpt_info { int fd; diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c deleted file mode 100644 index cc648e6fd3a..00000000000 --- a/arch/um/os-Linux/tty_log.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and - * geoffrey hing <ghing@net.ohio-state.edu> - * Licensed under the GPL - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/time.h> -#include "init.h" -#include "user.h" -#include "os.h" - -#define TTY_LOG_DIR "./" - -/* Set early in boot and then unchanged */ -static char *tty_log_dir = TTY_LOG_DIR; -static int tty_log_fd = -1; - -#define TTY_LOG_OPEN 1 -#define TTY_LOG_CLOSE 2 -#define TTY_LOG_WRITE 3 -#define TTY_LOG_EXEC 4 - -#define TTY_READ 1 -#define TTY_WRITE 2 - -struct tty_log_buf { - int what; - unsigned long tty; - int len; - int direction; - unsigned long sec; - unsigned long usec; -}; - -int open_tty_log(void *tty, void *current_tty) -{ - struct timeval tv; - struct tty_log_buf data; - char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; - int fd; - - gettimeofday(&tv, NULL); - if(tty_log_fd != -1){ - data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, - .tty = (unsigned long) tty, - .len = sizeof(current_tty), - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - write(tty_log_fd, ¤t_tty, data.len); - return tty_log_fd; - } - - sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, - (unsigned int) tv.tv_usec); - - fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), - 0644); - if(fd < 0){ - printk("open_tty_log : couldn't open '%s', errno = %d\n", - buf, -fd); - } - return fd; -} - -void close_tty_log(int fd, void *tty) -{ - struct tty_log_buf data; - struct timeval tv; - - if(tty_log_fd != -1){ - gettimeofday(&tv, NULL); - data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, - .tty = (unsigned long) tty, - .len = 0, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - return; - } - os_close_file(fd); -} - -static int log_chunk(int fd, const char *buf, int len) -{ - int total = 0, try, missed, n; - char chunk[64]; - - while(len > 0){ - try = (len > sizeof(chunk)) ? sizeof(chunk) : len; - missed = copy_from_user_proc(chunk, (char *) buf, try); - try -= missed; - n = write(fd, chunk, try); - if(n != try) { - if(n < 0) - return -errno; - return -EIO; - } - if(missed != 0) - return -EFAULT; - - len -= try; - total += try; - buf += try; - } - - return total; -} - -int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) -{ - struct timeval tv; - struct tty_log_buf data; - int direction; - - if(fd == tty_log_fd){ - gettimeofday(&tv, NULL); - direction = is_read ? TTY_READ : TTY_WRITE; - data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, - .tty = (unsigned long) tty, - .len = len, - .direction = direction, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - } - - return log_chunk(fd, buf, len); -} - -void log_exec(char **argv, void *tty) -{ - struct timeval tv; - struct tty_log_buf data; - char **ptr,*arg; - int len; - - if(tty_log_fd == -1) return; - - gettimeofday(&tv, NULL); - - len = 0; - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - len += strlen_user_proc(arg); - } - - data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, - .tty = (unsigned long) tty, - .len = len, - .direction = 0, - .sec = tv.tv_sec, - .usec = tv.tv_usec } ); - write(tty_log_fd, &data, sizeof(data)); - - for(ptr = argv; ; ptr++){ - if(copy_from_user_proc(&arg, ptr, sizeof(arg))) - return; - if(arg == NULL) break; - log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); - } -} - -extern void register_tty_logger(int (*opener)(void *, void *), - int (*writer)(int, const char *, int, - void *, int), - void (*closer)(int, void *)); - -static int register_logger(void) -{ - register_tty_logger(open_tty_log, write_tty_log, close_tty_log); - return 0; -} - -__uml_initcall(register_logger); - -static int __init set_tty_log_dir(char *name, int *add) -{ - tty_log_dir = name; - return 0; -} - -__uml_setup("tty_log_dir=", set_tty_log_dir, -"tty_log_dir=<directory>\n" -" This is used to specify the directory where the logs of all pty\n" -" data from this UML machine will be written.\n\n" -); - -static int __init set_tty_log_fd(char *name, int *add) -{ - char *end; - - tty_log_fd = strtoul(name, &end, 0); - if((*end != '\0') || (end == name)){ - printf("set_tty_log_fd - strtoul failed on '%s'\n", name); - tty_log_fd = -1; - } - - *add = 0; - return 0; -} - -__uml_setup("tty_log_fd=", set_tty_log_fd, -"tty_log_fd=<fd>\n" -" This is used to specify a preconfigured file descriptor to which all\n" -" tty data will be written. Preconfigure the descriptor with something\n" -" like '10>tty_log tty_log_fd=10'.\n\n" -); diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c deleted file mode 100644 index 087ed74ffca..00000000000 --- a/arch/um/os-Linux/uaccess.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <stddef.h> -#include "longjmp.h" - -unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, jmp_buf **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out) -{ - unsigned long *faddrp = (unsigned long *) fault_addr, ret; - - jmp_buf jbuf; - *fault_catcher = &jbuf; - if (UML_SETJMP(&jbuf) == 0) { - (*op)(to, from, n); - ret = 0; - *faulted_out = 0; - } - else { - ret = *faddrp; - *faulted_out = 1; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 106fa864155..c1dc89261f6 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -12,10 +12,8 @@ #include <string.h> #include <unistd.h> #include <sys/stat.h> -#include "init.h" -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <init.h> +#include <os.h> #define UML_DIR "~/.uml/" @@ -245,7 +243,7 @@ int __init set_umid(char *name) /* Changed in make_umid, which is called during early boot */ static int umid_setup = 0; -int __init make_umid(void) +static int __init make_umid(void) { int fd, err; char tmp[256]; diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 74f49bb9b12..db4a034aeee 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -1,5 +1,5 @@ -#include "linux/types.h" -#include "linux/module.h" +#include <linux/types.h> +#include <linux/module.h> /* Some of this are builtin function (some are not but could in the future), * so I *must* declare good prototypes for them and then EXPORT them. @@ -14,7 +14,6 @@ #undef memset extern size_t strlen(const char *); -extern void *memcpy(void *, const void *, size_t); extern void *memmove(void *, const void *, size_t); extern void *memset(void *, int, size_t); extern int printf(const char *, ...); @@ -24,7 +23,11 @@ extern int printf(const char *, ...); EXPORT_SYMBOL(strstr); #endif +#ifndef __x86_64__ +extern void *memcpy(void *, const void *, size_t); EXPORT_SYMBOL(memcpy); +#endif + EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(printf); @@ -42,7 +45,7 @@ EXPORT_SYMBOL(readdir64); extern void truncate64(void) __attribute__((weak)); EXPORT_SYMBOL(truncate64); -#ifdef SUBARCH_i386 +#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA EXPORT_SYMBOL(vsyscall_ehdr); EXPORT_SYMBOL(vsyscall_end); #endif @@ -100,9 +103,18 @@ EXPORT_SYMBOL_PROTO(getuid); EXPORT_SYMBOL_PROTO(fsync); EXPORT_SYMBOL_PROTO(fdatasync); +EXPORT_SYMBOL_PROTO(lstat64); +EXPORT_SYMBOL_PROTO(fstat64); +EXPORT_SYMBOL_PROTO(mknod); + /* Export symbols used by GCC for the stack protector. */ extern void __stack_smash_handler(void *) __attribute__((weak)); EXPORT_SYMBOL(__stack_smash_handler); extern long __guard __attribute__((weak)); EXPORT_SYMBOL(__guard); + +#ifdef _FORTIFY_SOURCE +extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); +EXPORT_SYMBOL(__sprintf_chk); +#endif diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 6ea77979531..faee55ef6d2 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <errno.h> #include <signal.h> #include <string.h> @@ -12,9 +13,7 @@ #include <wait.h> #include <sys/mman.h> #include <sys/utsname.h> -#include "kern_constants.h" -#include "os.h" -#include "user.h" +#include <os.h> void stack_protections(unsigned long address) { @@ -75,6 +74,36 @@ void setup_hostinfo(char *buf, int len) host.release, host.version, host.machine); } +/* + * We cannot use glibc's abort(). It makes use of tgkill() which + * has no effect within UML's kernel threads. + * After that glibc would execute an invalid instruction to kill + * the calling process and UML crashes with SIGSEGV. + */ +static inline void __attribute__ ((noreturn)) uml_abort(void) +{ + sigset_t sig; + + fflush(NULL); + + if (!sigemptyset(&sig) && !sigaddset(&sig, SIGABRT)) + sigprocmask(SIG_UNBLOCK, &sig, 0); + + for (;;) + if (kill(getpid(), SIGABRT) < 0) + exit(127); +} + +/* + * UML helper threads must not handle SIGWINCH/INT/TERM + */ +void os_fix_helper_signals(void) +{ + signal(SIGWINCH, SIG_IGN); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); +} + void os_dump_core(void) { int pid; @@ -116,5 +145,10 @@ void os_dump_core(void) while ((pid = waitpid(-1, NULL, WNOHANG | __WALL)) > 0) os_kill_ptraced_process(pid, 0); - abort(); + uml_abort(); +} + +void um_early_printk(const char *s, unsigned int n) +{ + printf("%.*s", n, s); } |
