diff options
Diffstat (limited to 'arch/um/kernel')
41 files changed, 377 insertions, 497 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 246f0e7fb4cc..a8918e80df96 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -4,9 +4,9 @@ # extra-y := vmlinux.lds -clean-files := vmlinux.lds.S config.tmp +clean-files := -obj-y = checksum.o config.o exec_kern.o exitcode.o \ +obj-y = config.o exec_kern.o exitcode.o \ helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \ physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ @@ -14,7 +14,7 @@ obj-y = checksum.o config.o exec_kern.o exitcode.o \ tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o umid.o \ user_util.o -obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o +obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o obj-$(CONFIG_GCOV) += gmon_syms.o obj-$(CONFIG_TTY_LOG) += tty_log.o @@ -23,18 +23,14 @@ obj-$(CONFIG_SYSCALL_DEBUG) += syscall_user.o obj-$(CONFIG_MODE_TT) += tt/ obj-$(CONFIG_MODE_SKAS) += skas/ -# This needs be compiled with frame pointers regardless of how the rest of the -# kernel is built. -CFLAGS_frame.o := -fno-omit-frame-pointer - user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(user-objs-y) config.o helper.o main.o process.o tempfile.o \ - time.o tty_log.o umid.o user_util.o frame.o + time.o tty_log.o umid.o user_util.o include arch/um/scripts/Makefile.rules -targets += config.c +targets := config.c config.tmp # Be careful with the below Sed code - sed is pitfall-rich! # We use sed to lower build requirements, for "embedded" builders for instance. diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c deleted file mode 100644 index e69b2be951d1..000000000000 --- a/arch/um/kernel/checksum.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "asm/uaccess.h" -#include "linux/errno.h" -#include "linux/module.h" - -unsigned int arch_csum_partial(const unsigned char *buff, int len, int sum); - -unsigned int csum_partial(unsigned char *buff, int len, int sum) -{ - return arch_csum_partial(buff, len, sum); -} - -EXPORT_SYMBOL(csum_partial); - -unsigned int csum_partial_copy_to(const unsigned char *src, - unsigned char __user *dst, int len, int sum, - int *err_ptr) -{ - if(copy_to_user(dst, src, len)){ - *err_ptr = -EFAULT; - return(-1); - } - - return(arch_csum_partial(src, len, sum)); -} - -unsigned int csum_partial_copy_from(const unsigned char __user *src, - unsigned char *dst, int len, int sum, - int *err_ptr) -{ - if(copy_from_user(dst, src, len)){ - *err_ptr = -EFAULT; - return(-1); - } - - return arch_csum_partial(dst, len, sum); -} diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 49ddabe69be7..efd222ffe20e 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -16,7 +16,6 @@ #include "kern.h" #include "irq_user.h" #include "tlb.h" -#include "2_5compat.h" #include "os.h" #include "time_user.h" #include "choose-mode.h" diff --git a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd.c index fc568af468b9..82ecf904b09c 100644 --- a/arch/um/kernel/initrd_kern.c +++ b/arch/um/kernel/initrd.c @@ -41,12 +41,31 @@ static int __init uml_initrd_setup(char *line, int *add) return 0; } -__uml_setup("initrd=", uml_initrd_setup, +__uml_setup("initrd=", uml_initrd_setup, "initrd=<initrd image>\n" " This is used to boot UML from an initrd image. The argument is the\n" " name of the file containing the image.\n\n" ); +int load_initrd(char *filename, void *buf, int size) +{ + int fd, n; + + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); + return(-1); + } + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); + return(-1); + } + + os_close_file(fd); + return(0); +} /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c deleted file mode 100644 index cb90681e151c..000000000000 --- a/arch/um/kernel/initrd_user.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> - -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "initrd.h" -#include "os.h" - -int load_initrd(char *filename, void *buf, int size) -{ - int fd, n; - - fd = os_open_file(filename, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Opening '%s' failed - err = %d\n", filename, -fd); - return(-1); - } - n = os_read_file(fd, buf, size); - if(n != size){ - printk("Read of %d bytes from '%s' failed, err = %d\n", size, - filename, -n); - return(-1); - } - - os_close_file(fd); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index d71e8f00810f..d44fb5282547 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -163,7 +163,6 @@ void __init init_IRQ(void) irq_desc[i].handler = &SIGIO_irq_type; enable_irq(i); } - init_irq_signals(0); } /* diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 6d6f9484b884..b3074cbaa479 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -236,9 +236,15 @@ static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) (*prev)->fd, pollfds[i].fd); goto out; } - memcpy(&pollfds[i], &pollfds[i + 1], - (pollfds_num - i - 1) * sizeof(pollfds[0])); + pollfds_num--; + + /* This moves the *whole* array after pollfds[i] (though + * it doesn't spot as such)! */ + + memmove(&pollfds[i], &pollfds[i + 1], + (pollfds_num - i) * sizeof(pollfds[0])); + if(last_irq_ptr == &old_fd->next) last_irq_ptr = prev; *prev = (*prev)->next; diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index b41d3397d07b..99439fa15ef4 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -10,7 +10,6 @@ #include "linux/spinlock.h" #include "linux/highmem.h" #include "asm/current.h" -#include "asm/delay.h" #include "asm/processor.h" #include "asm/unistd.h" #include "asm/pgalloc.h" @@ -28,8 +27,6 @@ EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(sys_waitpid); EXPORT_SYMBOL(task_size); EXPORT_SYMBOL(flush_tlb_range); @@ -60,6 +57,7 @@ EXPORT_SYMBOL(copy_to_user_tt); EXPORT_SYMBOL(strncpy_from_user_skas); EXPORT_SYMBOL(copy_to_user_skas); EXPORT_SYMBOL(copy_from_user_skas); +EXPORT_SYMBOL(clear_user_skas); #endif EXPORT_SYMBOL(uml_strdup); diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c index a17c49703f9b..e59f58152678 100644 --- a/arch/um/kernel/main.c +++ b/arch/um/kernel/main.c @@ -24,8 +24,6 @@ #include "mode.h" #include "choose-mode.h" #include "uml-config.h" -#include "irq_user.h" -#include "time_user.h" #include "os.h" /* Set in set_stklim, which is called from main and __wrap_malloc. @@ -71,7 +69,7 @@ static __init void do_uml_initcalls(void) static void last_ditch_exit(int sig) { - CHOOSE_MODE(kmalloc_ok = 0, (void) 0); + kmalloc_ok = 0; signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -87,7 +85,7 @@ int main(int argc, char **argv, char **envp) { char **new_argv; sigset_t mask; - int ret, i; + int ret, i, err; /* Enable all signals except SIGIO - in some environments, we can * enter with some signals blocked @@ -160,27 +158,29 @@ int main(int argc, char **argv, char **envp) */ change_sig(SIGPROF, 0); - /* Reboot */ - if(ret){ - int err; + /* This signal stuff used to be in the reboot case. However, + * sometimes a SIGVTALRM can come in when we're halting (reproducably + * when writing out gcov information, presumably because that takes + * some time) and cause a segfault. + */ - printf("\n"); + /* stop timers and set SIG*ALRM to be ignored */ + disable_timer(); - /* stop timers and set SIG*ALRM to be ignored */ - disable_timer(); + /* disable SIGIO for the fds and set SIGIO to be ignored */ + err = deactivate_all_fds(); + if(err) + printf("deactivate_all_fds failed, errno = %d\n", -err); - /* disable SIGIO for the fds and set SIGIO to be ignored */ - err = deactivate_all_fds(); - if(err) - printf("deactivate_all_fds failed, errno = %d\n", - -err); - - /* Let any pending signals fire now. This ensures - * that they won't be delivered after the exec, when - * they are definitely not expected. - */ - unblock_signals(); + /* Let any pending signals fire now. This ensures + * that they won't be delivered after the exec, when + * they are definitely not expected. + */ + unblock_signals(); + /* Reboot */ + if(ret){ + printf("\n"); execvp(new_argv[0], new_argv); perror("Failed to exec kernel"); ret = 1; diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index f156661781cb..c22825f13e40 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -100,12 +100,37 @@ void mem_init(void) #endif } +/* + * Create a page table and place a pointer to it in a middle page + * directory entry. + */ +static void __init one_page_table_init(pmd_t *pmd) +{ + if (pmd_none(*pmd)) { + pte_t *pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pmd(pmd, __pmd(_KERNPG_TABLE + + (unsigned long) __pa(pte))); + if (pte != pte_offset_kernel(pmd, 0)) + BUG(); + } +} + +static void __init one_md_table_init(pud_t *pud) +{ +#ifdef CONFIG_3_LEVEL_PGTABLES + pmd_t *pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + set_pud(pud, __pud(_KERNPG_TABLE + (unsigned long) __pa(pmd_table))); + if (pmd_table != pmd_offset(pud, 0)) + BUG(); +#endif +} + static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; - pte_t *pte; int i, j; unsigned long vaddr; @@ -115,15 +140,12 @@ static void __init fixrange_init(unsigned long start, unsigned long end, pgd = pgd_base + i; for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { - pmd = (pmd_t *)pgd; + pud = pud_offset(pgd, vaddr); + if (pud_none(*pud)) + one_md_table_init(pud); + pmd = pmd_offset(pud, vaddr); for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { - if (pmd_none(*pmd)) { - pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(_KERNPG_TABLE + - (unsigned long) __pa(pte))); - if (pte != pte_offset_kernel(pmd, 0)) - BUG(); - } + one_page_table_init(pmd); vaddr += PMD_SIZE; } j = 0; diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index f76a2692adca..1b5ef3e96c71 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -30,7 +30,6 @@ #include "init.h" #include "os.h" #include "uml-config.h" -#include "ptrace_user.h" #include "choose-mode.h" #include "mode.h" #ifdef UML_CONFIG_MODE_SKAS @@ -65,8 +64,6 @@ void init_new_thread_signals(int altstack) SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); - set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); signal(SIGHUP, SIG_IGN); @@ -133,7 +130,7 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, return(arg.pid); } -static int ptrace_child(void *arg) +static int ptrace_child(void) { int ret; int pid = os_getpid(), ppid = getppid(); @@ -162,20 +159,16 @@ static int ptrace_child(void *arg) _exit(ret); } -static int start_ptraced_child(void **stack_out) +static int start_ptraced_child(void) { - void *stack; - unsigned long sp; int pid, n, status; - stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if(stack == MAP_FAILED) - panic("check_ptrace : mmap failed, errno = %d", errno); - sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); + pid = fork(); + if(pid == 0) + ptrace_child(); + if(pid < 0) - panic("check_ptrace : clone failed, errno = %d", errno); + panic("check_ptrace : fork failed, errno = %d", errno); CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); @@ -183,7 +176,6 @@ static int start_ptraced_child(void **stack_out) panic("check_ptrace : expected SIGSTOP, got status = %d", status); - *stack_out = stack; return(pid); } @@ -191,12 +183,12 @@ static int start_ptraced_child(void **stack_out) * just avoid using sysemu, not panic, but only if SYSEMU features are broken. * So only for SYSEMU features we test mustpanic, while normal host features * must work anyway!*/ -static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic) +static int stop_ptraced_child(int pid, int exitcode, int mustexit) { int status, n, ret = 0; if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", errno); + panic("stop_ptraced_child : ptrace failed, errno = %d", errno); CATCH_EINTR(n = waitpid(pid, &status, 0)); if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); @@ -207,15 +199,13 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic) printk("check_ptrace : child exited with exitcode %d, while " "expecting %d; status 0x%x", exit_with, exitcode, status); - if (mustpanic) + if (mustexit) panic("\n"); else printk("\n"); ret = -1; } - if(munmap(stack, PAGE_SIZE) < 0) - panic("check_ptrace : munmap failed, errno = %d", errno); return ret; } @@ -237,12 +227,11 @@ __uml_setup("nosysemu", nosysemu_cmd_param, static void __init check_sysemu(void) { - void *stack; int pid, syscall, n, status, count=0; printk("Checking syscall emulation patch for ptrace..."); sysemu_supported = 0; - pid = start_ptraced_child(&stack); + pid = start_ptraced_child(); if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) goto fail; @@ -260,7 +249,7 @@ static void __init check_sysemu(void) panic("check_sysemu : failed to modify system " "call return, errno = %d", errno); - if (stop_ptraced_child(pid, stack, 0, 0) < 0) + if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; sysemu_supported = 1; @@ -268,7 +257,7 @@ static void __init check_sysemu(void) set_using_sysemu(!force_sysemu_disabled); printk("Checking advanced syscall emulation patch for ptrace..."); - pid = start_ptraced_child(&stack); + pid = start_ptraced_child(); while(1){ count++; if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0) @@ -293,7 +282,7 @@ static void __init check_sysemu(void) break; } } - if (stop_ptraced_child(pid, stack, 0, 0) < 0) + if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; sysemu_supported = 2; @@ -304,18 +293,17 @@ static void __init check_sysemu(void) return; fail: - stop_ptraced_child(pid, stack, 1, 0); + stop_ptraced_child(pid, 1, 0); fail_stopped: printk("missing\n"); } void __init check_ptrace(void) { - void *stack; int pid, syscall, n, status; printk("Checking that ptrace can change system call numbers..."); - pid = start_ptraced_child(&stack); + pid = start_ptraced_child(); if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno); @@ -342,7 +330,7 @@ void __init check_ptrace(void) break; } } - stop_ptraced_child(pid, stack, 0, 1); + stop_ptraced_child(pid, 0, 1); printk("OK\n"); check_sysemu(); } @@ -374,11 +362,10 @@ void forward_pending_sigio(int target) static inline int check_skas3_ptrace_support(void) { struct ptrace_faultinfo fi; - void *stack; int pid, n, ret = 1; printf("Checking for the skas3 patch in the host..."); - pid = start_ptraced_child(&stack); + pid = start_ptraced_child(); n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); if (n < 0) { @@ -393,7 +380,7 @@ static inline int check_skas3_ptrace_support(void) } init_registers(pid); - stop_ptraced_child(pid, stack, 1, 1); + stop_ptraced_child(pid, 1, 1); return(ret); } diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 7a943696f950..804c6bbdf67c 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -43,7 +43,6 @@ #include "tlb.h" #include "frame_kern.h" #include "sigcontext.h" -#include "2_5compat.h" #include "os.h" #include "mode.h" #include "mode_kern.h" @@ -55,18 +54,6 @@ */ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; -struct task_struct *get_task(int pid, int require) -{ - struct task_struct *ret; - - read_lock(&tasklist_lock); - ret = find_task_by_pid(pid); - read_unlock(&tasklist_lock); - - if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); - return(ret); -} - int external_pid(void *t) { struct task_struct *task = t ? t : current; @@ -115,16 +102,6 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) return(pid); } -void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) -{ - int cpu = smp_processor_id(); - - if (prev != next) - cpu_clear(cpu, prev->cpu_vm_mask); - cpu_set(cpu, next->cpu_vm_mask); -} - void set_current(void *t) { struct task_struct *task = t; @@ -152,7 +129,6 @@ void release_thread(struct task_struct *task) void exit_thread(void) { - CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); unprotect_stack((unsigned long) current_thread); } @@ -200,7 +176,6 @@ void default_idle(void) while(1){ /* endless idle loop with no priority at all */ - SET_PRI(current); /* * although we are an idle CPU, we do not want to @@ -223,11 +198,6 @@ int page_size(void) return(PAGE_SIZE); } -unsigned long page_mask(void) -{ - return(PAGE_MASK); -} - void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out) { @@ -360,11 +330,6 @@ char *uml_strdup(char *string) return(new); } -void *get_init_task(void) -{ - return(&init_thread_union.thread_info.task); -} - int copy_to_user_proc(void __user *to, void *from, int size) { return(copy_to_user(to, from, size)); @@ -476,21 +441,18 @@ int singlestepping(void * t) return 2; } +/* + * Only x86 and x86_64 have an arch_align_stack(). + * All other arches have "#define arch_align_stack(x) (x)" + * in their asm/system.h + * As this is included in UML from asm-um/system-generic.h, + * we can use it to behave as the subarch does. + */ +#ifndef arch_align_stack unsigned long arch_align_stack(unsigned long sp) { if (randomize_va_space) sp -= get_random_int() % 8192; return sp & ~0xf; } - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ +#endif diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index e50e60ff5d27..71af4d503899 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -19,15 +19,30 @@ #include "skas_ptrace.h" #include "sysdep/ptrace.h" +static inline void set_singlestepping(struct task_struct *child, int on) +{ + if (on) + child->ptrace |= PT_DTRACE; + else + child->ptrace &= ~PT_DTRACE; + child->thread.singlestep_syscall = 0; + +#ifdef SUBARCH_SET_SINGLESTEPPING + SUBARCH_SET_SINGLESTEPPING(child, on); +#endif +} + /* * Called by kernel/ptrace.c when detaching.. */ void ptrace_disable(struct task_struct *child) { - child->ptrace &= ~PT_DTRACE; - child->thread.singlestep_syscall = 0; + set_singlestepping(child,0); } +extern int peek_user(struct task_struct * child, long addr, long data); +extern int poke_user(struct task_struct * child, long addr, long data); + long sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -67,6 +82,10 @@ long sys_ptrace(long request, long pid, long addr, long data) goto out_tsk; } +#ifdef SUBACH_PTRACE_SPECIAL + SUBARCH_PTRACE_SPECIAL(child,request,addr,data); +#endif + ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; @@ -87,26 +106,9 @@ long sys_ptrace(long request, long pid, long addr, long data) } /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr < 0) - break; - - tmp = 0; /* Default return condition */ - if(addr < MAX_REG_OFFSET){ - tmp = getreg(child, addr); - } - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } - ret = put_user(tmp, (unsigned long __user *) data); - break; - } + case PTRACE_PEEKUSR: + ret = peek_user(child, addr, data); + break; /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ @@ -119,26 +121,8 @@ long sys_ptrace(long request, long pid, long addr, long data) break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr < 0) - break; - - if (addr < MAX_REG_OFFSET) { - ret = putreg(child, addr, data); - break; - } -#if 0 /* XXX x86_64 */ - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - if((addr == 4) || (addr == 5)) break; - child->thread.arch.debugregs[addr] = data; - ret = 0; - } -#endif - - break; + ret = poke_user(child, addr, data); + break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ @@ -146,8 +130,7 @@ long sys_ptrace(long request, long pid, long addr, long data) if (!valid_signal(data)) break; - child->ptrace &= ~PT_DTRACE; - child->thread.singlestep_syscall = 0; + set_singlestepping(child, 0); if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } @@ -170,8 +153,7 @@ long sys_ptrace(long request, long pid, long addr, long data) if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; - child->ptrace &= ~PT_DTRACE; - child->thread.singlestep_syscall = 0; + set_singlestepping(child, 0); child->exit_code = SIGKILL; wake_up_process(child); break; @@ -182,8 +164,7 @@ long sys_ptrace(long request, long pid, long addr, long data) if (!valid_signal(data)) break; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->ptrace |= PT_DTRACE; - child->thread.singlestep_syscall = 0; + set_singlestepping(child, 1); child->exit_code = data; /* give it a chance to run. */ wake_up_process(child); @@ -250,23 +231,19 @@ long sys_ptrace(long request, long pid, long addr, long data) break; #endif case PTRACE_FAULTINFO: { - struct ptrace_faultinfo fault; - - fault = ((struct ptrace_faultinfo) - { .is_write = child->thread.err, - .addr = child->thread.cr2 }); - ret = copy_to_user((unsigned long __user *) data, &fault, - sizeof(fault)); + /* Take the info from thread->arch->faultinfo, + * but transfer max. sizeof(struct ptrace_faultinfo). + * On i386, ptrace_faultinfo is smaller! + */ + ret = copy_to_user((unsigned long __user *) data, + &child->thread.arch.faultinfo, + sizeof(struct ptrace_faultinfo)); if(ret) break; break; } - case PTRACE_SIGPENDING: - ret = copy_to_user((unsigned long __user *) data, - &child->pending.signal, - sizeof(child->pending.signal)); - break; +#ifdef PTRACE_LDT case PTRACE_LDT: { struct ptrace_ldt ldt; @@ -282,6 +259,7 @@ long sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; break; } +#endif #ifdef CONFIG_PROC_MM case PTRACE_SWITCH_MM: { struct mm_struct *old = child->mm; @@ -337,15 +315,16 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) if (unlikely(current->audit_context)) { if (!entryexit) - audit_syscall_entry(current, - UPT_SYSCALL_NR(®s->regs), - UPT_SYSCALL_ARG1(®s->regs), - UPT_SYSCALL_ARG2(®s->regs), - UPT_SYSCALL_ARG3(®s->regs), - UPT_SYSCALL_ARG4(®s->regs)); - else - audit_syscall_exit(current, - UPT_SYSCALL_RET(®s->regs)); + audit_syscall_entry(current, + HOST_AUDIT_ARCH, + UPT_SYSCALL_NR(regs), + UPT_SYSCALL_ARG1(regs), + UPT_SYSCALL_ARG2(regs), + UPT_SYSCALL_ARG3(regs), + UPT_SYSCALL_ARG4(regs)); + else audit_syscall_exit(current, + AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), + UPT_SYSCALL_RET(regs)); } /* Fake a debug trap */ @@ -375,14 +354,3 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) current->exit_code = 0; } } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 668df13d8c9d..e89218958f38 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -182,6 +182,7 @@ static int write_sigio_thread(void *unused) int i, n, respond_fd; char c; + signal(SIGWINCH, SIG_IGN); fds = ¤t_poll; while(1){ n = poll(fds->poll, fds->used, -1); diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h index 94c564962378..e48490028111 100644 --- a/arch/um/kernel/skas/include/mode_kern-skas.h +++ b/arch/um/kernel/skas/include/mode_kern-skas.h @@ -18,7 +18,6 @@ extern int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct *p, struct pt_regs *regs); extern void release_thread_skas(struct task_struct *task); -extern void exit_thread_skas(void); extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); extern void init_idle_skas(void); extern void flush_tlb_kernel_range_skas(unsigned long start, diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index f0702c2c7204..96b51dba3471 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -27,9 +27,10 @@ extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, extern int unmap(int fd, void *addr, unsigned long len); extern int protect(int fd, unsigned long addr, unsigned long len, int r, int w, int x); -extern void user_signal(int sig, union uml_pt_regs *regs); +extern void user_signal(int sig, union uml_pt_regs *regs, int pid); extern int new_mm(int from); extern void start_userspace(int cpu); +extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern long execute_syscall_skas(void *r); #endif diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h index c35620385da0..cd6c280482cb 100644 --- a/arch/um/kernel/skas/include/uaccess-skas.h +++ b/arch/um/kernel/skas/include/uaccess-skas.h @@ -18,8 +18,8 @@ ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))) -static inline int __deprecated verify_area_skas(int type, const void * addr, - unsigned long size) +static inline int verify_area_skas(int type, const void * addr, + unsigned long size) { return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index b4ffaaa81241..773cd2b525fc 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -4,6 +4,7 @@ */ #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <errno.h> #include <signal.h> @@ -27,27 +28,37 @@ #include "chan_user.h" #include "signal_user.h" #include "registers.h" +#include "process.h" int is_skas_winch(int pid, int fd, void *data) { - if(pid != os_getpid()) + if(pid != os_getpgrp()) return(0); register_winch_irq(-1, fd, -1, data); return(1); } -static void handle_segv(int pid) +void get_skas_faultinfo(int pid, struct faultinfo * fi) { - struct ptrace_faultinfo fault; int err; - err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); + err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); if(err) - panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", - errno); + panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " + "errno = %d\n", errno); + + /* Special handling for i386, which has different structs */ + if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) + memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, + sizeof(struct faultinfo) - + sizeof(struct ptrace_faultinfo)); +} - segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); +static void handle_segv(int pid, union uml_pt_regs * regs) +{ + get_skas_faultinfo(pid, ®s->skas.faultinfo); + segv(regs->skas.faultinfo, 0, 1, NULL); } /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ @@ -163,7 +174,7 @@ void userspace(union uml_pt_regs *regs) if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: - handle_segv(pid); + handle_segv(pid, regs); break; case SIGTRAP + 0x80: handle_trap(pid, regs, local_using_sysemu); @@ -177,7 +188,7 @@ void userspace(union uml_pt_regs *regs) case SIGBUS: case SIGFPE: case SIGWINCH: - user_signal(WSTOPSIG(status), regs); + user_signal(WSTOPSIG(status), regs, pid); break; default: printk("userspace - child stopped with signal " @@ -190,6 +201,11 @@ void userspace(union uml_pt_regs *regs) } } } +#define INIT_JMP_NEW_THREAD 0 +#define INIT_JMP_REMOVE_SIGSTACK 1 +#define INIT_JMP_CALLBACK 2 +#define INIT_JMP_HALT 3 +#define INIT_JMP_REBOOT 4 void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) @@ -225,7 +241,7 @@ void thread_wait(void *sw, void *fb) *switch_buf = &buf; fork_buf = fb; if(sigsetjmp(buf, 1) == 0) - siglongjmp(*fork_buf, 1); + siglongjmp(*fork_buf, INIT_JMP_REMOVE_SIGSTACK); } void switch_threads(void *me, void *next) @@ -249,23 +265,31 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) sigjmp_buf **switch_buf = switch_buf_ptr; int n; + set_handler(SIGWINCH, (__sighandler_t) sig_handler, + SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM, + SIGVTALRM, -1); + *fork_buf_ptr = &initial_jmpbuf; n = sigsetjmp(initial_jmpbuf, 1); - if(n == 0) - new_thread_proc((void *) stack, new_thread_handler); - else if(n == 1) - remove_sigstack(); - else if(n == 2){ + switch(n){ + case INIT_JMP_NEW_THREAD: + new_thread_proc((void *) stack, new_thread_handler); + break; + case INIT_JMP_REMOVE_SIGSTACK: + remove_sigstack(); + break; + case INIT_JMP_CALLBACK: (*cb_proc)(cb_arg); siglongjmp(*cb_back, 1); - } - else if(n == 3){ + break; + case INIT_JMP_HALT: kmalloc_ok = 0; return(0); - } - else if(n == 4){ + case INIT_JMP_REBOOT: kmalloc_ok = 0; return(1); + default: + panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); } siglongjmp(**switch_buf, 1); } @@ -290,7 +314,7 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) block_signals(); if(sigsetjmp(here, 1) == 0) - siglongjmp(initial_jmpbuf, 2); + siglongjmp(initial_jmpbuf, INIT_JMP_CALLBACK); unblock_signals(); cb_proc = NULL; @@ -301,13 +325,13 @@ void initial_thread_cb_skas(void (*proc)(void *), void *arg) void halt_skas(void) { block_signals(); - siglongjmp(initial_jmpbuf, 3); + siglongjmp(initial_jmpbuf, INIT_JMP_HALT); } void reboot_skas(void) { block_signals(); - siglongjmp(initial_jmpbuf, 4); + siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT); } void switch_mm_skas(int mm_fd) diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 5d096ea63b97..fc71ef295782 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -68,8 +68,11 @@ void new_thread_handler(int sig) * 0 if it just exits */ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); - if(n == 1) + if(n == 1){ + /* Handle any immediate reschedules or signals */ + interrupt_end(); userspace(¤t->thread.regs.regs); + } else do_exit(0); } @@ -83,10 +86,6 @@ void release_thread_skas(struct task_struct *task) { } -void exit_thread_skas(void) -{ -} - void fork_handler(int sig) { change_sig(SIGUSR1, 1); @@ -100,6 +99,8 @@ void fork_handler(int sig) schedule_tail(current->thread.prev_sched); current->thread.prev_sched = NULL; + /* Handle any immediate reschedules or signals */ + interrupt_end(); userspace(¤t->thread.regs.regs); } diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 8e9b46d4702e..0dee1d95c806 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -5,12 +5,15 @@ #include <signal.h> #include <errno.h> -#include "sysdep/ptrace.h" #include "signal_user.h" #include "user_util.h" #include "kern_util.h" #include "task.h" #include "sigcontext.h" +#include "skas.h" +#include "ptrace_user.h" +#include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" void sig_handler_common_skas(int sig, void *sc_ptr) { @@ -31,9 +34,11 @@ void sig_handler_common_skas(int sig, void *sc_ptr) r = &TASK_REGS(get_current())->skas; save_user = r->is_user; r->is_user = 0; - r->fault_addr = SC_FAULT_ADDR(sc); - r->fault_type = SC_FAULT_TYPE(sc); - r->trap_type = SC_TRAP_TYPE(sc); + if ( sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGILL || + sig == SIGTRAP ) { + GET_FAULTINFO_FROM_SC(r->faultinfo, sc); + } change_sig(SIGUSR1, 1); info = &sig_info[sig]; @@ -45,14 +50,17 @@ void sig_handler_common_skas(int sig, void *sc_ptr) r->is_user = save_user; } -void user_signal(int sig, union uml_pt_regs *regs) +extern int ptrace_faultinfo; + +void user_signal(int sig, union uml_pt_regs *regs, int pid) { struct signal_info *info; + int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || + (sig == SIGILL) || (sig == SIGTRAP)); regs->skas.is_user = 1; - regs->skas.fault_addr = 0; - regs->skas.fault_type = 0; - regs->skas.trap_type = 0; + if (segv) + get_skas_faultinfo(pid, ®s->skas.faultinfo); info = &sig_info[sig]; (*info->handler)(sig, regs); diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index f7da9d027672..75195281081e 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -29,9 +29,12 @@ static unsigned long maybe_map(unsigned long virt, int is_write) if(IS_ERR(phys) || (is_write && !pte_write(pte))){ err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); if(err) - return(0); + return(-1UL); phys = um_virt_to_phys(current, virt, NULL); } + if(IS_ERR(phys)) + phys = (void *) -1; + return((unsigned long) phys); } @@ -42,7 +45,7 @@ static int do_op(unsigned long addr, int len, int is_write, int n; addr = maybe_map(addr, is_write); - if(addr == -1) + if(addr == -1UL) return(-1); page = phys_to_page(addr); diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile index 17f5909d60f7..f7b7eba83340 100644 --- a/arch/um/kernel/skas/util/Makefile +++ b/arch/um/kernel/skas/util/Makefile @@ -2,3 +2,4 @@ hostprogs-y := mk_ptregs always := $(hostprogs-y) mk_ptregs-objs := mk_ptregs-$(SUBARCH).o +HOSTCFLAGS_mk_ptregs-$(SUBARCH).o := -I$(objtree)/arch/um diff --git a/arch/um/kernel/skas/util/mk_ptregs-i386.c b/arch/um/kernel/skas/util/mk_ptregs-i386.c index 0788dd05bcac..1f96e1eeb8a7 100644 --- a/arch/um/kernel/skas/util/mk_ptregs-i386.c +++ b/arch/um/kernel/skas/util/mk_ptregs-i386.c @@ -1,8 +1,7 @@ #include <stdio.h> -#include <asm/ptrace.h> -#include <asm/user.h> +#include <user-offsets.h> -#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val)) +#define SHOW(name) printf("#define %s %d\n", #name, name) int main(int argc, char **argv) { @@ -12,28 +11,27 @@ int main(int argc, char **argv) printf("#ifndef __SKAS_PT_REGS_\n"); printf("#define __SKAS_PT_REGS_\n"); printf("\n"); - printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE); - printf("#define HOST_FP_SIZE %d\n", - sizeof(struct user_i387_struct) / sizeof(unsigned long)); - printf("#define HOST_XFP_SIZE %d\n", - sizeof(struct user_fxsr_struct) / sizeof(unsigned long)); + SHOW(HOST_FRAME_SIZE); + SHOW(HOST_FP_SIZE); + SHOW(HOST_XFP_SIZE); + + SHOW(HOST_IP); + SHOW(HOST_SP); + SHOW(HOST_EFLAGS); + SHOW(HOST_EAX); + SHOW(HOST_EBX); + SHOW(HOST_ECX); + SHOW(HOST_EDX); + SHOW(HOST_ESI); + SHOW(HOST_EDI); + SHOW(HOST_EBP); + SHOW(HOST_CS); + SHOW(HOST_SS); + SHOW(HOST_DS); + SHOW(HOST_FS); + SHOW(HOST_ES); + SHOW(HOST_GS); - PRINT_REG("IP", EIP); - PRINT_REG("SP", UESP); - PRINT_REG("EFLAGS", EFL); - PRINT_REG("EAX", EAX); - PRINT_REG("EBX", EBX); - PRINT_REG("ECX", ECX); - PRINT_REG("EDX", EDX); - PRINT_REG("ESI", ESI); - PRINT_REG("EDI", EDI); - PRINT_REG("EBP", EBP); - PRINT_REG("CS", CS); - PRINT_REG("SS", SS); - PRINT_REG("DS", DS); - PRINT_REG("FS", FS); - PRINT_REG("ES", ES); - PRINT_REG("GS", GS); printf("\n"); printf("#endif\n"); return(0); diff --git a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c index 67aee92a70ef..5fccbfe35f78 100644 --- a/arch/um/kernel/skas/util/mk_ptregs-x86_64.c +++ b/arch/um/kernel/skas/util/mk_ptregs-x86_64.c @@ -5,11 +5,10 @@ */ #include <stdio.h> -#define __FRAME_OFFSETS -#include <asm/ptrace.h> +#include <user-offsets.h> -#define PRINT_REG(name, val) \ - printf("#define HOST_%s (%d / sizeof(unsigned long))\n", (name), (val)) +#define SHOW(name) \ + printf("#define %s (%d / sizeof(unsigned long))\n", #name, name) int main(int argc, char **argv) { @@ -18,36 +17,35 @@ int main(int argc, char **argv) printf("\n"); printf("#ifndef __SKAS_PT_REGS_\n"); printf("#define __SKAS_PT_REGS_\n"); - printf("#define HOST_FRAME_SIZE (%d / sizeof(unsigned long))\n", - FRAME_SIZE); - PRINT_REG("RBX", RBX); - PRINT_REG("RCX", RCX); - PRINT_REG("RDI", RDI); - PRINT_REG("RSI", RSI); - PRINT_REG("RDX", RDX); - PRINT_REG("RBP", RBP); - PRINT_REG("RAX", RAX); - PRINT_REG("R8", R8); - PRINT_REG("R9", R9); - PRINT_REG("R10", R10); - PRINT_REG("R11", R11); - PRINT_REG("R12", R12); - PRINT_REG("R13", R13); - PRINT_REG("R14", R14); - PRINT_REG("R15", R15); - PRINT_REG("ORIG_RAX", ORIG_RAX); - PRINT_REG("CS", CS); - PRINT_REG("SS", SS); - PRINT_REG("EFLAGS", EFLAGS); + SHOW(HOST_FRAME_SIZE); + SHOW(HOST_RBX); + SHOW(HOST_RCX); + SHOW(HOST_RDI); + SHOW(HOST_RSI); + SHOW(HOST_RDX); + SHOW(HOST_RBP); + SHOW(HOST_RAX); + SHOW(HOST_R8); + SHOW(HOST_R9); + SHOW(HOST_R10); + SHOW(HOST_R11); + SHOW(HOST_R12); + SHOW(HOST_R13); + SHOW(HOST_R14); + SHOW(HOST_R15); + SHOW(HOST_ORIG_RAX); + SHOW(HOST_CS); + SHOW(HOST_SS); + SHOW(HOST_EFLAGS); #if 0 - PRINT_REG("FS", FS); - PRINT_REG("GS", GS); - PRINT_REG("DS", DS); - PRINT_REG("ES", ES); + SHOW(HOST_FS); + SHOW(HOST_GS); + SHOW(HOST_DS); + SHOW(HOST_ES); #endif - PRINT_REG("IP", RIP); - PRINT_REG("SP", RSP); + SHOW(HOST_IP); + SHOW(HOST_SP); printf("#define HOST_FP_SIZE 0\n"); printf("#define HOST_XFP_SIZE 0\n"); printf("\n"); diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index 42731e04f50f..b7a55251e897 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -17,7 +17,6 @@ #include "linux/utime.h" #include "asm/mman.h" #include "asm/uaccess.h" -#include "asm/ipc.h" #include "kern_util.h" #include "user_util.h" #include "sysdep/syscalls.h" diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index e630438f9e73..f80850091e79 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/config.h" #include "linux/sched.h" #include "linux/kernel.h" #include "linux/module.h" @@ -12,14 +13,14 @@ #include "sysrq.h" #include "user_util.h" -void show_trace(unsigned long * stack) +/* Catch non-i386 SUBARCH's. */ +#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) +void show_trace(struct task_struct *task, unsigned long * stack) { - /* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from - * arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/ unsigned long addr; if (!stack) { - stack = (unsigned long*) &stack; + stack = (unsigned long*) &stack; WARN_ON(1); } @@ -35,6 +36,7 @@ void show_trace(unsigned long * stack) } printk("\n"); } +#endif /* * stack dumps generator - this is used by arch-independent code. @@ -44,7 +46,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(&stack); + show_trace(current, &stack); } EXPORT_SYMBOL(dump_stack); @@ -59,7 +61,11 @@ void show_stack(struct task_struct *task, unsigned long *esp) int i; if (esp == NULL) { - if (task != current) { + if (task != current && task != NULL) { + /* XXX: Isn't this bogus? I.e. isn't this the + * *userspace* stack of this task? If not so, use this + * even when task == current (as in i386). + */ esp = (unsigned long *) KSTK_ESP(task); /* Which one? No actual difference - just coding style.*/ //esp = (unsigned long *) PT_REGS_IP(&task->thread.regs); @@ -77,5 +83,6 @@ void show_stack(struct task_struct *task, unsigned long *esp) printk("%08lx ", *stack++); } - show_trace(esp); + printk("Call Trace: \n"); + show_trace(current, esp); } diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 2461cd73ca87..6516fc52afe0 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -48,8 +48,6 @@ static unsigned long long prev_usecs; static long long delta; /* Deviation per interval */ #endif -#define MILLION 1000000 - void timer_irq(union uml_pt_regs *regs) { unsigned long long ticks = 0; @@ -136,22 +134,6 @@ long um_stime(int __user *tptr) return 0; } -void __udelay(unsigned long usecs) -{ - int i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) ; -} - -void __const_udelay(unsigned long usecs) -{ - int i, n; - - n = (loops_per_jiffy * HZ * usecs) / MILLION; - for(i=0;i<n;i++) ; -} - void timer_handler(int sig, union uml_pt_regs *regs) { local_irq_disable(); diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 47e766e6ba10..c20aef120598 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -23,7 +23,6 @@ #include "kern.h" #include "chan_kern.h" #include "mconsole_kern.h" -#include "2_5compat.h" #include "mem.h" #include "mem_kern.h" @@ -48,7 +47,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, goto good_area; else if(!(vma->vm_flags & VM_GROWSDOWN)) goto out; - else if(!ARCH_IS_STACKGROW(address)) + else if(is_user && !ARCH_IS_STACKGROW(address)) goto out; else if(expand_stack(vma, address)) goto out; @@ -57,10 +56,11 @@ int handle_page_fault(unsigned long address, unsigned long ip, *code_out = SEGV_ACCERR; if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; + + if(!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto out; + page = address & PAGE_MASK; - pgd = pgd_offset(mm, page); - pud = pud_offset(pgd, page); - pmd = pmd_offset(pud, page); do { survive: switch (handle_mm_fault(mm, vma, address, is_write)){ @@ -106,46 +106,24 @@ out_of_memory: goto out; } -LIST_HEAD(physmem_remappers); - -void register_remapper(struct remapper *info) -{ - list_add(&info->list, &physmem_remappers); -} - -static int check_remapped_addr(unsigned long address, int is_write) -{ - struct remapper *remapper; - struct list_head *ele; - __u64 offset; - int fd; - - fd = phys_mapping(__pa(address), &offset); - if(fd == -1) - return(0); - - list_for_each(ele, &physmem_remappers){ - remapper = list_entry(ele, struct remapper, list); - if((*remapper->proc)(fd, address, is_write, offset)) - return(1); - } - - return(0); -} - -unsigned long segv(unsigned long address, unsigned long ip, int is_write, - int is_user, void *sc) +/* + * We give a *copy* of the faultinfo in the regs to segv. + * This must be done, since nesting SEGVs could overwrite + * the info in the regs. A pointer to the info then would + * give us bad data! + */ +unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) { struct siginfo si; void *catcher; int err; + int is_write = FAULT_WRITE(fi); + unsigned long address = FAULT_ADDRESS(fi); if(!is_user && (address >= start_vm) && (address < end_vm)){ flush_tlb_kernel_vm(); return(0); } - else if(check_remapped_addr(address & PAGE_MASK, is_write)) - return(0); else if(current->mm == NULL) panic("Segfault with no mm"); err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); @@ -159,7 +137,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, } else if(current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); - else if(arch_fixup(ip, sc)) + else if(!is_user && arch_fixup(ip, sc)) return(0); if(!is_user) @@ -171,6 +149,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, si.si_errno = 0; si.si_code = BUS_ADRERR; si.si_addr = (void *)address; + current->thread.arch.faultinfo = fi; force_sig_info(SIGBUS, &si, current); } else if(err == -ENOMEM){ @@ -180,22 +159,20 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, else { si.si_signo = SIGSEGV; si.si_addr = (void *) address; - current->thread.cr2 = address; - current->thread.err = is_write; + current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } return(0); } -void bad_segv(unsigned long address, unsigned long ip, int is_write) +void bad_segv(struct faultinfo fi, unsigned long ip) { struct siginfo si; si.si_signo = SIGSEGV; si.si_code = SEGV_ACCERR; - si.si_addr = (void *) address; - current->thread.cr2 = address; - current->thread.err = is_write; + si.si_addr = (void *) FAULT_ADDRESS(fi); + current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } @@ -204,6 +181,7 @@ void relay_signal(int sig, union uml_pt_regs *regs) if(arch_handle_signal(sig, regs)) return; if(!UPT_IS_USER(regs)) panic("Kernel mode signal %d", sig); + current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); force_sig(sig, current); } diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 50a4042a509f..f825a6eda3f5 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -54,23 +54,22 @@ struct { void segv_handler(int sig, union uml_pt_regs *regs) { int index, max; + struct faultinfo * fi = UPT_FAULTINFO(regs); - if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){ - bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), - UPT_FAULT_WRITE(regs)); + if(UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)){ + bad_segv(*fi, UPT_IP(regs)); return; } max = sizeof(segfault_record)/sizeof(segfault_record[0]); index = next_trap_index(max); nsegfaults++; - segfault_record[index].address = UPT_FAULT_ADDR(regs); + segfault_record[index].address = FAULT_ADDRESS(*fi); segfault_record[index].pid = os_getpid(); - segfault_record[index].is_write = UPT_FAULT_WRITE(regs); + segfault_record[index].is_write = FAULT_WRITE(*fi); segfault_record[index].sp = UPT_SP(regs); segfault_record[index].is_user = UPT_IS_USER(regs); - segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), - UPT_IS_USER(regs), regs); + segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs); } void usr2_handler(int sig, union uml_pt_regs *regs) diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile index 3d5177df3504..c3faea21a996 100644 --- a/arch/um/kernel/tt/Makefile +++ b/arch/um/kernel/tt/Makefile @@ -4,6 +4,7 @@ # extra-y := unmap_fin.o +targets := unmap.o clean-files := unmap_tmp.o obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h index 28aaab3448fa..e0ca0e0b2516 100644 --- a/arch/um/kernel/tt/include/mode_kern-tt.h +++ b/arch/um/kernel/tt/include/mode_kern-tt.h @@ -19,7 +19,6 @@ extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct *p, struct pt_regs *regs); extern void release_thread_tt(struct task_struct *task); -extern void exit_thread_tt(void); extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); extern void init_idle_tt(void); extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h index bb69d6b7d022..3fbb5fe26f49 100644 --- a/arch/um/kernel/tt/include/uaccess-tt.h +++ b/arch/um/kernel/tt/include/uaccess-tt.h @@ -33,8 +33,8 @@ extern unsigned long uml_physmem; (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ (under_task_size(addr, size) || is_stack(addr, size)))) -static inline int __deprecated verify_area_tt(int type, const void * addr, - unsigned long size) +static inline int verify_area_tt(int type, const void * addr, + unsigned long size) { return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); } diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c index 92ec85d67c7c..84a9385a8fef 100644 --- a/arch/um/kernel/tt/ksyms.c +++ b/arch/um/kernel/tt/ksyms.c @@ -12,6 +12,7 @@ EXPORT_SYMBOL(__do_copy_to_user); EXPORT_SYMBOL(__do_strncpy_from_user); EXPORT_SYMBOL(__do_strnlen_user); EXPORT_SYMBOL(__do_clear_user); +EXPORT_SYMBOL(clear_user_tt); EXPORT_SYMBOL(tracing_pid); EXPORT_SYMBOL(honeypot); diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c index 74346a04a2b2..bcb8796c3cb1 100644 --- a/arch/um/kernel/tt/mem.c +++ b/arch/um/kernel/tt/mem.c @@ -21,14 +21,8 @@ void before_mem_tt(unsigned long brk_start) remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1); } -#ifdef CONFIG_HOST_2G_2G -#define TOP 0x80000000 -#else -#define TOP 0xc0000000 -#endif - #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) -#define START (TOP - SIZE) +#define START (CONFIG_TOP_ADDR - SIZE) unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, unsigned long *task_size_out) diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index f19f7c18febe..776310fd5b8b 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -32,10 +32,6 @@ void *switch_to_tt(void *prev, void *next, void *last) unsigned long flags; int err, vtalrm, alrm, prof, cpu; char c; - /* jailing and SMP are incompatible, so this doesn't need to be - * made per-cpu - */ - static int reading; from = prev; to = next; @@ -59,14 +55,11 @@ void *switch_to_tt(void *prev, void *next, void *last) c = 0; set_current(to); - reading = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); - reading = 1; - if((from->exit_state == EXIT_ZOMBIE) || - (from->exit_state == EXIT_DEAD)) + if(from->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); @@ -81,8 +74,7 @@ void *switch_to_tt(void *prev, void *next, void *last) * in case it has not already killed itself. */ prev_sched = current->thread.prev_sched; - if((prev_sched->exit_state == EXIT_ZOMBIE) || - (prev_sched->exit_state == EXIT_DEAD)) + if(prev_sched->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); change_sig(SIGVTALRM, vtalrm); @@ -101,14 +93,18 @@ void release_thread_tt(struct task_struct *task) { int pid = task->thread.mode.tt.extern_pid; + /* + * We first have to kill the other process, before + * closing its switch_pipe. Else it might wake up + * and receive "EOF" before we could kill it. + */ if(os_getpid() != pid) os_kill_process(pid, 0); -} -void exit_thread_tt(void) -{ - os_close_file(current->thread.mode.tt.switch_pipe[0]); - os_close_file(current->thread.mode.tt.switch_pipe[1]); + os_close_file(task->thread.mode.tt.switch_pipe[0]); + os_close_file(task->thread.mode.tt.switch_pipe[1]); + /* use switch_pipe as flag: thread is released */ + task->thread.mode.tt.switch_pipe[0] = -1; } void suspend_new_thread(int fd) diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c index e4e7e9c2224c..b218316cfdb2 100644 --- a/arch/um/kernel/tt/syscall_user.c +++ b/arch/um/kernel/tt/syscall_user.c @@ -63,6 +63,10 @@ void do_syscall(void *task, int pid, int local_using_sysemu) UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs); +#ifdef UPT_ORIGGPR2 + UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs); +#endif + if(((unsigned long *) PT_IP(proc_regs) >= &_stext) && ((unsigned long *) PT_IP(proc_regs) <= &_etext)) tracer_panic("I'm tracing myself and I can't get out"); diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 7b5d937e5955..d11e7399d7a1 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -26,6 +26,7 @@ #include "kern_util.h" #include "chan_user.h" #include "ptrace_user.h" +#include "irq_user.h" #include "mode.h" #include "tt.h" @@ -33,7 +34,7 @@ static int tracer_winch[2]; int is_tracer_winch(int pid, int fd, void *data) { - if(pid != tracing_pid) + if(pid != os_getpgrp()) return(0); register_winch_irq(tracer_winch[0], fd, -1, data); @@ -89,8 +90,10 @@ void tracer_panic(char *format, ...) static void tracer_segv(int sig, struct sigcontext sc) { + struct faultinfo fi; + GET_FAULTINFO_FROM_SC(fi, &sc); printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", - SC_FAULT_ADDR(&sc), SC_IP(&sc)); + FAULT_ADDRESS(fi), SC_IP(&sc)); while(1) pause(); } @@ -117,6 +120,7 @@ static int signal_tramp(void *arg) signal(SIGSEGV, (__sighandler_t) sig_handler); set_cmdline("(idle thread)"); set_init_pid(os_getpid()); + init_irq_signals(0); proc = arg; return((*proc)(NULL)); } diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index 92a3820ca543..fc108615beaf 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c @@ -7,6 +7,7 @@ #include <errno.h> #include <signal.h> #include "sysdep/ptrace.h" +#include "sysdep/sigcontext.h" #include "signal_user.h" #include "user_util.h" #include "kern_util.h" @@ -28,6 +29,11 @@ void sig_handler_common_tt(int sig, void *sc_ptr) change_sig(SIGSEGV, 1); r = &TASK_REGS(get_current())->tt; + if ( sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGILL || + sig == SIGTRAP ) { + GET_FAULTINFO_FROM_SC(r->faultinfo, sc); + } save_regs = *r; is_user = user_context(SC_SP(sc)); r->sc = sc; diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 5c49d88eed3d..8736d098f0ee 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -23,9 +23,9 @@ #include "asm/ptrace.h" #include "asm/elf.h" #include "asm/user.h" +#include "asm/setup.h" #include "ubd_user.h" #include "asm/current.h" -#include "asm/setup.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" @@ -42,9 +42,9 @@ #define DEFAULT_COMMAND_LINE "root=98:0" /* Changed in linux_main and setup_arch, which run before SMP is started */ -char command_line[COMMAND_LINE_SIZE] = { 0 }; +static char command_line[COMMAND_LINE_SIZE] = { 0 }; -void add_arg(char *arg) +static void add_arg(char *arg) { if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { printf("add_arg: Too many command line arguments!\n"); @@ -110,12 +110,6 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -pte_t * __bad_pagetable(void) -{ - panic("Someone should implement __bad_pagetable"); - return(NULL); -} - /* Set in linux_main */ unsigned long host_task_size; unsigned long task_size; @@ -449,7 +443,7 @@ void __init setup_arch(char **cmdline_p) { notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); paging_init(); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; setup_hostinfo(); } diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 76eadb309189..dd5355500bdc 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -73,6 +73,8 @@ SECTIONS .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ diff --git a/arch/um/kernel/vmlinux.lds.S b/arch/um/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..1660a769674b --- /dev/null +++ b/arch/um/kernel/vmlinux.lds.S @@ -0,0 +1,6 @@ +#include <linux/config.h> +#ifdef CONFIG_LD_SCRIPT_STATIC +#include "uml.lds.S" +#else +#include "dyn.lds.S" +#endif |