diff options
Diffstat (limited to 'arch/frv/kernel')
-rw-r--r-- | arch/frv/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/frv/kernel/entry.S | 2 | ||||
-rw-r--r-- | arch/frv/kernel/frv_ksyms.c | 27 | ||||
-rw-r--r-- | arch/frv/kernel/futex.c | 242 | ||||
-rw-r--r-- | arch/frv/kernel/irq.c | 17 | ||||
-rw-r--r-- | arch/frv/kernel/module.c | 80 | ||||
-rw-r--r-- | arch/frv/kernel/pm.c | 2 | ||||
-rw-r--r-- | arch/frv/kernel/process.c | 26 | ||||
-rw-r--r-- | arch/frv/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/frv/kernel/signal.c | 239 | ||||
-rw-r--r-- | arch/frv/kernel/time.c | 3 | ||||
-rw-r--r-- | arch/frv/kernel/traps.c | 3 | ||||
-rw-r--r-- | arch/frv/kernel/uaccess.c | 7 | ||||
-rw-r--r-- | arch/frv/kernel/vmlinux.lds.S | 1 |
14 files changed, 491 insertions, 162 deletions
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile index 981c2c7dec0d..5a827b349b5e 100644 --- a/arch/frv/kernel/Makefile +++ b/arch/frv/kernel/Makefile @@ -20,3 +20,5 @@ obj-$(CONFIG_FUJITSU_MB93493) += irq-mb93493.o obj-$(CONFIG_PM) += pm.o cmode.o obj-$(CONFIG_MB93093_PDK) += pm-mb93093.o obj-$(CONFIG_SYSCTL) += sysctl.o +obj-$(CONFIG_FUTEX) += futex.o +obj-$(CONFIG_MODULES) += module.o diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index ad10ea595459..5f6548388b74 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -1076,7 +1076,7 @@ __entry_work_notifysig: LEDS 0x6410 ori.p gr4,#0,gr8 call do_notify_resume - bra __entry_return_direct + bra __entry_resume_userspace # perform syscall entry tracing __syscall_trace_entry: diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index 1a76d5247190..0f1c6cbc4f50 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -16,17 +16,16 @@ #include <asm/semaphore.h> #include <asm/checksum.h> #include <asm/hardirq.h> -#include <asm/current.h> +#include <asm/cacheflush.h> -extern void dump_thread(struct pt_regs *, struct user *); extern long __memcpy_user(void *dst, const void *src, size_t count); +extern long __memset_user(void *dst, const void *src, size_t count); /* platform dependent support */ EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); @@ -50,7 +49,11 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(__res_bus_clock_speed_HZ); EXPORT_SYMBOL(__page_offset); EXPORT_SYMBOL(__memcpy_user); -EXPORT_SYMBOL(flush_dcache_page); +EXPORT_SYMBOL(__memset_user); +EXPORT_SYMBOL(frv_dcache_writeback); +EXPORT_SYMBOL(frv_cache_invalidate); +EXPORT_SYMBOL(frv_icache_invalidate); +EXPORT_SYMBOL(frv_cache_wback_inv); #ifndef CONFIG_MMU EXPORT_SYMBOL(memory_start); @@ -72,6 +75,9 @@ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(__outsl_ns); +EXPORT_SYMBOL(__insl_ns); + EXPORT_SYMBOL(get_wchan); #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS @@ -80,14 +86,13 @@ EXPORT_SYMBOL(atomic_test_and_OR_mask); EXPORT_SYMBOL(atomic_test_and_XOR_mask); EXPORT_SYMBOL(atomic_add_return); EXPORT_SYMBOL(atomic_sub_return); -EXPORT_SYMBOL(__xchg_8); -EXPORT_SYMBOL(__xchg_16); EXPORT_SYMBOL(__xchg_32); -EXPORT_SYMBOL(__cmpxchg_8); -EXPORT_SYMBOL(__cmpxchg_16); EXPORT_SYMBOL(__cmpxchg_32); #endif +EXPORT_SYMBOL(__debug_bug_printk); +EXPORT_SYMBOL(__delay_loops_MHz); + /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that @@ -101,6 +106,8 @@ extern void __divdi3(void); extern void __lshrdi3(void); extern void __moddi3(void); extern void __muldi3(void); +extern void __mulll(void); +extern void __umulll(void); extern void __negdi2(void); extern void __ucmpdi2(void); extern void __udivdi3(void); @@ -116,8 +123,10 @@ EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__lshrdi3); //EXPORT_SYMBOL(__moddi3); EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__mulll); +EXPORT_SYMBOL(__umulll); EXPORT_SYMBOL(__negdi2); -//EXPORT_SYMBOL(__ucmpdi2); +EXPORT_SYMBOL(__ucmpdi2); //EXPORT_SYMBOL(__udivdi3); //EXPORT_SYMBOL(__udivmoddi4); //EXPORT_SYMBOL(__umoddi3); diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c new file mode 100644 index 000000000000..eae874a970c6 --- /dev/null +++ b/arch/frv/kernel/futex.c @@ -0,0 +1,242 @@ +/* futex.c: futex operations + * + * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/futex.h> +#include <asm/futex.h> +#include <asm/errno.h> +#include <asm/uaccess.h> + +/* + * the various futex operations; MMU fault checking is ignored under no-MMU + * conditions + */ +static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval) +{ + int oldval, ret; + + asm("0: \n" + " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ + " ckeq icc3,cc7 \n" + "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ + " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ + "2: cst.p %3,%M0 ,cc3,#1 \n" + " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ + " beq icc3,#0,0b \n" + " setlos 0,%2 \n" + "3: \n" + ".subsection 2 \n" + "4: setlos %5,%2 \n" + " bra 3b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .balign 8 \n" + " .long 1b,4b \n" + " .long 2b,4b \n" + ".previous" + : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg) + : "3"(oparg), "i"(-EFAULT) + : "memory", "cc7", "cc3", "icc3" + ); + + *_oldval = oldval; + return ret; +} + +static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval) +{ + int oldval, ret; + + asm("0: \n" + " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ + " ckeq icc3,cc7 \n" + "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ + " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ + " add %1,%3,%3 \n" + "2: cst.p %3,%M0 ,cc3,#1 \n" + " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ + " beq icc3,#0,0b \n" + " setlos 0,%2 \n" + "3: \n" + ".subsection 2 \n" + "4: setlos %5,%2 \n" + " bra 3b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .balign 8 \n" + " .long 1b,4b \n" + " .long 2b,4b \n" + ".previous" + : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg) + : "3"(oparg), "i"(-EFAULT) + : "memory", "cc7", "cc3", "icc3" + ); + + *_oldval = oldval; + return ret; +} + +static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval) +{ + int oldval, ret; + + asm("0: \n" + " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ + " ckeq icc3,cc7 \n" + "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ + " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ + " or %1,%3,%3 \n" + "2: cst.p %3,%M0 ,cc3,#1 \n" + " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ + " beq icc3,#0,0b \n" + " setlos 0,%2 \n" + "3: \n" + ".subsection 2 \n" + "4: setlos %5,%2 \n" + " bra 3b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .balign 8 \n" + " .long 1b,4b \n" + " .long 2b,4b \n" + ".previous" + : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg) + : "3"(oparg), "i"(-EFAULT) + : "memory", "cc7", "cc3", "icc3" + ); + + *_oldval = oldval; + return ret; +} + +static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval) +{ + int oldval, ret; + + asm("0: \n" + " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ + " ckeq icc3,cc7 \n" + "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ + " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ + " and %1,%3,%3 \n" + "2: cst.p %3,%M0 ,cc3,#1 \n" + " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ + " beq icc3,#0,0b \n" + " setlos 0,%2 \n" + "3: \n" + ".subsection 2 \n" + "4: setlos %5,%2 \n" + " bra 3b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .balign 8 \n" + " .long 1b,4b \n" + " .long 2b,4b \n" + ".previous" + : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg) + : "3"(oparg), "i"(-EFAULT) + : "memory", "cc7", "cc3", "icc3" + ); + + *_oldval = oldval; + return ret; +} + +static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval) +{ + int oldval, ret; + + asm("0: \n" + " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ + " ckeq icc3,cc7 \n" + "1: ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ + " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ + " xor %1,%3,%3 \n" + "2: cst.p %3,%M0 ,cc3,#1 \n" + " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ + " beq icc3,#0,0b \n" + " setlos 0,%2 \n" + "3: \n" + ".subsection 2 \n" + "4: setlos %5,%2 \n" + " bra 3b \n" + ".previous \n" + ".section __ex_table,\"a\" \n" + " .balign 8 \n" + " .long 1b,4b \n" + " .long 2b,4b \n" + ".previous" + : "+U"(*uaddr), "=&r"(oldval), "=&r"(ret), "=r"(oparg) + : "3"(oparg), "i"(-EFAULT) + : "memory", "cc7", "cc3", "icc3" + ); + + *_oldval = oldval; + return ret; +} + +/*****************************************************************************/ +/* + * do the futex operations + */ +int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) +{ + int op = (encoded_op >> 28) & 7; + int cmp = (encoded_op >> 24) & 15; + int oparg = (encoded_op << 8) >> 20; + int cmparg = (encoded_op << 20) >> 20; + int oldval = 0, ret; + + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) + oparg = 1 << oparg; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + inc_preempt_count(); + + switch (op) { + case FUTEX_OP_SET: + ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval); + break; + case FUTEX_OP_ADD: + ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval); + break; + case FUTEX_OP_OR: + ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval); + break; + case FUTEX_OP_ANDN: + ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval); + break; + case FUTEX_OP_XOR: + ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval); + break; + default: + ret = -ENOSYS; + break; + } + + dec_preempt_count(); + + if (!ret) { + switch (cmp) { + case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; + case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; + case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; + case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; + case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; + case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; + default: ret = -ENOSYS; break; + } + } + + return ret; + +} /* end futex_atomic_op_inuser() */ diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 8c524cdd2717..59580c59c62c 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c @@ -32,6 +32,7 @@ #include <linux/irq.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/module.h> #include <asm/atomic.h> #include <asm/io.h> @@ -178,6 +179,8 @@ void disable_irq_nosync(unsigned int irq) spin_unlock_irqrestore(&level->lock, flags); } +EXPORT_SYMBOL(disable_irq_nosync); + /** * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable @@ -204,6 +207,8 @@ void disable_irq(unsigned int irq) #endif } +EXPORT_SYMBOL(disable_irq); + /** * enable_irq - enable handling of an irq * @irq: Interrupt to enable @@ -268,6 +273,8 @@ void enable_irq(unsigned int irq) spin_unlock_irqrestore(&level->lock, flags); } +EXPORT_SYMBOL(enable_irq); + /*****************************************************************************/ /* * handles all normal device IRQ's @@ -425,6 +432,8 @@ int request_irq(unsigned int irq, return retval; } +EXPORT_SYMBOL(request_irq); + /** * free_irq - free an interrupt * @irq: Interrupt line to free @@ -496,6 +505,8 @@ void free_irq(unsigned int irq, void *dev_id) } } +EXPORT_SYMBOL(free_irq); + /* * IRQ autodetection code.. * @@ -519,6 +530,8 @@ unsigned long probe_irq_on(void) return 0; } +EXPORT_SYMBOL(probe_irq_on); + /* * Return a mask of triggered interrupts (this * can handle only legacy ISA interrupts). @@ -542,6 +555,8 @@ unsigned int probe_irq_mask(unsigned long xmask) return 0; } +EXPORT_SYMBOL(probe_irq_mask); + /* * Return the one interrupt that triggered (this can * handle any interrupt source). @@ -571,6 +586,8 @@ int probe_irq_off(unsigned long xmask) return -1; } +EXPORT_SYMBOL(probe_irq_off); + /* this was setup_x86_irq but it seems pretty generic */ int setup_irq(unsigned int irq, struct irqaction *new) { diff --git a/arch/frv/kernel/module.c b/arch/frv/kernel/module.c new file mode 100644 index 000000000000..850d168f69fc --- /dev/null +++ b/arch/frv/kernel/module.c @@ -0,0 +1,80 @@ +/* module.c: FRV specific module loading bits + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * - Derived from arch/i386/kernel/module.c, Copyright (C) 2001 Rusty Russell. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + + return vmalloc_exec(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", me->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index 712c3c24c954..f0b8fff3e733 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -13,6 +13,7 @@ #include <linux/config.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/pm.h> #include <linux/pm_legacy.h> #include <linux/sched.h> @@ -27,6 +28,7 @@ #include "local.h" void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); extern void frv_change_cmode(int); diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 54a452136f00..0fff8a61ef2a 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -204,7 +204,7 @@ int copy_thread(int nr, unsigned long clone_flags, regs0 = __kernel_frame0_ptr; childregs0 = (struct pt_regs *) - ((unsigned long) p->thread_info + THREAD_SIZE - USER_CONTEXT_SIZE); + (task_stack_page(p) + THREAD_SIZE - USER_CONTEXT_SIZE); childregs = childregs0; /* set up the userspace frame (the only place that the USP is stored) */ @@ -220,7 +220,7 @@ int copy_thread(int nr, unsigned long clone_flags, *childregs = *regs; childregs->sp = (unsigned long) childregs0; childregs->next_frame = childregs0; - childregs->gr15 = (unsigned long) p->thread_info; + childregs->gr15 = (unsigned long) task_thread_info(p); childregs->gr29 = (unsigned long) p; } @@ -244,28 +244,6 @@ int copy_thread(int nr, unsigned long clone_flags, } /* end copy_thread() */ /* - * fill in the user structure for a core dump.. - */ -void dump_thread(struct pt_regs *regs, struct user *dump) -{ -#if 0 - /* changed the size calculations - should hopefully work better. lbt */ - dump->magic = CMAGIC; - dump->start_code = 0; - dump->start_stack = user_stack(regs) & ~(PAGE_SIZE - 1); - dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; - dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; - dump->u_dsize -= dump->u_tsize; - dump->u_ssize = 0; - - if (dump->start_stack < TASK_SIZE) - dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; - - dump->regs = *(struct user_context *) regs; -#endif -} - -/* * sys_execve() executes a new program. */ asmlinkage int sys_execve(char *name, char **argv, char **envp) diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index 767ebb55bd83..5908deae9607 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c @@ -787,6 +787,7 @@ void __init setup_arch(char **cmdline_p) #endif /* register those serial ports that are available */ +#ifdef CONFIG_FRV_ONCPU_SERIAL #ifndef CONFIG_GDBSTUB_UART0 __reg(UART0_BASE + UART_IER * 8) = 0; early_serial_setup(&__frv_uart0); @@ -795,6 +796,7 @@ void __init setup_arch(char **cmdline_p) __reg(UART1_BASE + UART_IER * 8) = 0; early_serial_setup(&__frv_uart1); #endif +#endif #if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH) /* we need to initialize the Flashrom device here since we might diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index d4ccc0728dfe..679c1d5cc958 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -35,74 +35,22 @@ struct fdpic_func_descriptor { unsigned long GOT; }; -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); - /* * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) { - sigset_t saveset; - mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; + current->saved_sigmask = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - __frame->gr8 = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(__frame, &saveset)) - /* return the signal number as the return value of this function - * - this is an utterly evil hack. syscalls should not invoke do_signal() - * as entry.S sets regs->gr8 to the return value of the system call - * - we can't just use sigpending() as we'd have to discard SIG_IGN signals - * and call waitpid() if SIGCHLD needed discarding - * - this only works on the i386 because it passes arguments to the signal - * handler on the stack, and the return value in EAX is effectively - * discarded - */ - return __frame->gr8; - } -} - -asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) -{ - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - __frame->gr8 = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(__frame, &saveset)) - /* return the signal number as the return value of this function - * - this is an utterly evil hack. syscalls should not invoke do_signal() - * as entry.S sets regs->gr8 to the return value of the system call - * - we can't just use sigpending() as we'd have to discard SIG_IGN signals - * and call waitpid() if SIGCHLD needed discarding - * - this only works on the i386 because it passes arguments to the signal - * handler on the stack, and the return value in EAX is effectively - * discarded - */ - return __frame->gr8; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } asmlinkage int sys_sigaction(int sig, @@ -276,13 +224,12 @@ static int setup_sigcontext(struct sigcontext __user *sc, unsigned long mask) * Determine which stack to use.. */ static inline void __user *get_sigframe(struct k_sigaction *ka, - struct pt_regs *regs, size_t frame_size) { unsigned long sp; /* Default to using normal stack */ - sp = regs->sp; + sp = __frame->sp; /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { @@ -291,18 +238,19 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, } return (void __user *) ((sp - frame_size) & ~7UL); + } /* end get_sigframe() */ /*****************************************************************************/ /* * */ -static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) +static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) { struct sigframe __user *frame; int rsig; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(ka, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; @@ -346,47 +294,51 @@ static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct p } /* set up registers for signal handler */ - regs->sp = (unsigned long) frame; - regs->lr = (unsigned long) &frame->retcode; - regs->gr8 = sig; + __frame->sp = (unsigned long) frame; + __frame->lr = (unsigned long) &frame->retcode; + __frame->gr8 = sig; if (get_personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor *) ka->sa.sa_handler; - __get_user(regs->pc, &funcptr->text); - __get_user(regs->gr15, &funcptr->GOT); + __get_user(__frame->pc, &funcptr->text); + __get_user(__frame->gr15, &funcptr->GOT); } else { - regs->pc = (unsigned long) ka->sa.sa_handler; - regs->gr15 = 0; + __frame->pc = (unsigned long) ka->sa.sa_handler; + __frame->gr15 = 0; } set_fs(USER_DS); + /* the tracer may want to single-step inside the handler */ + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); + #if DEBUG_SIG printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", - sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); + sig, current->comm, current->pid, frame, __frame->pc, + frame->pretcode); #endif - return; + return 0; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + return -EFAULT; + } /* end setup_frame() */ /*****************************************************************************/ /* * */ -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs * regs) +static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set) { struct rt_sigframe __user *frame; int rsig; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(ka, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; @@ -409,7 +361,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (__put_user(0, &frame->uc.uc_flags) || __put_user(0, &frame->uc.uc_link) || __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || - __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags) || + __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) || __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) goto give_sigsegv; @@ -440,34 +392,38 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } /* Set up registers for signal handler */ - regs->sp = (unsigned long) frame; - regs->lr = (unsigned long) &frame->retcode; - regs->gr8 = sig; - regs->gr9 = (unsigned long) &frame->info; + __frame->sp = (unsigned long) frame; + __frame->lr = (unsigned long) &frame->retcode; + __frame->gr8 = sig; + __frame->gr9 = (unsigned long) &frame->info; if (get_personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor *funcptr = (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; - __get_user(regs->pc, &funcptr->text); - __get_user(regs->gr15, &funcptr->GOT); + __get_user(__frame->pc, &funcptr->text); + __get_user(__frame->gr15, &funcptr->GOT); } else { - regs->pc = (unsigned long) ka->sa.sa_handler; - regs->gr15 = 0; + __frame->pc = (unsigned long) ka->sa.sa_handler; + __frame->gr15 = 0; } set_fs(USER_DS); + /* the tracer may want to single-step inside the handler */ + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); + #if DEBUG_SIG printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", - sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); + sig, current->comm, current->pid, frame, __frame->pc, + frame->pretcode); #endif - return; + return 0; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current); + return -EFAULT; } /* end setup_rt_frame() */ @@ -475,43 +431,51 @@ give_sigsegv: /* * OK, we're invoking a handler */ -static void handle_signal(unsigned long sig, siginfo_t *info, - struct k_sigaction *ka, sigset_t *oldset, - struct pt_regs *regs) +static int handle_signal(unsigned long sig, siginfo_t *info, + struct k_sigaction *ka, sigset_t *oldset) { + int ret; + /* Are we from a system call? */ - if (in_syscall(regs)) { + if (in_syscall(__frame)) { /* If so, check system call restarting.. */ - switch (regs->gr8) { + switch (__frame->gr8) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: - regs->gr8 = -EINTR; + __frame->gr8 = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->gr8 = -EINTR; + __frame->gr8 = -EINTR; break; } + /* fallthrough */ case -ERESTARTNOINTR: - regs->gr8 = regs->orig_gr8; - regs->pc -= 4; + __frame->gr8 = __frame->orig_gr8; + __frame->pc -= 4; } } /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(sig, ka, info, oldset, regs); + ret = setup_rt_frame(sig, ka, info, oldset); else - setup_frame(sig, ka, oldset, regs); + ret = setup_frame(sig, ka, oldset); + + if (ret == 0) { + 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, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + return ret; - 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, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); } /* end handle_signal() */ /*****************************************************************************/ @@ -520,10 +484,11 @@ static void handle_signal(unsigned long sig, siginfo_t *info, * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -int do_signal(struct pt_regs *regs, sigset_t *oldset) +static void do_signal(void) { struct k_sigaction ka; siginfo_t info; + sigset_t *oldset; int signr; /* @@ -532,45 +497,63 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) * kernel mode. Just return without doing anything * if so. */ - if (!user_mode(regs)) - return 1; + if (!user_mode(__frame)) + return; if (try_to_freeze()) goto no_signal; - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, &ka, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, __frame, NULL); if (signr > 0) { - handle_signal(signr, &info, &ka, oldset, regs); - return 1; + if (handle_signal(signr, &info, &ka, oldset) == 0) { + /* 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); + } + + return; } - no_signal: +no_signal: /* Did we come from a system call? */ - if (regs->syscallno >= 0) { + if (__frame->syscallno >= 0) { /* Restart the system call - no handlers present */ - if (regs->gr8 == -ERESTARTNOHAND || - regs->gr8 == -ERESTARTSYS || - regs->gr8 == -ERESTARTNOINTR) { - regs->gr8 = regs->orig_gr8; - regs->pc -= 4; - } + switch (__frame->gr8) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + __frame->gr8 = __frame->orig_gr8; + __frame->pc -= 4; + break; - if (regs->gr8 == -ERESTART_RESTARTBLOCK){ - regs->gr8 = __NR_restart_syscall; - regs->pc -= 4; + case -ERESTART_RESTARTBLOCK: + __frame->gr8 = __NR_restart_syscall; + __frame->pc -= 4; + break; } } - return 0; + /* if there's no signal to deliver, we just put the saved sigmask + * back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + } /* end do_signal() */ /*****************************************************************************/ /* * notification of userspace execution resumption - * - triggered by current->work.notify_resume + * - triggered by the TIF_WORK_MASK flags */ asmlinkage void do_notify_resume(__u32 thread_info_flags) { @@ -579,7 +562,7 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) clear_thread_flag(TIF_SINGLESTEP); /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(__frame, NULL); + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + do_signal(); } /* end do_notify_resume() */ diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 2e9741227b73..24cf85f89e40 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -189,6 +189,8 @@ void do_gettimeofday(struct timeval *tv) tv->tv_usec = usec; } +EXPORT_SYMBOL(do_gettimeofday); + int do_settimeofday(struct timespec *tv) { time_t wtm_sec, sec = tv->tv_sec; @@ -218,6 +220,7 @@ int do_settimeofday(struct timespec *tv) clock_was_set(); return 0; } + EXPORT_SYMBOL(do_settimeofday); /* diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c index 89073cae4b5d..9eb84b2e6abc 100644 --- a/arch/frv/kernel/traps.c +++ b/arch/frv/kernel/traps.c @@ -19,6 +19,7 @@ #include <linux/string.h> #include <linux/linkage.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/setup.h> #include <asm/fpu.h> @@ -250,6 +251,8 @@ void dump_stack(void) show_stack(NULL, NULL); } +EXPORT_SYMBOL(dump_stack); + void show_stack(struct task_struct *task, unsigned long *sp) { } diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c index f3fd58a5bc4a..9b751c0f0e84 100644 --- a/arch/frv/kernel/uaccess.c +++ b/arch/frv/kernel/uaccess.c @@ -10,6 +10,7 @@ */ #include <linux/mm.h> +#include <linux/module.h> #include <asm/uaccess.h> /*****************************************************************************/ @@ -58,8 +59,11 @@ long strncpy_from_user(char *dst, const char *src, long count) memset(p, 0, count); /* clear remainder of buffer [security] */ return err; + } /* end strncpy_from_user() */ +EXPORT_SYMBOL(strncpy_from_user); + /*****************************************************************************/ /* * Return the size of a string (including the ending 0) @@ -92,4 +96,7 @@ long strnlen_user(const char *src, long count) } return p - src + 1; /* return length including NUL */ + } /* end strnlen_user() */ + +EXPORT_SYMBOL(strnlen_user); diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index fceafd2cc202..f474534ba78a 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -112,6 +112,7 @@ SECTIONS #endif ) SCHED_TEXT + LOCK_TEXT *(.fixup) *(.gnu.warning) *(.exitcall.exit) |