diff options
Diffstat (limited to 'arch')
28 files changed, 290 insertions, 121 deletions
diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c index 9550f37fb62..1e7a101cbf4 100644 --- a/arch/frv/kernel/gdb-stub.c +++ b/arch/frv/kernel/gdb-stub.c @@ -1195,7 +1195,7 @@ static void gdbstub_check_breakpoint(void) /* * */ -static void __attribute__((unused)) gdbstub_show_regs(void) +static void __maybe_unused gdbstub_show_regs(void) { unsigned long *reg; int loop; @@ -1223,7 +1223,7 @@ static void __attribute__((unused)) gdbstub_show_regs(void) /* * dump debugging regs */ -static void __attribute__((unused)) gdbstub_dump_debugregs(void) +static void __maybe_unused gdbstub_dump_debugregs(void) { gdbstub_printk("DCR %08lx ", __debug_status.dcr); gdbstub_printk("BRR %08lx\n", __debug_status.brr); @@ -2079,25 +2079,25 @@ void gdbstub_exit(int status) * GDB wants to call malloc() and free() to allocate memory for calling kernel * functions directly from its command line */ -static void *malloc(size_t size) __attribute__((unused)); +static void *malloc(size_t size) __maybe_unused; static void *malloc(size_t size) { return kmalloc(size, GFP_ATOMIC); } -static void free(void *p) __attribute__((unused)); +static void free(void *p) __maybe_unused; static void free(void *p) { kfree(p); } -static uint32_t ___get_HSR0(void) __attribute__((unused)); +static uint32_t ___get_HSR0(void) __maybe_unused; static uint32_t ___get_HSR0(void) { return __get_HSR(0); } -static uint32_t ___set_HSR0(uint32_t x) __attribute__((unused)); +static uint32_t ___set_HSR0(uint32_t x) __maybe_unused; static uint32_t ___set_HSR0(uint32_t x) { __set_HSR(0, x); diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S index dab98fd99e6..54e21c3f205 100644 --- a/arch/h8300/kernel/syscalls.S +++ b/arch/h8300/kernel/syscalls.S @@ -31,7 +31,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ .long SYMBOL_NAME(sys_chown16) - .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ @@ -45,11 +45,11 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_fstat) .long SYMBOL_NAME(sys_pause) .long SYMBOL_NAME(sys_utime) /* 30 */ - .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ - .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ .long SYMBOL_NAME(sys_access) .long SYMBOL_NAME(sys_nice) - .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* 35 old ftime syscall holder */ .long SYMBOL_NAME(sys_sync) .long SYMBOL_NAME(sys_kill) .long SYMBOL_NAME(sys_rename) @@ -58,7 +58,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_dup) .long SYMBOL_NAME(sys_pipe) .long SYMBOL_NAME(sys_times) - .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ .long SYMBOL_NAME(sys_setgid16) .long SYMBOL_NAME(sys_getgid16) @@ -66,13 +66,13 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_geteuid16) .long SYMBOL_NAME(sys_getegid16) /* 50 */ .long SYMBOL_NAME(sys_acct) - .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ - .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ + .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ + .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ .long SYMBOL_NAME(sys_ioctl) .long SYMBOL_NAME(sys_fcntl) /* 55 */ - .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ .long SYMBOL_NAME(sys_setpgid) - .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_umask) /* 60 */ .long SYMBOL_NAME(sys_chroot) @@ -112,7 +112,7 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_fchown16) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) - .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ .long SYMBOL_NAME(sys_statfs) .long SYMBOL_NAME(sys_fstatfs) /* 100 */ .long SYMBOL_NAME(sys_ni_syscall) /* ioperm for i386 */ @@ -202,8 +202,8 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_capset) /* 185 */ .long SYMBOL_NAME(sys_sigaltstack) .long SYMBOL_NAME(sys_sendfile) - .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ - .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ .long SYMBOL_NAME(sys_vfork) /* 190 */ .long SYMBOL_NAME(sys_getrlimit) .long SYMBOL_NAME(sys_mmap2) @@ -236,10 +236,10 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ - .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* reserved TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* reserved Security */ .long SYMBOL_NAME(sys_gettid) - .long SYMBOL_NAME(sys_ni_syscall) /* 225 */ /* sys_readahead */ + .long SYMBOL_NAME(sys_readahead) /* 225 */ .long SYMBOL_NAME(sys_setxattr) .long SYMBOL_NAME(sys_lsetxattr) .long SYMBOL_NAME(sys_fsetxattr) @@ -257,8 +257,8 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_futex) /* 240 */ .long SYMBOL_NAME(sys_sched_setaffinity) .long SYMBOL_NAME(sys_sched_getaffinity) - .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_thread_area */ - .long SYMBOL_NAME(sys_ni_syscall) /* sys_get_thread_area */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_io_setup) /* 245 */ .long SYMBOL_NAME(sys_io_destroy) .long SYMBOL_NAME(sys_io_getevents) @@ -288,8 +288,8 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_utimes) .long SYMBOL_NAME(sys_fadvise64_64) .long SYMBOL_NAME(sys_ni_syscall) /* sys_vserver */ - .long SYMBOL_NAME(sys_mbind) - .long SYMBOL_NAME(sys_get_mempolicy) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_get_mempolicy) /* 275 */ .long SYMBOL_NAME(sys_set_mempolicy) .long SYMBOL_NAME(sys_mq_open) .long SYMBOL_NAME(sys_mq_unlink) @@ -297,16 +297,42 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_mq_timedreceive) /* 280 */ .long SYMBOL_NAME(sys_mq_notify) .long SYMBOL_NAME(sys_mq_getsetattr) - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for kexec */ .long SYMBOL_NAME(sys_waitid) - .long SYMBOL_NAME(sys_ni_syscall) /* 285 */ /* available */ - .long SYMBOL_NAME(sys_add_key) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_kexec_load */ + .long SYMBOL_NAME(sys_add_key) /* 285 */ .long SYMBOL_NAME(sys_request_key) .long SYMBOL_NAME(sys_keyctl) - - .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 - .long SYMBOL_NAME(sys_ni_syscall) - .endr + .long SYMBOL_NAME(sys_ioprio_set) + .long SYMBOL_NAME(sys_ioprio_get) /* 290 */ + .long SYMBOL_NAME(sys_inotify_init) + .long SYMBOL_NAME(sys_inotify_add_watch) + .long SYMBOL_NAME(sys_inotify_rm_watch) + .long SYMBOL_NAME(sys_migrate_pages) + .long SYMBOL_NAME(sys_openat) /* 295 */ + .long SYMBOL_NAME(sys_mkdirat) + .long SYMBOL_NAME(sys_mknodat) + .long SYMBOL_NAME(sys_fchownat) + .long SYMBOL_NAME(sys_futimesat) + .long SYMBOL_NAME(sys_fstatat64) /* 300 */ + .long SYMBOL_NAME(sys_unlinkat) + .long SYMBOL_NAME(sys_renameat) + .long SYMBOL_NAME(sys_linkat) + .long SYMBOL_NAME(sys_symlinkat) + .long SYMBOL_NAME(sys_readlinkat) /* 305 */ + .long SYMBOL_NAME(sys_fchmodat) + .long SYMBOL_NAME(sys_faccessat) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_pselect6 */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_ppoll */ + .long SYMBOL_NAME(sys_unshare) /* 310 */ + .long SYMBOL_NAME(sys_set_robust_list) + .long SYMBOL_NAME(sys_get_robust_list) + .long SYMBOL_NAME(sys_splice) + .long SYMBOL_NAME(sys_sync_file_range) + .long SYMBOL_NAME(sys_tee) /* 315 */ + .long SYMBOL_NAME(sys_vmsplice) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_move_pages */ + .long SYMBOL_NAME(sys_getcpu) + .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_pwait */ .macro call_sp addr mov.l #SYMBOL_NAME(\addr),er6 diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 0772678ceec..bf6adce5226 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -320,3 +320,6 @@ ENTRY(sys_call_table) .long sys_getcpu .long sys_epoll_pwait .long sys_utimensat /* 320 */ + .long sys_signalfd + .long sys_timerfd + .long sys_eventfd diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 9740d6b8ae1..c3bb8a755b0 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -241,6 +241,10 @@ config GENERIC_CALIBRATE_DELAY bool default y +config SCHED_NO_NO_OMIT_FRAME_POINTER + bool + default y + config PREEMPT bool "Preemptible Kernel" help diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S index 8bb74b10dca..49a6d16a3d5 100644 --- a/arch/m32r/mm/mmu.S +++ b/arch/m32r/mm/mmu.S @@ -163,7 +163,8 @@ ENTRY(tme_handler) ; pte_data = (unsigned long)pte_val(*pte); ld r2, @r3 ; r2: pte data - or3 r2, r2, #2 ; _PAGE_PRESENT(=2) + and3 r3, r2, #2 ; _PAGE_PRESENT(=2) check + beqz r3, 3f .fillinsn 5: @@ -264,11 +265,8 @@ ENTRY(tme_handler) ; and3 r1, r1, #0xeff ldi r4, #611 ; _KERNPG_TABLE(=611) - beq r1, r4, 4f ; !pmd_bad(*pmd) ? - .fillinsn -3: - ldi r1, #0 ; r1: pte_data = 0 - bra 5f + bne r1, r4, 3f ; !pmd_bad(*pmd) ? + .fillinsn 4: ; pte = pte_offset(pmd, address); @@ -282,8 +280,10 @@ ENTRY(tme_handler) add r4, r3 ; r4: pte ; pte_data = (unsigned long)pte_val(*pte); ld r1, @r4 ; r1: pte_data - .fillinsn + and3 r3, r1, #2 ; _PAGE_PRESENT(=2) check + beqz r3, 3f + .fillinsn ;; set tlb ; r0: address, r1: pte_data, r2: entry ; r3,r4: (free) @@ -295,8 +295,7 @@ ENTRY(tme_handler) and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) or r3, r4 st r3, @r2 - or3 r4, r1, #2 ; _PAGE_PRESENT(=2) - st r4, @(4,r2) ; set_tlb_data(entry, pte_data); + st r1, @(4,r2) ; set_tlb_data(entry, pte_data); ld r4, @sp+ ld r3, @sp+ @@ -306,6 +305,11 @@ ENTRY(tme_handler) ld sp, @sp+ rte + .fillinsn +3: + ldi r1, #2 ; r1: pte_data = 0 | _PAGE_PRESENT(=2) + bra 5b + #else #error unknown isa configuration #endif diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 9ed4931af16..068377a2a8d 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -173,7 +173,7 @@ void local_irq_restore(unsigned long en) lv1_get_version_info(&tmp); } - hard_irq_enable(); + __hard_irq_enable(); } #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c index 064a7ba4f02..77b7b34b595 100644 --- a/arch/powerpc/kernel/swsusp.c +++ b/arch/powerpc/kernel/swsusp.c @@ -36,8 +36,4 @@ void restore_processor_state(void) #ifdef CONFIG_PPC32 set_context(current->active_mm->context.id, current->active_mm->pgd); #endif - -#ifdef CONFIG_PPC64 - hard_irq_enable(); -#endif } diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 8c20f0fb865..812bf563ed6 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -43,12 +43,10 @@ static void cbe_power_save(void) unsigned long ctrl, thread_switch_control; /* - * We need to hard disable interrupts, but we also need to mark them - * hard disabled in the PACA so that the local_irq_enable() done by - * our caller upon return propertly hard enables. + * We need to hard disable interrupts, the local_irq_enable() done by + * our caller upon return will hard re-enable. */ hard_irq_disable(); - get_paca()->hard_enabled = 0; ctrl = mfspr(SPRN_CTRLF); diff --git a/arch/um/Kconfig b/arch/um/Kconfig index b9c0f307a8f..c504312219b 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -277,7 +277,8 @@ config HIGHMEM config KERNEL_STACK_ORDER int "Kernel stack size order" - default 2 + default 1 if 64BIT + default 0 if !64BIT help This option determines the size of UML kernel stacks. They will be 1 << order pages. The default is OK unless you're running Valgrind diff --git a/arch/um/defconfig b/arch/um/defconfig index f938fa82214..a54d0efecae 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -86,7 +86,7 @@ CONFIG_MCONSOLE=y # CONFIG_MAGIC_SYSRQ is not set CONFIG_NEST_LEVEL=0 # CONFIG_HIGHMEM is not set -CONFIG_KERNEL_STACK_ORDER=2 +CONFIG_KERNEL_STACK_ORDER=0 CONFIG_UML_REAL_TIME_CLOCK=y # diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 5593a802708..541f4a8ca51 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -28,3 +28,5 @@ DEFINE(UM_NR_CPUS, NR_CPUS); /* For crypto assembler code. */ DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); + +DEFINE(UM_THREAD_SIZE, THREAD_SIZE); diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 50a49691e0e..8d7f7c1cb9c 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -117,4 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs); extern void copy_sc(union uml_pt_regs *regs, void *from); +unsigned long to_irq_stack(int sig, unsigned long *mask_out); +unsigned long from_irq_stack(int nested); + #endif diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 688d181b5f8..4d9fb26387d 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -272,7 +272,6 @@ extern void do_longjmp(void *p, int val); /* util.c */ extern void stack_protections(unsigned long address); -extern void task_protections(unsigned long address); extern int raw(int fd); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(char *buf, int len); diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index e36f92b463c..87a4e4427d8 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -97,6 +97,8 @@ SECTIONS .data : { . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ *(.data.init_task) + . = ALIGN(KERNEL_STACK_SIZE); + *(.data.init_irqstack) *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index cda91aa8e70..d4f1d1ab252 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com) * Licensed under the GPL */ @@ -33,28 +33,20 @@ EXPORT_SYMBOL(init_task); /* * Initial thread structure. * - * We need to make sure that this is 16384-byte aligned due to the + * 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 -__attribute__((__section__(".data.init_task"))) = -{ INIT_THREAD_INFO(init_task) }; +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +union thread_union cpu0_irqstack + __attribute__((__section__(".data.init_irqstack"))) = + { INIT_THREAD_INFO(init_task) }; void unprotect_stack(unsigned long stack) { - os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, - 1, 1, 0); + os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 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 8f2ed369031..dba04d88b43 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) * Licensed under the GPL * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: @@ -32,6 +32,7 @@ #include "sigio.h" #include "um_malloc.h" #include "misc_constants.h" +#include "as-layout.h" /* * Generic, controller-independent functions: @@ -53,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v) if (i < NR_IRQS) { spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; - if (!action) + if (!action) goto skip; seq_printf(p, "%3d: ",i); #ifndef CONFIG_SMP @@ -468,3 +469,113 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler) out: return err; } + +/* + * IRQ stack entry and exit: + * + * Unlike i386, UML doesn't receive IRQs on the normal kernel stack + * and switch over to the IRQ stack after some preparation. We use + * sigaltstack to receive signals on a separate stack from the start. + * These two functions make sure the rest of the kernel won't be too + * upset by being on a different stack. The IRQ stack has a + * thread_info structure at the bottom so that current et al continue + * to work. + * + * to_irq_stack copies the current task's thread_info to the IRQ stack + * thread_info and sets the tasks's stack to point to the IRQ stack. + * + * from_irq_stack copies the thread_info struct back (flags may have + * been modified) and resets the task's stack pointer. + * + * Tricky bits - + * + * What happens when two signals race each other? UML doesn't block + * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal + * could arrive while a previous one is still setting up the + * thread_info. + * + * There are three cases - + * The first interrupt on the stack - sets up the thread_info and + * handles the interrupt + * A nested interrupt interrupting the copying of the thread_info - + * can't handle the interrupt, as the stack is in an unknown state + * A nested interrupt not interrupting the copying of the + * thread_info - doesn't do any setup, just handles the interrupt + * + * The first job is to figure out whether we interrupted stack setup. + * This is done by xchging the signal mask with thread_info->pending. + * If the value that comes back is zero, then there is no setup in + * progress, and the interrupt can be handled. If the value is + * non-zero, then there is stack setup in progress. In order to have + * the interrupt handled, we leave our signal in the mask, and it will + * be handled by the upper handler after it has set up the stack. + * + * Next is to figure out whether we are the outer handler or a nested + * one. As part of setting up the stack, thread_info->real_thread is + * set to non-NULL (and is reset to NULL on exit). This is the + * nesting indicator. If it is non-NULL, then the stack is already + * set up and the handler can run. + */ + +static unsigned long pending_mask; + +unsigned long to_irq_stack(int sig, unsigned long *mask_out) +{ + struct thread_info *ti; + unsigned long mask, old; + int nested; + + mask = xchg(&pending_mask, 1 << sig); + if(mask != 0){ + /* If any interrupts come in at this point, we want to + * make sure that their bits aren't lost by our + * putting our bit in. So, this loop accumulates bits + * until xchg returns the same value that we put in. + * When that happens, there were no new interrupts, + * and pending_mask contains a bit for each interrupt + * that came in. + */ + old = 1 << sig; + do { + old |= mask; + mask = xchg(&pending_mask, old); + } while(mask != old); + return 1; + } + + ti = current_thread_info(); + nested = (ti->real_thread != NULL); + if(!nested){ + struct task_struct *task; + struct thread_info *tti; + + task = cpu_tasks[ti->cpu].task; + tti = task_thread_info(task); + *ti = *tti; + ti->real_thread = tti; + task->stack = ti; + } + + mask = xchg(&pending_mask, 0); + *mask_out |= mask | nested; + return 0; +} + +unsigned long from_irq_stack(int nested) +{ + struct thread_info *ti, *to; + unsigned long mask; + + ti = current_thread_info(); + + pending_mask = 1; + + to = ti->real_thread; + current->stack = to; + ti->real_thread = NULL; + *to = *ti; + + mask = xchg(&pending_mask, 0); + return mask & ~1; +} + diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index a96ae1a0610..2a69a7ce579 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -163,8 +163,12 @@ static int start_kernel_proc(void *unused) extern int userspace_pid[]; +extern char cpu0_irqstack[]; + int start_uml_skas(void) { + stack_protections((unsigned long) &cpu0_irqstack); + set_sigstack(cpu0_irqstack, THREAD_SIZE); if(proc_mm) userspace_pid[0] = start_userspace(0); diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index 98e21743e60..40126cb5180 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -57,7 +57,7 @@ void flush_thread_tt(void) enable_timer(); free_page(stack); protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current_thread); + stack_protections((unsigned long) current_thread); force_flush_all(); unblock_signals(); } diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index c631303cb80..74347adf81b 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -209,7 +209,7 @@ void finish_fork_handler(int sig) if(current->mm != current->parent->mm) protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current_thread); + stack_protections((unsigned long) current_thread); free_page(current->thread.temp_stack); local_irq_disable(); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 1cf954a47fd..ecc458fe51b 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -459,7 +459,7 @@ int __init linux_main(int argc, char **argv) uml_postsetup(); - task_protections((unsigned long) &init_thread_info); + stack_protections((unsigned long) &init_thread_info); os_flush_stdout(); return CHOOSE_MODE(start_uml_tt(), start_uml_skas()); diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index f6301274cf3..bc59f97e34d 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -59,6 +59,8 @@ SECTIONS { . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ *(.data.init_task) + . = ALIGN(KERNEL_STACK_SIZE); + *(.data.init_irqstack) *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 48d49341530..18e5c8b67eb 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -61,15 +61,19 @@ void sig_handler(int sig, struct sigcontext *sc) static void real_alarm_handler(int sig, struct sigcontext *sc) { + union uml_pt_regs regs; + if(sig == SIGALRM) switch_timers(0); - CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, - sig, sc); + if(sc != NULL) + copy_sc(®s, sc); + regs.skas.is_user = 0; + unblock_signals(); + timer_handler(sig, ®s); if(sig == SIGALRM) switch_timers(1); - } void alarm_handler(int sig, struct sigcontext *sc) @@ -113,6 +117,46 @@ void remove_sigstack(void) void (*handlers[_NSIG])(int sig, struct sigcontext *sc); +void handle_signal(int sig, struct sigcontext *sc) +{ + unsigned long pending = 0; + + do { + int nested, bail; + + /* + * pending comes back with one bit set for each + * interrupt that arrived while setting up the stack, + * plus a bit for this interrupt, plus the zero bit is + * set if this is a nested interrupt. + * If bail is true, then we interrupted another + * handler setting up the stack. In this case, we + * have to return, and the upper handler will deal + * with this interrupt. + */ + bail = to_irq_stack(sig, &pending); + if(bail) + return; + + nested = pending & 1; + pending &= ~1; + + while((sig = ffs(pending)) != 0){ + sig--; + pending &= ~(1 << sig); + (*handlers[sig])(sig, sc); + } + + /* Again, pending comes back with a mask of signals + * that arrived while tearing down the stack. If this + * is non-zero, we just go back, set up the stack + * again, and handle the new interrupts. + */ + if(!nested) + pending = from_irq_stack(nested); + } while(pending); +} + extern void hard_handler(int sig); void set_handler(int sig, void (*handler)(int), int flags, ...) diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 6a0e466d01e..f9d2f8545af 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -288,7 +288,8 @@ int start_userspace(unsigned long stub_stack) void userspace(union uml_pt_regs *regs) { int err, status, op, pid = userspace_pid[0]; - int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ + /* To prevent races if using_sysemu changes under us.*/ + int local_using_sysemu; while(1){ restore_registers(pid, regs); @@ -296,7 +297,8 @@ void userspace(union uml_pt_regs *regs) /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); - op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL)); + op = SELECT_PTRACE_OPERATION(local_using_sysemu, + singlestepping(NULL)); err = ptrace(op, pid, 0, 0); if(err) @@ -490,8 +492,8 @@ void map_stub_pages(int fd, unsigned long code, void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) { (*buf)[0].JB_IP = (unsigned long) handler; - (*buf)[0].JB_SP = (unsigned long) stack + - (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *); + (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE - + sizeof(void *); } #define INIT_JMP_NEW_THREAD 0 @@ -533,8 +535,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) case INIT_JMP_NEW_THREAD: (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; (*switch_buf)[0].JB_SP = (unsigned long) stack + - (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - - sizeof(void *); + UM_THREAD_SIZE - sizeof(void *); break; case INIT_JMP_CALLBACK: (*cb_proc)(cb_arg); diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c index 0d3eae51835..f311609f93d 100644 --- a/arch/um/os-Linux/sys-i386/signal.c +++ b/arch/um/os-Linux/sys-i386/signal.c @@ -1,15 +1,13 @@ /* - * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <signal.h> -extern void (*handlers[])(int sig, struct sigcontext *sc); +extern void handle_signal(int sig, struct sigcontext *sc); void hard_handler(int sig) { - struct sigcontext *sc = (struct sigcontext *) (&sig + 1); - - (*handlers[sig])(sig, sc); + handle_signal(sig, (struct sigcontext *) (&sig + 1)); } diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c index 3f369e5f976..82a388822cd 100644 --- a/arch/um/os-Linux/sys-x86_64/signal.c +++ b/arch/um/os-Linux/sys-x86_64/signal.c @@ -1,16 +1,16 @@ /* - * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <signal.h> -extern void (*handlers[])(int sig, struct sigcontext *sc); +extern void handle_signal(int sig, struct sigcontext *sc); void hard_handler(int sig) { struct ucontext *uc; asm("movq %%rdx, %0" : "=r" (uc)); - (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext); + handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext); } diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index c307a89ed25..7cbcf484e13 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -33,25 +33,8 @@ void stack_protections(unsigned long address) { - int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - - if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0) - panic("protecting stack failed, errno = %d", errno); -} - -void task_protections(unsigned long address) -{ - unsigned long guard = address + UM_KERN_PAGE_SIZE; - unsigned long stack = guard + UM_KERN_PAGE_SIZE; - int prot = 0, pages; - -#ifdef notdef - if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0) - panic("protecting guard page failed, errno = %d", errno); -#endif - pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; - prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0) + if(mprotect((void *) address, UM_THREAD_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC) < 0) panic("protecting stack failed, errno = %d", errno); } @@ -72,7 +55,7 @@ int raw(int fd) /* XXX tcsetattr could have applied only some changes * (and cfmakeraw() is a set of changes) */ - return(0); + return 0; } void setup_machinename(char *machine_out) diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index f2106837827..52be79beb30 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -716,4 +716,7 @@ ia32_sys_call_table: .quad sys_getcpu .quad sys_epoll_pwait .quad compat_sys_utimensat /* 320 */ + .quad sys_signalfd + .quad sys_timerfd + .quad sys_eventfd ia32_syscall_end: diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index 213d90e0475..6c34bdd22e2 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c @@ -62,13 +62,6 @@ void __init x86_64_start_kernel(char * real_mode_data) { int i; - /* - * Make sure kernel is aligned to 2MB address. Catching it at compile - * time is better. Change your config file and compile the kernel - * for a 2MB aligned address (CONFIG_PHYSICAL_START) - */ - BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1)); - /* clear bss before set_intr_gate with early_idt_handler */ clear_bss(); |