diff options
Diffstat (limited to 'arch/um/kernel')
37 files changed, 567 insertions, 790 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 1119233597a..d8b78a03855 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -3,20 +3,22 @@  # Licensed under the GPL  # -CPPFLAGS_vmlinux.lds := -U$(SUBARCH) -DSTART=$(LDS_START) \ -                        -DELF_ARCH=$(LDS_ELF_ARCH)        \ -                        -DELF_FORMAT=$(LDS_ELF_FORMAT) +CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START)		\ +                        -DELF_ARCH=$(LDS_ELF_ARCH)	\ +                        -DELF_FORMAT=$(LDS_ELF_FORMAT)	\ +			$(LDS_EXTRA)  extra-y := vmlinux.lds  clean-files := -obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ +obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \  	physmem.o process.o ptrace.o reboot.o sigio.o \ -	signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ -	um_arch.o umid.o skas/ +	signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \ +	um_arch.o umid.o maccess.o skas/  obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o  obj-$(CONFIG_GPROF)	+= gprof_syms.o  obj-$(CONFIG_GCOV)	+= gmon_syms.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o  USER_OBJS := config.o diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c index 91ea538e161..1fb12235ab9 100644 --- a/arch/um/kernel/asm-offsets.c +++ b/arch/um/kernel/asm-offsets.c @@ -1 +1 @@ -#include "sysdep/kernel-offsets.h" +#include <sysdep/kernel-offsets.h> diff --git a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in index b7a43feafde..972bf165956 100644 --- a/arch/um/kernel/config.c.in +++ b/arch/um/kernel/config.c.in @@ -5,7 +5,7 @@  #include <stdio.h>  #include <stdlib.h> -#include "init.h" +#include <init.h>  static __initdata const char *config[] = {  "CONFIG" diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index a3cab6d3ae0..adde088aeef 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -14,8 +14,6 @@ SECTIONS    __binary_start = .;    . = ALIGN(4096);		/* Init code and data */    _text = .; -  _stext = .; -  __init_begin = .;    INIT_TEXT_SECTION(PAGE_SIZE)    . = ALIGN(PAGE_SIZE); @@ -67,6 +65,7 @@ SECTIONS    } =0x90909090    .plt            : { *(.plt) }    .text           : { +    _stext = .;      TEXT_TEXT      SCHED_TEXT      LOCK_TEXT @@ -89,9 +88,11 @@ SECTIONS    .kstrtab : { *(.kstrtab) } -  #include "asm/common.lds.S" +  #include <asm/common.lds.S> +  __init_begin = .;    init.data : { INIT_DATA } +  __init_end = .;    /* Ensure the __preinit_array_start label is properly aligned.  We       could instead move the label definition inside the section, but @@ -155,6 +156,7 @@ SECTIONS     . = ALIGN(32 / 8);    . = ALIGN(32 / 8);    } +   __bss_stop = .;    _end = .;    PROVIDE (end = .); diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c new file mode 100644 index 00000000000..4a0800bc37b --- /dev/null +++ b/arch/um/kernel/early_printk.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/init.h> +#include <os.h> + +static void early_console_write(struct console *con, const char *s, unsigned int n) +{ +	um_early_printk(s, n); +} + +static struct console early_console_dev = { +	.name = "earlycon", +	.write = early_console_write, +	.flags = CON_BOOT, +	.index = -1, +}; + +static int __init setup_early_printk(char *buf) +{ +	if (!early_console) { +		early_console = &early_console_dev; +		register_console(&early_console_dev); +	} +	return 0; +} + +early_param("earlyprintk", setup_early_printk); diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 340268be00b..0d7103c9eff 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -3,20 +3,19 @@   * Licensed under the GPL   */ -#include "linux/stddef.h" -#include "linux/fs.h" -#include "linux/smp_lock.h" -#include "linux/ptrace.h" -#include "linux/sched.h" -#include "linux/slab.h" -#include "asm/current.h" -#include "asm/processor.h" -#include "asm/uaccess.h" -#include "as-layout.h" -#include "mem_user.h" -#include "skas.h" -#include "os.h" -#include "internal.h" +#include <linux/stddef.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/current.h> +#include <asm/processor.h> +#include <asm/uaccess.h> +#include <as-layout.h> +#include <mem_user.h> +#include <skas.h> +#include <os.h>  void flush_thread(void)  { @@ -33,56 +32,19 @@ void flush_thread(void)  		       "err = %d\n", ret);  		force_sig(SIGKILL, current);  	} +	get_safe_registers(current_pt_regs()->regs.gp, +			   current_pt_regs()->regs.fp);  	__switch_mm(¤t->mm->context.id);  }  void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)  { -	set_fs(USER_DS);  	PT_REGS_IP(regs) = eip;  	PT_REGS_SP(regs) = esp; -} - -static long execve1(const char *file, -		    const char __user *const __user *argv, -		    const char __user *const __user *env) -{ -	long error; - -	error = do_execve(file, argv, env, ¤t->thread.regs); -	if (error == 0) { -		task_lock(current); -		current->ptrace &= ~PT_DTRACE; +	current->ptrace &= ~PT_DTRACE;  #ifdef SUBARCH_EXECVE1 -		SUBARCH_EXECVE1(¤t->thread.regs.regs); +	SUBARCH_EXECVE1(regs->regs);  #endif -		task_unlock(current); -	} -	return error; -} - -long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env) -{ -	long err; - -	err = execve1(file, argv, env); -	if (!err) -		UML_LONGJMP(current->thread.exec_buf, 1); -	return err; -} - -long sys_execve(const char __user *file, const char __user *const __user *argv, -		const char __user *const __user *env) -{ -	long error; -	char *filename; - -	filename = getname(file); -	error = PTR_ERR(filename); -	if (IS_ERR(filename)) goto out; -	error = execve1(filename, argv, env); -	putname(filename); - out: -	return error;  } +EXPORT_SYMBOL(start_thread); diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 829df49dee9..41ebbfebb33 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -40,9 +40,11 @@ static ssize_t exitcode_proc_write(struct file *file,  		const char __user *buffer, size_t count, loff_t *pos)  {  	char *end, buf[sizeof("nnnnn\0")]; +	size_t size;  	int tmp; -	if (copy_from_user(buf, buffer, count)) +	size = min(count, sizeof(buf)); +	if (copy_from_user(buf, buffer, size))  		return -EFAULT;  	tmp = simple_strtol(buf, &end, 0); diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c index 72eccd2a411..1bf61266da8 100644 --- a/arch/um/kernel/gmon_syms.c +++ b/arch/um/kernel/gmon_syms.c @@ -3,22 +3,7 @@   * Licensed under the GPL   */ -#include "linux/module.h" +#include <linux/module.h>  extern void __bb_init_func(void *)  __attribute__((weak));  EXPORT_SYMBOL(__bb_init_func); - -/* - * This is defined (and referred to in profiling stub code) only by some GCC - * versions in libgcov. - * - * Since SuSE backported the fix, we cannot handle it depending on GCC version. - * So, unconditionally export it. But also give it a weak declaration, which - * will be overridden by any other one. - */ - -extern void __gcov_init(void *) __attribute__((weak)); -EXPORT_SYMBOL(__gcov_init); - -extern void __gcov_merge_add(void *) __attribute__((weak)); -EXPORT_SYMBOL(__gcov_merge_add); diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c index e2f043d0de6..74ddb44288a 100644 --- a/arch/um/kernel/gprof_syms.c +++ b/arch/um/kernel/gprof_syms.c @@ -3,7 +3,7 @@   * Licensed under the GPL   */ -#include "linux/module.h" +#include <linux/module.h>  extern void mcount(void);  EXPORT_SYMBOL(mcount); diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c deleted file mode 100644 index ddc9698b66e..00000000000 --- a/arch/um/kernel/init_task.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com) - * Licensed under the GPL - */ - -#include "linux/sched.h" -#include "linux/init_task.h" -#include "linux/fs.h" -#include "linux/module.h" -#include "linux/mqueue.h" -#include "asm/uaccess.h" - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ - -struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_task); - -/* - * Initial thread structure. - * - * We need to make sure that this is aligned due to the - * way process stacks are handled. This is done by having a special - * "init_task" linker map entry.. - */ - -union thread_union init_thread_union __init_task_data = -	{ INIT_THREAD_INFO(init_task) }; - -union thread_union cpu0_irqstack -	__attribute__((__section__(".data..init_irqstack"))) = -		{ INIT_THREAD_INFO(init_task) }; diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c index d386c75c88e..55cead809b1 100644 --- a/arch/um/kernel/initrd.c +++ b/arch/um/kernel/initrd.c @@ -3,16 +3,16 @@   * Licensed under the GPL   */ -#include "linux/init.h" -#include "linux/bootmem.h" -#include "linux/initrd.h" -#include "asm/types.h" -#include "initrd.h" -#include "init.h" -#include "os.h" +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/initrd.h> +#include <asm/types.h> +#include <init.h> +#include <os.h>  /* Changed by uml_initrd_setup, which is a setup */  static char *initrd __initdata = NULL; +static int load_initrd(char *filename, void *buf, int size);  static int __init read_initrd(void)  { @@ -62,7 +62,7 @@ __uml_setup("initrd=", uml_initrd_setup,  "    name of the file containing the image.\n\n"  ); -int load_initrd(char *filename, void *buf, int size) +static int load_initrd(char *filename, void *buf, int size)  {  	int fd, n; diff --git a/arch/um/kernel/internal.h b/arch/um/kernel/internal.h deleted file mode 100644 index 5bf97db24a0..00000000000 --- a/arch/um/kernel/internal.h +++ /dev/null @@ -1 +0,0 @@ -extern long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env); diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 3f0ac9e0c96..1d8505b1e29 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -5,61 +5,17 @@   *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar   */ -#include "linux/cpumask.h" -#include "linux/hardirq.h" -#include "linux/interrupt.h" -#include "linux/kernel_stat.h" -#include "linux/module.h" -#include "linux/sched.h" -#include "linux/seq_file.h" -#include "linux/slab.h" -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" - -/* - * Generic, controller-independent functions: - */ - -int show_interrupts(struct seq_file *p, void *v) -{ -	int i = *(loff_t *) v, j; -	struct irqaction * action; -	unsigned long flags; - -	if (i == 0) { -		seq_printf(p, "           "); -		for_each_online_cpu(j) -			seq_printf(p, "CPU%d       ",j); -		seq_putc(p, '\n'); -	} - -	if (i < NR_IRQS) { -		raw_spin_lock_irqsave(&irq_desc[i].lock, flags); -		action = irq_desc[i].action; -		if (!action) -			goto skip; -		seq_printf(p, "%3d: ",i); -#ifndef CONFIG_SMP -		seq_printf(p, "%10u ", kstat_irqs(i)); -#else -		for_each_online_cpu(j) -			seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); -#endif -		seq_printf(p, " %14s", irq_desc[i].chip->name); -		seq_printf(p, "  %s", action->name); - -		for (action=action->next; action; action = action->next) -			seq_printf(p, ", %s", action->name); - -		seq_putc(p, '\n'); -skip: -		raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); -	} else if (i == NR_IRQS) -		seq_putc(p, '\n'); - -	return 0; -} +#include <linux/cpumask.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h>  /*   * This list is accessed under irq_lock, except in sigio_handler, @@ -74,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds;  extern void free_irqs(void); -void sigio_handler(int sig, struct uml_pt_regs *regs) +void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)  {  	struct irq_fd *irq_fd;  	int n; @@ -302,6 +258,7 @@ void deactivate_fd(int fd, int irqnum)  	ignore_sigio_fd(fd);  } +EXPORT_SYMBOL(deactivate_fd);  /*   * Called just before shutdown in order to provide a clean exec @@ -340,6 +297,13 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)  	return 1;  } +void um_free_irq(unsigned int irq, void *dev) +{ +	free_irq_by_irq_and_dev(irq, dev); +	free_irq(irq, dev); +} +EXPORT_SYMBOL(um_free_irq); +  int um_request_irq(unsigned int irq, int fd, int type,  		   irq_handler_t handler,  		   unsigned long irqflags, const char * devname, @@ -360,42 +324,40 @@ EXPORT_SYMBOL(um_request_irq);  EXPORT_SYMBOL(reactivate_fd);  /* - * irq_chip must define (startup || enable) && - * (shutdown || disable) && end + * irq_chip must define at least enable/disable and ack when + * the edge handler is used.   */ -static void dummy(unsigned int irq) +static void dummy(struct irq_data *d)  {  }  /* This is used for everything else than the timer. */  static struct irq_chip normal_irq_type = {  	.name = "SIGIO", -	.release = free_irq_by_irq_and_dev, -	.disable = dummy, -	.enable = dummy, -	.ack = dummy, -	.end = dummy +	.irq_disable = dummy, +	.irq_enable = dummy, +	.irq_ack = dummy, +	.irq_mask = dummy, +	.irq_unmask = dummy,  };  static struct irq_chip SIGVTALRM_irq_type = {  	.name = "SIGVTALRM", -	.release = free_irq_by_irq_and_dev, -	.shutdown = dummy, /* never called */ -	.disable = dummy, -	.enable = dummy, -	.ack = dummy, -	.end = dummy +	.irq_disable = dummy, +	.irq_enable = dummy, +	.irq_ack = dummy, +	.irq_mask = dummy, +	.irq_unmask = dummy,  };  void __init init_IRQ(void)  {  	int i; -	set_irq_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); +	irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq); -	for (i = 1; i < NR_IRQS; i++) { -		set_irq_chip_and_handler(i, &normal_irq_type, handle_edge_irq); -	} +	for (i = 1; i < NR_IRQS; i++) +		irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);  }  /* diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 0ae0dfcfbff..543c0475693 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -3,33 +3,11 @@   * Licensed under the GPL   */ -#include "linux/module.h" -#include "linux/syscalls.h" -#include "asm/tlbflush.h" -#include "asm/uaccess.h" -#include "as-layout.h" -#include "kern_util.h" -#include "mem_user.h" -#include "os.h" +#include <linux/module.h> +#include <os.h> -EXPORT_SYMBOL(uml_physmem);  EXPORT_SYMBOL(set_signals);  EXPORT_SYMBOL(get_signals); -EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(sys_waitpid); -EXPORT_SYMBOL(flush_tlb_range); - -EXPORT_SYMBOL(high_physmem); -EXPORT_SYMBOL(empty_zero_page); -EXPORT_SYMBOL(handle_page_fault); -EXPORT_SYMBOL(find_iomem); - -EXPORT_SYMBOL(strnlen_user); -EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(copy_to_user); -EXPORT_SYMBOL(copy_from_user); -EXPORT_SYMBOL(clear_user); -EXPORT_SYMBOL(uml_strdup);  EXPORT_SYMBOL(os_stat_fd);  EXPORT_SYMBOL(os_stat_file); @@ -57,24 +35,10 @@ EXPORT_SYMBOL(os_connect_socket);  EXPORT_SYMBOL(os_accept_connection);  EXPORT_SYMBOL(os_rcv_fd);  EXPORT_SYMBOL(run_helper); -EXPORT_SYMBOL(start_thread);  EXPORT_SYMBOL(os_major);  EXPORT_SYMBOL(os_minor);  EXPORT_SYMBOL(os_makedev);  EXPORT_SYMBOL(add_sigio_fd);  EXPORT_SYMBOL(ignore_sigio_fd); -EXPORT_SYMBOL(deactivate_fd);  EXPORT_SYMBOL(sigio_broken); - -#ifdef CONFIG_SMP - -/* required for SMP */ - -extern void __write_lock_failed(rwlock_t *rw); -EXPORT_SYMBOL(__write_lock_failed); - -extern void __read_lock_failed(rwlock_t *rw); -EXPORT_SYMBOL(__read_lock_failed); - -#endif diff --git a/arch/um/kernel/maccess.c b/arch/um/kernel/maccess.c new file mode 100644 index 00000000000..1f3d5c4910d --- /dev/null +++ b/arch/um/kernel/maccess.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/uaccess.h> +#include <linux/kernel.h> +#include <os.h> + +long probe_kernel_read(void *dst, const void *src, size_t size) +{ +	void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE); + +	if ((unsigned long)src < PAGE_SIZE || size <= 0) +		return -EFAULT; + +	if (os_mincore(psrc, size + src - psrc) <= 0) +		return -EFAULT; + +	return __probe_kernel_read(dst, src, size); +} diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 8137ccc9635..8636e905426 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -4,6 +4,7 @@   */  #include <linux/stddef.h> +#include <linux/module.h>  #include <linux/bootmem.h>  #include <linux/highmem.h>  #include <linux/mm.h> @@ -11,15 +12,16 @@  #include <linux/slab.h>  #include <asm/fixmap.h>  #include <asm/page.h> -#include "as-layout.h" -#include "init.h" -#include "kern.h" -#include "kern_util.h" -#include "mem_user.h" -#include "os.h" +#include <as-layout.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h>  /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */  unsigned long *empty_zero_page = NULL; +EXPORT_SYMBOL(empty_zero_page);  /* allocated in paging_init and unchanged thereafter */  static unsigned long *empty_bad_page = NULL; @@ -40,17 +42,12 @@ static unsigned long brk_end;  static void setup_highmem(unsigned long highmem_start,  			  unsigned long highmem_len)  { -	struct page *page;  	unsigned long highmem_pfn;  	int i;  	highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; -	for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) { -		page = &mem_map[highmem_pfn + i]; -		ClearPageReserved(page); -		init_page_count(page); -		__free_page(page); -	} +	for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) +		free_highmem_page(&mem_map[highmem_pfn + i]);  }  #endif @@ -68,21 +65,14 @@ void __init mem_init(void)  	uml_reserved = brk_end;  	/* this will put all low memory onto the freelists */ -	totalram_pages = free_all_bootmem(); +	free_all_bootmem();  	max_low_pfn = totalram_pages;  #ifdef CONFIG_HIGHMEM -	totalhigh_pages = highmem >> PAGE_SHIFT; -	totalram_pages += totalhigh_pages; +	setup_highmem(end_iomem, highmem);  #endif -	num_physpages = totalram_pages;  	max_pfn = totalram_pages; -	printk(KERN_INFO "Memory: %luk available\n", -	       nr_free_pages() << (PAGE_SHIFT-10)); +	mem_init_print_info(NULL);  	kmalloc_ok = 1; - -#ifdef CONFIG_HIGHMEM -	setup_highmem(end_iomem, highmem); -#endif  }  /* @@ -252,15 +242,7 @@ void free_initmem(void)  #ifdef CONFIG_BLK_DEV_INITRD  void free_initrd_mem(unsigned long start, unsigned long end)  { -	if (start < end) -		printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", -		       (end - start) >> 10); -	for (; start < end; start += PAGE_SIZE) { -		ClearPageReserved(virt_to_page(start)); -		init_page_count(virt_to_page(start)); -		free_page(start); -		totalram_pages++; -	} +	free_reserved_area((void *)start, (void *)end, -1, "initrd");  }  #endif @@ -297,8 +279,12 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)  	struct page *pte;  	pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); -	if (pte) -		pgtable_page_ctor(pte); +	if (!pte) +		return NULL; +	if (!pgtable_page_ctor(pte)) { +		__free_page(pte); +		return NULL; +	}  	return pte;  } diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index a1a9090254c..30fdd5d0067 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -3,20 +3,22 @@   * Licensed under the GPL   */ -#include "linux/bootmem.h" -#include "linux/mm.h" -#include "linux/pfn.h" -#include "asm/page.h" -#include "as-layout.h" -#include "init.h" -#include "kern.h" -#include "mem_user.h" -#include "os.h" +#include <linux/module.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <linux/pfn.h> +#include <asm/page.h> +#include <as-layout.h> +#include <init.h> +#include <kern.h> +#include <mem_user.h> +#include <os.h>  static int physmem_fd = -1;  /* Changed during early boot */  unsigned long high_physmem; +EXPORT_SYMBOL(high_physmem);  extern unsigned long long physmem_size; @@ -101,6 +103,7 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,  	 */  	os_seek_file(physmem_fd, __pa(&__syscall_stub_start));  	os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE); +	os_fsync_file(physmem_fd);  	bootmap_size = init_bootmem(pfn, pfn + delta);  	free_bootmem(__pa(reserve_end) + bootmap_size, @@ -184,6 +187,7 @@ unsigned long find_iomem(char *driver, unsigned long *len_out)  	return 0;  } +EXPORT_SYMBOL(find_iomem);  static int setup_iomem(void)  { diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index fab4371184f..f17bca8ed2c 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -18,14 +18,15 @@  #include <linux/seq_file.h>  #include <linux/tick.h>  #include <linux/threads.h> +#include <linux/tracehook.h>  #include <asm/current.h>  #include <asm/pgtable.h> +#include <asm/mmu_context.h>  #include <asm/uaccess.h> -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "skas.h" -#include "tlb.h" +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h>  /*   * This is a per-cpu array.  A processor only modifies its entry and it only @@ -68,17 +69,6 @@ unsigned long alloc_stack(int order, int atomic)  	return page;  } -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ -	int pid; - -	current->thread.request.u.thread.proc = fn; -	current->thread.request.u.thread.arg = arg; -	pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, -		      ¤t->thread.regs, 0, NULL, NULL); -	return pid; -} -  static inline void set_current(struct task_struct *task)  {  	cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) @@ -87,47 +77,34 @@ static inline void set_current(struct task_struct *task)  extern void arch_switch_to(struct task_struct *to); -void *_switch_to(void *prev, void *next, void *last) +void *__switch_to(struct task_struct *from, struct task_struct *to)  { -	struct task_struct *from = prev; -	struct task_struct *to = next; -  	to->thread.prev_sched = from;  	set_current(to); -	do { -		current->thread.saved_task = NULL; - -		switch_threads(&from->thread.switch_buf, -			       &to->thread.switch_buf); - -		arch_switch_to(current); - -		if (current->thread.saved_task) -			show_regs(&(current->thread.regs)); -		to = current->thread.saved_task; -		from = current; -	} while (current->thread.saved_task); +	switch_threads(&from->thread.switch_buf, &to->thread.switch_buf); +	arch_switch_to(current);  	return current->thread.prev_sched; -  }  void interrupt_end(void)  {  	if (need_resched())  		schedule(); -	if (test_tsk_thread_flag(current, TIF_SIGPENDING)) +	if (test_thread_flag(TIF_SIGPENDING))  		do_signal(); +	if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) +		tracehook_notify_resume(¤t->thread.regs);  }  void exit_thread(void)  {  } -void *get_current(void) +int get_current_pid(void)  { -	return current; +	return task_pid_nr(current);  }  /* @@ -147,16 +124,10 @@ void new_thread_handler(void)  	arg = current->thread.request.u.thread.arg;  	/* -	 * The return value is 1 if the kernel thread execs a process, -	 * 0 if it just exits +	 * callback returns only if the kernel thread execs a process  	 */ -	n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); -	if (n == 1) { -		/* Handle any immediate reschedules or signals */ -		interrupt_end(); -		userspace(¤t->thread.regs.regs); -	} -	else do_exit(0); +	n = fn(arg); +	userspace(¤t->thread.regs.regs);  }  /* Called magically, see new_thread_handler above */ @@ -175,41 +146,38 @@ void fork_handler(void)  	current->thread.prev_sched = NULL; -	/* Handle any immediate reschedules or signals */ -	interrupt_end(); -  	userspace(¤t->thread.regs.regs);  }  int copy_thread(unsigned long clone_flags, unsigned long sp, -		unsigned long stack_top, struct task_struct * p, -		struct pt_regs *regs) +		unsigned long arg, struct task_struct * p)  {  	void (*handler)(void); +	int kthread = current->flags & PF_KTHREAD;  	int ret = 0;  	p->thread = (struct thread_struct) INIT_THREAD; -	if (current->thread.forking) { -	  	memcpy(&p->thread.regs.regs, ®s->regs, +	if (!kthread) { +	  	memcpy(&p->thread.regs.regs, current_pt_regs(),  		       sizeof(p->thread.regs.regs)); -		REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0); +		PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);  		if (sp != 0)  			REGS_SP(p->thread.regs.regs.gp) = sp;  		handler = fork_handler;  		arch_copy_thread(¤t->thread.arch, &p->thread.arch); -	} -	else { -		get_safe_registers(p->thread.regs.regs.gp); -		p->thread.request.u.thread = current->thread.request.u.thread; +	} else { +		get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); +		p->thread.request.u.thread.proc = (int (*)(void *))sp; +		p->thread.request.u.thread.arg = (void *)arg;  		handler = new_thread_handler;  	}  	new_thread(task_stack_page(p), &p->thread.switch_buf, handler); -	if (current->thread.forking) { +	if (!kthread) {  		clear_flushed_tls(p);  		/* @@ -231,31 +199,14 @@ void initial_thread_cb(void (*proc)(void *), void *arg)  	kmalloc_ok = save_kmalloc_ok;  } -void default_idle(void) +void arch_cpu_idle(void)  {  	unsigned long long nsecs; -	while (1) { -		/* endless idle loop with no priority at all */ - -		/* -		 * although we are an idle CPU, we do not want to -		 * get into the scheduler unnecessarily. -		 */ -		if (need_resched()) -			schedule(); - -		tick_nohz_stop_sched_tick(1); -		nsecs = disable_timer(); -		idle_sleep(nsecs); -		tick_nohz_restart_sched_tick(); -	} -} - -void cpu_idle(void) -{  	cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); -	default_idle(); +	nsecs = disable_timer(); +	idle_sleep(nsecs); +	local_irq_enable();  }  int __cant_sleep(void) { @@ -286,6 +237,7 @@ char *uml_strdup(const char *string)  {  	return kstrdup(string, GFP_KERNEL);  } +EXPORT_SYMBOL(uml_strdup);  int copy_to_user_proc(void __user *to, void *from, int size)  { @@ -407,7 +359,7 @@ int singlestepping(void * t)  /*   * 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 + * in their asm/exec.h   * As this is included in UML from asm-um/system-generic.h,   * we can use it to behave as the subarch does.   */ diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 701b672c112..694d551c889 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -3,11 +3,12 @@   * Licensed under the GPL   */ -#include "linux/audit.h" -#include "linux/ptrace.h" -#include "linux/sched.h" -#include "asm/uaccess.h" -#include "skas_ptrace.h" +#include <linux/audit.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/tracehook.h> +#include <asm/uaccess.h> +#include <skas_ptrace.h> @@ -50,23 +51,11 @@ long arch_ptrace(struct task_struct *child, long request,  	void __user *vp = p;  	switch (request) { -	/* read word at location addr. */ -	case PTRACE_PEEKTEXT: -	case PTRACE_PEEKDATA: -		ret = generic_ptrace_peekdata(child, addr, data); -		break; -  	/* read the word at location addr in the USER area. */  	case PTRACE_PEEKUSR:  		ret = peek_user(child, addr, data);  		break; -	/* write the word at location addr. */ -	case PTRACE_POKETEXT: -	case PTRACE_POKEDATA: -		ret = generic_ptrace_pokedata(child, addr, data); -		break; -  	/* write the word at location addr in the USER area */  	case PTRACE_POKEUSR:  		ret = poke_user(child, addr, data); @@ -107,16 +96,6 @@ long arch_ptrace(struct task_struct *child, long request,  		break;  	}  #endif -#ifdef PTRACE_GETFPREGS -	case PTRACE_GETFPREGS: /* Get the child FPU state. */ -		ret = get_fpregs(vp, child); -		break; -#endif -#ifdef PTRACE_SETFPREGS -	case PTRACE_SETFPREGS: /* Set the child FPU state. */ -		ret = set_fpregs(vp, child); -		break; -#endif  	case PTRACE_GET_THREAD_AREA:  		ret = ptrace_get_thread_area(child, addr, vp);  		break; @@ -154,12 +133,6 @@ long arch_ptrace(struct task_struct *child, long request,  		break;  	}  #endif -#ifdef PTRACE_ARCH_PRCTL -	case PTRACE_ARCH_PRCTL: -		/* XXX Calls ptrace on the host - needs some SMP thinking */ -		ret = arch_prctl(child, data, (void __user *) addr); -		break; -#endif  	default:  		ret = ptrace_request(child, request, addr, data);  		if (ret == -EIO) @@ -190,50 +163,36 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,   * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and   * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check   */ -void syscall_trace(struct uml_pt_regs *regs, int entryexit) +void syscall_trace_enter(struct pt_regs *regs)  { -	int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; -	int tracesysgood; - -	if (unlikely(current->audit_context)) { -		if (!entryexit) -			audit_syscall_entry(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(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), -					UPT_SYSCALL_RET(regs)); -	} - -	/* Fake a debug trap */ -	if (is_singlestep) -		send_sigtrap(current, regs, 0); +	audit_syscall_entry(HOST_AUDIT_ARCH, +			    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));  	if (!test_thread_flag(TIF_SYSCALL_TRACE))  		return; -	if (!(current->ptrace & PT_PTRACED)) -		return; +	tracehook_report_syscall_entry(regs); +} -	/* -	 * the 0x80 provides a way for the tracing parent to distinguish -	 * between a syscall stop and SIGTRAP delivery -	 */ -	tracesysgood = (current->ptrace & PT_TRACESYSGOOD); -	ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); +void syscall_trace_leave(struct pt_regs *regs) +{ +	int ptraced = current->ptrace; -	if (entryexit) /* force do_signal() --> is_syscall() */ -		set_thread_flag(TIF_SIGPENDING); +	audit_syscall_exit(regs); -	/* -	 * this isn't the same as continuing with a signal, but it will do -	 * for normal use.  strace only continues with a signal if the -	 * stopping signal is not SIGTRAP.  -brl -	 */ -	if (current->exit_code) { -		send_sig(current->exit_code, current, 1); -		current->exit_code = 0; -	} +	/* Fake a debug trap */ +	if (ptraced & PT_DTRACE) +		send_sigtrap(current, ®s->regs, 0); + +	if (!test_thread_flag(TIF_SYSCALL_TRACE)) +		return; + +	tracehook_report_syscall_exit(regs, 0); +	/* force do_signal() --> is_syscall() */ +	if (ptraced & PT_PTRACED) +		set_thread_flag(TIF_SIGPENDING);  } diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 869bec9f251..ced8903921a 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -3,11 +3,13 @@   * Licensed under the GPL   */ -#include "linux/sched.h" -#include "linux/slab.h" -#include "kern_util.h" -#include "os.h" -#include "skas.h" +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/oom.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h>  void (*pm_power_off)(void); @@ -20,16 +22,20 @@ static void kill_off_processes(void)  		os_kill_ptraced_process(userspace_pid[0], 1);  	else {  		struct task_struct *p; -		int pid, me; +		int pid; -		me = os_getpid(); +		read_lock(&tasklist_lock);  		for_each_process(p) { -			if (p->mm == NULL) -				continue; +			struct task_struct *t; -			pid = p->mm->context.id.u.pid; +			t = find_lock_task_mm(p); +			if (!t) +				continue; +			pid = t->mm->context.id.u.pid; +			task_unlock(t);  			os_kill_ptraced_process(pid, 1);  		} +		read_unlock(&tasklist_lock);  	}  } diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index 2b272b63b51..b5e0cbb3438 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c @@ -4,9 +4,9 @@   */  #include <linux/interrupt.h> -#include "irq_kern.h" -#include "os.h" -#include "sigio.h" +#include <irq_kern.h> +#include <os.h> +#include <sigio.h>  /* Protected by sigio_lock() called from write_sigio_workaround */  static int sigio_irq_fd = -1; @@ -25,8 +25,7 @@ int write_sigio_irq(int fd)  	int err;  	err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, -			     IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio", -			     NULL); +			     0, "write sigio", NULL);  	if (err) {  		printk(KERN_ERR "write_sigio_irq : um_request_irq failed, "  		       "err = %d\n", err); diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index b5c094c4ade..f57e02e7910 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -9,29 +9,25 @@  #include <asm/siginfo.h>  #include <asm/signal.h>  #include <asm/unistd.h> -#include "frame_kern.h" -#include "kern_util.h" -#include <sysdep/sigcontext.h> +#include <frame_kern.h> +#include <kern_util.h>  EXPORT_SYMBOL(block_signals);  EXPORT_SYMBOL(unblock_signals); -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -  /*   * OK, we're invoking a handler   */ -static int handle_signal(struct pt_regs *regs, unsigned long signr, -			 struct k_sigaction *ka, siginfo_t *info, -			 sigset_t *oldset) +static void handle_signal(struct pt_regs *regs, unsigned long signr, +			 struct k_sigaction *ka, struct siginfo *info)  { +	sigset_t *oldset = sigmask_to_save(); +	int singlestep = 0;  	unsigned long sp;  	int err; -	/* Always make any pending restarted system calls return -EINTR */ -	current_thread_info()->restart_block.fn = do_no_restart_syscall; +	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) +		singlestep = 1;  	/* Did we come from a system call? */  	if (PT_REGS_SYSCALL_NR(regs) >= 0) { @@ -66,51 +62,22 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,  #endif  		err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset); -	if (err) { -		spin_lock_irq(¤t->sighand->siglock); -		current->blocked = *oldset; -		recalc_sigpending(); -		spin_unlock_irq(¤t->sighand->siglock); +	if (err)  		force_sigsegv(signr, current); -	} else { -		spin_lock_irq(¤t->sighand->siglock); -		sigorsets(¤t->blocked, ¤t->blocked, -			  &ka->sa.sa_mask); -		if (!(ka->sa.sa_flags & SA_NODEFER)) -			sigaddset(¤t->blocked, signr); -		recalc_sigpending(); -		spin_unlock_irq(¤t->sighand->siglock); -	} - -	return err; +	else +		signal_delivered(signr, info, ka, regs, singlestep);  }  static int kern_do_signal(struct pt_regs *regs)  {  	struct k_sigaction ka_copy; -	siginfo_t info; -	sigset_t *oldset; +	struct siginfo info;  	int sig, handled_sig = 0; -	if (test_thread_flag(TIF_RESTORE_SIGMASK)) -		oldset = ¤t->saved_sigmask; -	else -		oldset = ¤t->blocked; -  	while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {  		handled_sig = 1;  		/* Whee!  Actually deliver the signal.  */ -		if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) { -			/* -			 * a signal was successfully delivered; the saved -			 * sigmask will have been stored in the signal frame, -			 * and will be restored by sigreturn, so we can simply -			 * clear the TIF_RESTORE_SIGMASK flag -			 */ -			if (test_thread_flag(TIF_RESTORE_SIGMASK)) -				clear_thread_flag(TIF_RESTORE_SIGMASK); -			break; -		} +		handle_signal(regs, sig, &ka_copy, &info);  	}  	/* Did we come from a system call? */ @@ -146,10 +113,8 @@ static int kern_do_signal(struct pt_regs *regs)  	 * if there's no signal to deliver, we just put the saved sigmask  	 * back  	 */ -	if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { -		clear_thread_flag(TIF_RESTORE_SIGMASK); -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -	} +	if (!handled_sig) +		restore_saved_sigmask();  	return handled_sig;  } @@ -157,26 +122,3 @@ int do_signal(void)  {  	return kern_do_signal(¤t->thread.regs);  } - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys_sigsuspend(int history0, int history1, old_sigset_t mask) -{ -	mask &= _BLOCKABLE; -	spin_lock_irq(¤t->sighand->siglock); -	current->saved_sigmask = current->blocked; -	siginitset(¤t->blocked, mask); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); - -	current->state = TASK_INTERRUPTIBLE; -	schedule(); -	set_thread_flag(TIF_RESTORE_SIGMASK); -	return -ERESTARTNOHAND; -} - -long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) -{ -	return do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs)); -} diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 2c8583c1a34..289771dadf8 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -7,11 +7,10 @@  #include <sched.h>  #include <asm/unistd.h>  #include <sys/time.h> -#include "as-layout.h" -#include "kern_constants.h" -#include "ptrace_user.h" -#include "stub-data.h" -#include "sysdep/stub.h" +#include <as-layout.h> +#include <ptrace_user.h> +#include <stub-data.h> +#include <sysdep/stub.h>  /*   * This is in a separate file because it needs to be compiled with any diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 3d099f97478..007d5503f49 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -3,14 +3,14 @@   * Licensed under the GPL   */ -#include "linux/mm.h" -#include "linux/sched.h" -#include "linux/slab.h" -#include "asm/pgalloc.h" -#include "asm/pgtable.h" -#include "as-layout.h" -#include "os.h" -#include "skas.h" +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <as-layout.h> +#include <os.h> +#include <skas.h>  extern int __syscall_stub_start; @@ -31,7 +31,7 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,  	if (!pmd)  		goto out_pmd; -	pte = pte_alloc_map(mm, pmd, proc); +	pte = pte_alloc_map(mm, NULL, pmd, proc);  	if (!pte)  		goto out_pte; @@ -92,8 +92,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)  		goto out_free;  	} -	to_mm->stub_pages = NULL; -  	return 0;   out_free: @@ -103,9 +101,8 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)  	return ret;  } -void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +void uml_setup_stubs(struct mm_struct *mm)  { -	struct page **pages;  	int err, ret;  	if (!skas_needs_stub) @@ -120,29 +117,20 @@ void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)  	if (ret)  		goto out; -	pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL); -	if (pages == NULL) { -		printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page " -		       "pointers\n"); -		goto out; -	} - -	pages[0] = virt_to_page(&__syscall_stub_start); -	pages[1] = virt_to_page(mm->context.id.stack); -	mm->context.stub_pages = pages; +	mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); +	mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);  	/* dup_mmap already holds mmap_sem */  	err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,  				      VM_READ | VM_MAYREAD | VM_EXEC | -				      VM_MAYEXEC | VM_DONTCOPY, pages); +				      VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP, +				      mm->context.stub_pages);  	if (err) {  		printk(KERN_ERR "install_special_mapping returned %d\n", err); -		goto out_free; +		goto out;  	}  	return; -out_free: -	kfree(pages);  out:  	force_sigsegv(SIGSEGV, current);  } @@ -151,8 +139,6 @@ void arch_exit_mmap(struct mm_struct *mm)  {  	pte_t *pte; -	if (mm->context.stub_pages != NULL) -		kfree(mm->context.stub_pages);  	pte = virt_to_pte(mm, STUB_CODE);  	if (pte != NULL)  		pte_clear(mm, STUB_CODE, pte); diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 2e9852c0d48..4da11b3c8dd 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -3,12 +3,12 @@   * Licensed under the GPL   */ -#include "linux/init.h" -#include "linux/sched.h" -#include "as-layout.h" -#include "kern.h" -#include "os.h" -#include "skas.h" +#include <linux/init.h> +#include <linux/sched.h> +#include <as-layout.h> +#include <kern.h> +#include <os.h> +#include <skas.h>  int new_mm(unsigned long stack)  { @@ -41,7 +41,7 @@ static int __init start_kernel_proc(void *unused)  	cpu_tasks[0].pid = pid;  	cpu_tasks[0].task = current;  #ifdef CONFIG_SMP -	cpu_online_map = cpumask_of_cpu(0); +	init_cpu_online(get_cpu_mask(0));  #endif  	start_kernel();  	return 0; diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index f5173e1ec3a..c0681e09743 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -3,11 +3,11 @@   * Licensed under the GPL   */ -#include "linux/kernel.h" -#include "linux/ptrace.h" -#include "kern_util.h" -#include "sysdep/ptrace.h" -#include "sysdep/syscalls.h" +#include <linux/kernel.h> +#include <linux/ptrace.h> +#include <kern_util.h> +#include <sysdep/ptrace.h> +#include <sysdep/syscalls.h>  extern int syscall_table_size;  #define NR_SYSCALLS (syscall_table_size / sizeof(void *)) @@ -18,7 +18,7 @@ void handle_syscall(struct uml_pt_regs *r)  	long result;  	int syscall; -	syscall_trace(r, 0); +	syscall_trace_enter(regs);  	/*  	 * This should go in the declaration of syscall, but when I do that, @@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r)  		result = -ENOSYS;  	else result = EXECUTE_SYSCALL(syscall, regs); -	REGS_SET_SYSCALL_RETURN(r->gp, result); +	PT_REGS_SET_SYSCALL_RETURN(regs, result); -	syscall_trace(r, 1); +	syscall_trace_leave(regs);  } diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 696634214dc..4ffb644d6c0 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -6,12 +6,13 @@  #include <linux/err.h>  #include <linux/highmem.h>  #include <linux/mm.h> +#include <linux/module.h>  #include <linux/sched.h>  #include <asm/current.h>  #include <asm/page.h>  #include <asm/pgtable.h> -#include "kern_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h>  pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)  { @@ -68,7 +69,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write,  		return -1;  	page = pte_page(*pte); -	addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + +	addr = (unsigned long) kmap_atomic(page) +  		(addr & ~PAGE_MASK);  	current->thread.fault_catcher = &buf; @@ -81,7 +82,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write,  	current->thread.fault_catcher = NULL; -	kunmap_atomic((void *)addr, KM_UML_USERCOPY); +	kunmap_atomic((void *)addr);  	return n;  } @@ -149,6 +150,7 @@ int copy_from_user(void *to, const void __user *from, int n)  	       buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):  	       n;  } +EXPORT_SYMBOL(copy_from_user);  static int copy_chunk_to_user(unsigned long to, int len, void *arg)  { @@ -170,6 +172,7 @@ int copy_to_user(void __user *to, const void *from, int n)  	       buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :  	       n;  } +EXPORT_SYMBOL(copy_to_user);  static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)  { @@ -204,6 +207,7 @@ int strncpy_from_user(char *dst, const char __user *src, int count)  		return -EFAULT;  	return strnlen(dst, count);  } +EXPORT_SYMBOL(strncpy_from_user);  static int clear_chunk(unsigned long addr, int len, void *unused)  { @@ -226,6 +230,7 @@ int clear_user(void __user *mem, int len)  	return access_ok(VERIFY_WRITE, mem, len) ?  	       buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len;  } +EXPORT_SYMBOL(clear_user);  static int strnlen_chunk(unsigned long str, int len, void *arg)  { @@ -249,5 +254,6 @@ int strnlen_user(const void __user *str, int len)  	n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);  	if (n == 0)  		return count + 1; -	return -EFAULT; +	return 0;  } +EXPORT_SYMBOL(strnlen_user); diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 106bf27e2a9..5c8c3ea7db7 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -3,27 +3,24 @@   * Licensed under the GPL   */ -#include "linux/percpu.h" -#include "asm/pgalloc.h" -#include "asm/tlb.h" - -/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */ -DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +#include <linux/percpu.h> +#include <asm/pgalloc.h> +#include <asm/tlb.h>  #ifdef CONFIG_SMP -#include "linux/sched.h" -#include "linux/module.h" -#include "linux/threads.h" -#include "linux/interrupt.h" -#include "linux/err.h" -#include "linux/hardirq.h" -#include "asm/smp.h" -#include "asm/processor.h" -#include "asm/spinlock.h" -#include "kern.h" -#include "irq_user.h" -#include "os.h" +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/threads.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <asm/smp.h> +#include <asm/processor.h> +#include <asm/spinlock.h> +#include <kern.h> +#include <irq_user.h> +#include <os.h>  /* Per CPU bogomips and other parameters   * The only piece used here is the ipi pipe, which is set before SMP is @@ -79,7 +76,7 @@ static int idle_proc(void *cpup)  		cpu_relax();  	notify_cpu_starting(cpu); -	cpu_set(cpu, cpu_online_map); +	set_cpu_online(cpu, true);  	default_idle();  	return 0;  } @@ -113,8 +110,7 @@ void smp_prepare_cpus(unsigned int maxcpus)  	for (i = 0; i < ncpus; ++i)  		set_cpu_possible(i, true); -	cpu_clear(me, cpu_online_map); -	cpu_set(me, cpu_online_map); +	set_cpu_online(me, true);  	cpu_set(me, cpu_callin_map);  	err = os_pipe(cpu_data[me].ipi_pipe, 1, 1); @@ -141,13 +137,13 @@ void smp_prepare_cpus(unsigned int maxcpus)  void smp_prepare_boot_cpu(void)  { -	cpu_set(smp_processor_id(), cpu_online_map); +	set_cpu_online(smp_processor_id(), true);  } -int __cpu_up(unsigned int cpu) +int __cpu_up(unsigned int cpu, struct task_struct *tidle)  {  	cpu_set(cpu, smp_commenced_mask); -	while (!cpu_isset(cpu, cpu_online_map)) +	while (!cpu_online(cpu))  		mb();  	return 0;  } @@ -173,7 +169,7 @@ void IPI_handler(int cpu)  			break;  		case 'R': -			set_tsk_need_resched(current); +			scheduler_ipi();  			break;  		case 'S': diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index f958cb876ee..c1d0ae069b5 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -3,40 +3,16 @@   * Licensed under the GPL   */ -#include "linux/file.h" -#include "linux/fs.h" -#include "linux/mm.h" -#include "linux/sched.h" -#include "linux/utsname.h" -#include "linux/syscalls.h" -#include "asm/current.h" -#include "asm/mman.h" -#include "asm/uaccess.h" -#include "asm/unistd.h" -#include "internal.h" - -long sys_fork(void) -{ -	long ret; - -	current->thread.forking = 1; -	ret = do_fork(SIGCHLD, UPT_SP(¤t->thread.regs.regs), -		      ¤t->thread.regs, 0, NULL, NULL); -	current->thread.forking = 0; -	return ret; -} - -long sys_vfork(void) -{ -	long ret; - -	current->thread.forking = 1; -	ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, -		      UPT_SP(¤t->thread.regs.regs), -		      ¤t->thread.regs, 0, NULL, NULL); -	current->thread.forking = 0; -	return ret; -} +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/utsname.h> +#include <linux/syscalls.h> +#include <asm/current.h> +#include <asm/mman.h> +#include <asm/uaccess.h> +#include <asm/unistd.h>  long old_mmap(unsigned long addr, unsigned long len,  	      unsigned long prot, unsigned long flags, @@ -50,19 +26,3 @@ long old_mmap(unsigned long addr, unsigned long len,   out:  	return err;  } - -int kernel_execve(const char *filename, -		  const char *const argv[], -		  const char *const envp[]) -{ -	mm_segment_t fs; -	int ret; - -	fs = get_fs(); -	set_fs(KERNEL_DS); -	ret = um_execve(filename, (const char __user *const __user *)argv, -			(const char __user *const __user *) envp); -	set_fs(fs); - -	return ret; -} diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 0960de54495..799d7e413bf 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -1,78 +1,98 @@  /*   * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL + * Copyright (C) 2013 Richard Weinberger <richrd@nod.at> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation.   */  #include <linux/kallsyms.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/sched.h> -#include "sysrq.h" +#include <asm/sysrq.h> +#include <os.h> -/* Catch non-i386 SUBARCH's. */ -#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) -void show_trace(struct task_struct *task, unsigned long * stack) +struct stack_frame { +	struct stack_frame *next_frame; +	unsigned long return_address; +}; + +static void do_stack_trace(unsigned long *sp, unsigned long bp)  { +	int reliable;  	unsigned long addr; +	struct stack_frame *frame = (struct stack_frame *)bp; -	if (!stack) { -		stack = (unsigned long*) &stack; -		WARN_ON(1); -	} - -	printk(KERN_INFO "Call Trace: \n"); -	while (((long) stack & (THREAD_SIZE-1)) != 0) { -		addr = *stack; +	printk(KERN_INFO "Call Trace:\n"); +	while (((long) sp & (THREAD_SIZE-1)) != 0) { +		addr = *sp;  		if (__kernel_text_address(addr)) { -			printk(KERN_INFO "%08lx:  [<%08lx>]", -			       (unsigned long) stack, addr); -			print_symbol(KERN_CONT " %s", addr); +			reliable = 0; +			if ((unsigned long) sp == bp + sizeof(long)) { +				frame = frame ? frame->next_frame : NULL; +				bp = (unsigned long)frame; +				reliable = 1; +			} + +			printk(KERN_INFO " [<%08lx>]", addr); +			printk(KERN_CONT " %s", reliable ? "" : "? "); +			print_symbol(KERN_CONT "%s", addr);  			printk(KERN_CONT "\n");  		} -		stack++; +		sp++;  	}  	printk(KERN_INFO "\n");  } -#endif -/* - * stack dumps generator - this is used by arch-independent code. - * And this is identical to i386 currently. - */ -void dump_stack(void) +static unsigned long get_frame_pointer(struct task_struct *task, +				       struct pt_regs *segv_regs)  { -	unsigned long stack; - -	show_trace(current, &stack); +	if (!task || task == current) +		return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); +	else +		return KSTK_EBP(task);  } -EXPORT_SYMBOL(dump_stack); -/*Stolen from arch/i386/kernel/traps.c */ -static const int kstack_depth_to_print = 24; +static unsigned long *get_stack_pointer(struct task_struct *task, +					struct pt_regs *segv_regs) +{ +	if (!task || task == current) +		return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); +	else +		return (unsigned long *)KSTK_ESP(task); +} -/* This recently started being used in arch-independent code too, as in - * kernel/sched.c.*/ -void show_stack(struct task_struct *task, unsigned long *esp) +void show_stack(struct task_struct *task, unsigned long *stack)  { -	unsigned long *stack; +	unsigned long *sp = stack, bp = 0; +	struct pt_regs *segv_regs = current->thread.segv_regs;  	int i; -	if (esp == NULL) { -		if (task != current && task != NULL) { -			esp = (unsigned long *) KSTK_ESP(task); -		} else { -			esp = (unsigned long *) &esp; -		} +	if (!segv_regs && os_is_signal_stack()) { +		printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," +				" aborting stack trace!\n"); +		return;  	} -	stack = esp; -	for (i = 0; i < kstack_depth_to_print; i++) { +#ifdef CONFIG_FRAME_POINTER +	bp = get_frame_pointer(task, segv_regs); +#endif + +	if (!stack) +		sp = get_stack_pointer(task, segv_regs); + +	printk(KERN_INFO "Stack:\n"); +	stack = sp; +	for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) {  		if (kstack_end(stack))  			break; -		if (i && ((i % 8) == 0)) -			printk(KERN_INFO "       "); -		printk(KERN_CONT "%08lx ", *stack++); +		if (i && ((i % STACKSLOTS_PER_LINE) == 0)) +			printk(KERN_CONT "\n"); +		printk(KERN_CONT " %08lx", *stack++);  	} +	printk(KERN_CONT "\n"); -	show_trace(task, esp); +	do_stack_trace(sp, bp);  } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index a08d9fab81f..117568d4f64 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -10,10 +10,10 @@  #include <linux/threads.h>  #include <asm/irq.h>  #include <asm/param.h> -#include "kern_util.h" -#include "os.h" +#include <kern_util.h> +#include <os.h> -void timer_handler(int sig, struct uml_pt_regs *regs) +void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)  {  	unsigned long flags; @@ -75,8 +75,6 @@ static struct clocksource itimer_clocksource = {  	.rating		= 300,  	.read		= itimer_read,  	.mask		= CLOCKSOURCE_MASK(64), -	.mult		= 1000, -	.shift		= 0,  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,  }; @@ -84,7 +82,7 @@ static void __init setup_itimer(void)  {  	int err; -	err = request_irq(TIMER_IRQ, um_timer, IRQF_DISABLED, "timer", NULL); +	err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL);  	if (err != 0)  		printk(KERN_ERR "register_timer : request_irq failed - "  		       "errno = %d\n", -err); @@ -94,9 +92,9 @@ static void __init setup_itimer(void)  		clockevent_delta2ns(60 * HZ, &itimer_clockevent);  	itimer_clockevent.min_delta_ns =  		clockevent_delta2ns(1, &itimer_clockevent); -	err = clocksource_register(&itimer_clocksource); +	err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC);  	if (err) { -		printk(KERN_ERR "clocksource_register returned %d\n", err); +		printk(KERN_ERR "clocksource_register_hz returned %d\n", err);  		return;  	}  	clockevents_register_device(&itimer_clockevent); diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index d175d0566af..f1b3eb14b85 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -4,14 +4,15 @@   */  #include <linux/mm.h> +#include <linux/module.h>  #include <linux/sched.h>  #include <asm/pgtable.h>  #include <asm/tlbflush.h> -#include "as-layout.h" -#include "mem_user.h" -#include "os.h" -#include "skas.h" -#include "tlb.h" +#include <as-layout.h> +#include <mem_user.h> +#include <os.h> +#include <skas.h> +#include <kern_util.h>  struct host_vm_change {  	struct host_vm_op { @@ -75,6 +76,7 @@ static int do_ops(struct host_vm_change *hvc, int end,  		default:  			printk(KERN_ERR "Unknown op type %d in do_ops\n",  			       op->type); +			BUG();  			break;  		}  	} @@ -123,6 +125,9 @@ static int add_munmap(unsigned long addr, unsigned long len,  	struct host_vm_op *last;  	int ret = 0; +	if ((addr >= STUB_START) && (addr < STUB_END)) +		return -EINVAL; +  	if (hvc->index != 0) {  		last = &hvc->ops[hvc->index - 1];  		if ((last->type == MUNMAP) && @@ -282,12 +287,15 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,  	/* This is not an else because ret is modified above */  	if (ret) {  		printk(KERN_ERR "fix_range_common: failed, killing current " -		       "process\n"); +		       "process: %d\n", task_tgid_vnr(current)); +		/* We are under mmap_sem, release it such that current can terminate */ +		up_write(¤t->mm->mmap_sem);  		force_sig(SIGKILL, current); +		do_signal();  	}  } -int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) +static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)  {  	struct mm_struct *mm;  	pgd_t *pgd; @@ -499,6 +507,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,  		flush_tlb_kernel_range_common(start, end);  	else fix_range(vma->vm_mm, start, end, 0);  } +EXPORT_SYMBOL(flush_tlb_range);  void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,  			unsigned long end) diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 637c6505dc0..5678c3571e7 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -6,15 +6,15 @@  #include <linux/mm.h>  #include <linux/sched.h>  #include <linux/hardirq.h> +#include <linux/module.h>  #include <asm/current.h>  #include <asm/pgtable.h>  #include <asm/tlbflush.h> -#include "arch.h" -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "skas.h" -#include "sysdep/sigcontext.h" +#include <arch.h> +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <skas.h>  /*   * Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by @@ -30,6 +30,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,  	pmd_t *pmd;  	pte_t *pte;  	int err = -EFAULT; +	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;  	*code_out = SEGV_MAPERR; @@ -40,6 +41,9 @@ int handle_page_fault(unsigned long address, unsigned long ip,  	if (in_atomic())  		goto out_nosemaphore; +	if (is_user) +		flags |= FAULT_FLAG_USER; +retry:  	down_read(&mm->mmap_sem);  	vma = find_vma(mm, address);  	if (!vma) @@ -55,17 +59,24 @@ int handle_page_fault(unsigned long address, unsigned long ip,  good_area:  	*code_out = SEGV_ACCERR; -	if (is_write && !(vma->vm_flags & VM_WRITE)) -		goto out; - -	/* Don't require VM_READ|VM_EXEC for write faults! */ -	if (!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) -		goto out; +	if (is_write) { +		if (!(vma->vm_flags & VM_WRITE)) +			goto out; +		flags |= FAULT_FLAG_WRITE; +	} else { +		/* Don't require VM_READ|VM_EXEC for write faults! */ +		if (!(vma->vm_flags & (VM_READ | VM_EXEC))) +			goto out; +	}  	do {  		int fault; -		fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); +		fault = handle_mm_fault(mm, vma, address, flags); + +		if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) +			goto out_nosemaphore; +  		if (unlikely(fault & VM_FAULT_ERROR)) {  			if (fault & VM_FAULT_OOM) {  				goto out_of_memory; @@ -75,10 +86,18 @@ good_area:  			}  			BUG();  		} -		if (fault & VM_FAULT_MAJOR) -			current->maj_flt++; -		else -			current->min_flt++; +		if (flags & FAULT_FLAG_ALLOW_RETRY) { +			if (fault & VM_FAULT_MAJOR) +				current->maj_flt++; +			else +				current->min_flt++; +			if (fault & VM_FAULT_RETRY) { +				flags &= ~FAULT_FLAG_ALLOW_RETRY; +				flags |= FAULT_FLAG_TRIED; + +				goto retry; +			} +		}  		pgd = pgd_offset(mm, address);  		pud = pud_offset(pgd, address); @@ -109,9 +128,33 @@ out_of_memory:  	 * (which will retry the fault, or kill us if we got oom-killed).  	 */  	up_read(&mm->mmap_sem); +	if (!is_user) +		goto out_nosemaphore;  	pagefault_out_of_memory();  	return 0;  } +EXPORT_SYMBOL(handle_page_fault); + +static void show_segv_info(struct uml_pt_regs *regs) +{ +	struct task_struct *tsk = current; +	struct faultinfo *fi = UPT_FAULTINFO(regs); + +	if (!unhandled_signal(tsk, SIGSEGV)) +		return; + +	if (!printk_ratelimit()) +		return; + +	printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x", +		task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, +		tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi), +		(void *)UPT_IP(regs), (void *)UPT_SP(regs), +		fi->error_code); + +	print_vma_addr(KERN_CONT " in ", UPT_IP(regs)); +	printk(KERN_CONT "\n"); +}  static void bad_segv(struct faultinfo fi, unsigned long ip)  { @@ -136,11 +179,12 @@ void fatal_sigsegv(void)  	os_dump_core();  } -void segv_handler(int sig, struct uml_pt_regs *regs) +void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)  {  	struct faultinfo * fi = UPT_FAULTINFO(regs);  	if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) { +		show_segv_info(regs);  		bad_segv(*fi, UPT_IP(regs));  		return;  	} @@ -162,9 +206,12 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,  	int is_write = FAULT_WRITE(fi);  	unsigned long address = FAULT_ADDRESS(fi); +	if (!is_user && regs) +		current->thread.segv_regs = container_of(regs, struct pt_regs, regs); +  	if (!is_user && (address >= start_vm) && (address < end_vm)) {  		flush_tlb_kernel_vm(); -		return 0; +		goto out;  	}  	else if (current->mm == NULL) {  		show_regs(container_of(regs, struct pt_regs, regs)); @@ -186,7 +233,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,  	catcher = current->thread.fault_catcher;  	if (!err) -		return 0; +		goto out;  	else if (catcher != NULL) {  		current->thread.fault_addr = (void *) address;  		UML_LONGJMP(catcher, 1); @@ -194,7 +241,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,  	else if (current->thread.fault_addr != NULL)  		panic("fault_addr set but no fault catcher");  	else if (!is_user && arch_fixup(ip, regs)) -		return 0; +		goto out;  	if (!is_user) {  		show_regs(container_of(regs, struct pt_regs, regs)); @@ -202,6 +249,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,  		      address, ip);  	} +	show_segv_info(regs); +  	if (err == -EACCES) {  		si.si_signo = SIGBUS;  		si.si_errno = 0; @@ -216,11 +265,19 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,  		current->thread.arch.faultinfo = fi;  		force_sig_info(SIGSEGV, &si, current);  	} + +out: +	if (regs) +		current->thread.segv_regs = NULL; +  	return 0;  } -void relay_signal(int sig, struct uml_pt_regs *regs) +void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)  { +	struct faultinfo *fi; +	struct siginfo clean_si; +  	if (!UPT_IS_USER(regs)) {  		if (sig == SIGBUS)  			printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " @@ -230,18 +287,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs)  	arch_examine_signal(sig, regs); -	current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); -	force_sig(sig, current); +	memset(&clean_si, 0, sizeof(clean_si)); +	clean_si.si_signo = si->si_signo; +	clean_si.si_errno = si->si_errno; +	clean_si.si_code = si->si_code; +	switch (sig) { +	case SIGILL: +	case SIGFPE: +	case SIGSEGV: +	case SIGBUS: +	case SIGTRAP: +		fi = UPT_FAULTINFO(regs); +		clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi); +		current->thread.arch.faultinfo = *fi; +#ifdef __ARCH_SI_TRAPNO +		clean_si.si_trapno = si->si_trapno; +#endif +		break; +	default: +		printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n", +			sig, si->si_code); +	} + +	force_sig_info(sig, &clean_si, current);  } -void bus_handler(int sig, struct uml_pt_regs *regs) +void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs)  {  	if (current->thread.fault_catcher != NULL)  		UML_LONGJMP(current->thread.fault_catcher, 1); -	else relay_signal(sig, regs); +	else +		relay_signal(sig, si, regs);  } -void winch(int sig, struct uml_pt_regs *regs) +void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)  {  	do_IRQ(WINCH_IRQ, regs);  } diff --git a/arch/um/kernel/uaccess.c b/arch/um/kernel/uaccess.c deleted file mode 100644 index dd33f040c52..00000000000 --- a/arch/um/kernel/uaccess.c +++ /dev/null @@ -1,33 +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 - */ - -/* - * These are here rather than tt/uaccess.c because skas mode needs them in - * order to do SIGBUS recovery when a tmpfs mount runs out of room. - */ - -#include <linux/string.h> -#include "os.h" - -static void __do_copy(void *to, const void *from, int n) -{ -	memcpy(to, from, n); -} - - -int __do_copy_to_user(void *to, const void *from, int n, -		      void **fault_addr, jmp_buf **fault_catcher) -{ -	unsigned long fault; -	int faulted; - -	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, -			       __do_copy, &faulted); -	if (!faulted) -		return 0; -	else -		return n - (fault - (unsigned long) to); -} diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 8d84250324b..016adf0985d 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -10,16 +10,18 @@  #include <linux/seq_file.h>  #include <linux/string.h>  #include <linux/utsname.h> +#include <linux/sched.h>  #include <asm/pgtable.h>  #include <asm/processor.h> +#include <asm/sections.h>  #include <asm/setup.h> -#include "as-layout.h" -#include "arch.h" -#include "init.h" -#include "kern.h" -#include "kern_util.h" -#include "mem_user.h" -#include "os.h" +#include <as-layout.h> +#include <arch.h> +#include <init.h> +#include <kern.h> +#include <kern_util.h> +#include <mem_user.h> +#include <os.h>  #define DEFAULT_COMMAND_LINE "root=98:0" @@ -47,6 +49,10 @@ struct cpuinfo_um boot_cpu_data = {  	.ipi_pipe		= { -1, -1 }  }; +union thread_union cpu0_irqstack +	__attribute__((__section__(".data..init_irqstack"))) = +		{ INIT_THREAD_INFO(init_task) }; +  unsigned long thread_saved_pc(struct task_struct *task)  {  	/* FIXME: Need to look up userspace_pid by cpu */ @@ -102,6 +108,8 @@ const struct seq_operations cpuinfo_op = {  /* Set in linux_main */  unsigned long uml_physmem; +EXPORT_SYMBOL(uml_physmem); +  unsigned long uml_reserved; /* Also modified in mem_init */  unsigned long start_vm;  unsigned long end_vm; @@ -227,7 +235,6 @@ static int panic_exit(struct notifier_block *self, unsigned long unused1,  		      void *unused2)  {  	bust_spinlocks(1); -	show_regs(&(current->thread.regs));  	bust_spinlocks(0);  	uml_exitcode = 1;  	os_dump_core(); diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 81e07e2be3a..f6cc3bd6178 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -4,9 +4,9 @@   */  #include <asm/errno.h> -#include "init.h" -#include "kern.h" -#include "os.h" +#include <init.h> +#include <kern.h> +#include <os.h>  /* Changed by set_umid_arg */  static int umid_inited = 0; diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index fbd99402d4d..6899195602b 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -20,13 +20,12 @@ SECTIONS    . = START + SIZEOF_HEADERS;    _text = .; -  _stext = .; -  __init_begin = .;    INIT_TEXT_SECTION(0)    . = ALIGN(PAGE_SIZE);    .text      :    { +    _stext = .;      TEXT_TEXT      SCHED_TEXT      LOCK_TEXT @@ -60,9 +59,12 @@ SECTIONS  	PROVIDE_HIDDEN(__rela_iplt_end = .);    } -  #include "asm/common.lds.S" +  #include <asm/common.lds.S> +  __init_begin = .;    init.data : { INIT_DATA } +  __init_end = .; +    .data    :    {      INIT_TASK_DATA(KERNEL_STACK_SIZE) @@ -97,6 +99,7 @@ SECTIONS    PROVIDE(_bss_start = .);    SBSS(0)    BSS(0) +   __bss_stop = .;    _end = .;    PROVIDE (end = .);  | 
