diff options
Diffstat (limited to 'arch/openrisc/kernel')
| -rw-r--r-- | arch/openrisc/kernel/Makefile | 2 | ||||
| -rw-r--r-- | arch/openrisc/kernel/entry.S | 79 | ||||
| -rw-r--r-- | arch/openrisc/kernel/head.S | 13 | ||||
| -rw-r--r-- | arch/openrisc/kernel/idle.c | 78 | ||||
| -rw-r--r-- | arch/openrisc/kernel/module.c | 6 | ||||
| -rw-r--r-- | arch/openrisc/kernel/process.c | 1 | ||||
| -rw-r--r-- | arch/openrisc/kernel/prom.c | 76 | ||||
| -rw-r--r-- | arch/openrisc/kernel/setup.c | 33 | ||||
| -rw-r--r-- | arch/openrisc/kernel/signal.c | 248 | ||||
| -rw-r--r-- | arch/openrisc/kernel/traps.c | 11 | ||||
| -rw-r--r-- | arch/openrisc/kernel/vmlinux.h | 4 |
11 files changed, 191 insertions, 360 deletions
diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile index 35f92ce51c2..ec6d9d37cef 100644 --- a/arch/openrisc/kernel/Makefile +++ b/arch/openrisc/kernel/Makefile @@ -4,7 +4,7 @@ extra-y := head.o vmlinux.lds -obj-y := setup.o idle.o or32_ksyms.o process.o dma.o \ +obj-y := setup.o or32_ksyms.o process.o dma.o \ traps.o time.o irq.o entry.o ptrace.o signal.o \ sys_call_table.o diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index 5e5b30601bb..fec8bf97d80 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -201,12 +201,17 @@ EXCEPTION_ENTRY(_bus_fault_handler) l.nop /* ---[ 0x300: Data Page Fault exception ]------------------------------- */ +EXCEPTION_ENTRY(_dtlb_miss_page_fault_handler) + l.and r5,r5,r0 + l.j 1f + l.nop EXCEPTION_ENTRY(_data_page_fault_handler) /* set up parameters for do_page_fault */ + l.ori r5,r0,0x300 // exception vector +1: l.addi r3,r1,0 // pt_regs /* r4 set be EXCEPTION_HANDLE */ // effective address of fault - l.ori r5,r0,0x300 // exception vector /* * __PHX__: TODO @@ -276,12 +281,17 @@ EXCEPTION_ENTRY(_data_page_fault_handler) l.nop /* ---[ 0x400: Insn Page Fault exception ]------------------------------- */ +EXCEPTION_ENTRY(_itlb_miss_page_fault_handler) + l.and r5,r5,r0 + l.j 1f + l.nop EXCEPTION_ENTRY(_insn_page_fault_handler) /* set up parameters for do_page_fault */ + l.ori r5,r0,0x400 // exception vector +1: l.addi r3,r1,0 // pt_regs /* r4 set be EXCEPTION_HANDLE */ // effective address of fault - l.ori r5,r0,0x400 // exception vector l.ori r6,r0,0x0 // !write access /* call fault.c handler in or32/mm/fault.c */ @@ -843,37 +853,44 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00) /* ========================================================[ return ] === */ +_resume_userspace: + DISABLE_INTERRUPTS(r3,r4) + l.lwz r4,TI_FLAGS(r10) + l.andi r13,r4,_TIF_WORK_MASK + l.sfeqi r13,0 + l.bf _restore_all + l.nop + _work_pending: - /* - * if (current_thread_info->flags & _TIF_NEED_RESCHED) - * schedule(); - */ - l.lwz r5,TI_FLAGS(r10) - l.andi r3,r5,_TIF_NEED_RESCHED - l.sfnei r3,0 - l.bnf _work_notifysig + l.lwz r5,PT_ORIG_GPR11(r1) + l.sfltsi r5,0 + l.bnf 1f l.nop - l.jal schedule + l.andi r5,r5,0 +1: + l.jal do_work_pending + l.ori r3,r1,0 /* pt_regs */ + + l.sfeqi r11,0 + l.bf _restore_all l.nop - l.j _resume_userspace + l.sfltsi r11,0 + l.bnf 1f l.nop - -/* Handle pending signals and notify-resume requests. - * do_notify_resume must be passed the latest pushed pt_regs, not - * necessarily the "userspace" ones. Also, pt_regs->syscallno - * must be set so that the syscall restart functionality works. - */ -_work_notifysig: - l.jal do_notify_resume - l.ori r3,r1,0 /* pt_regs */ - -_resume_userspace: - DISABLE_INTERRUPTS(r3,r4) - l.lwz r3,TI_FLAGS(r10) - l.andi r3,r3,_TIF_WORK_MASK - l.sfnei r3,0 - l.bf _work_pending + l.and r11,r11,r0 + l.ori r11,r11,__NR_restart_syscall + l.j _syscall_check_trace_enter l.nop +1: + l.lwz r11,PT_ORIG_GPR11(r1) + /* Restore arg registers */ + l.lwz r3,PT_GPR3(r1) + l.lwz r4,PT_GPR4(r1) + l.lwz r5,PT_GPR5(r1) + l.lwz r6,PT_GPR6(r1) + l.lwz r7,PT_GPR7(r1) + l.j _syscall_check_trace_enter + l.lwz r8,PT_GPR8(r1) _restore_all: RESTORE_ALL @@ -1040,7 +1057,7 @@ ENTRY(_switch) * we are expected to have set up the arg to schedule_tail already, * hence we do so here unconditionally: */ - l.lwz r3,TI_STACK(r3) /* Load 'prev' as schedule_tail arg */ + l.lwz r3,TI_TASK(r3) /* Load 'prev' as schedule_tail arg */ l.jr r9 l.nop @@ -1083,10 +1100,6 @@ ENTRY(__sys_fork) l.j _fork_save_extra_regs_and_call l.addi r3,r1,0 -ENTRY(sys_sigaltstack) - l.j _sys_sigaltstack - l.addi r5,r1,0 - ENTRY(sys_rt_sigreturn) l.j _sys_rt_sigreturn l.addi r3,r1,0 diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index 1088b5fca3b..1d3c9c28ac2 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S @@ -19,6 +19,7 @@ #include <linux/threads.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/serial_reg.h> #include <asm/processor.h> #include <asm/page.h> #include <asm/mmu.h> @@ -291,9 +292,9 @@ /* Jump to .init code at _start which lives in the .head section * and will be discarded after boot. */ - LOAD_SYMBOL_2_GPR(r4, _start) - tophys (r3,r4) /* MMU disabled */ - l.jr r3 + LOAD_SYMBOL_2_GPR(r15, _start) + tophys (r13,r15) /* MMU disabled */ + l.jr r13 l.nop /* ---[ 0x200: BUS exception ]------------------------------------------- */ @@ -1069,8 +1070,7 @@ d_pte_not_present: EXCEPTION_LOAD_GPR4 EXCEPTION_LOAD_GPR5 EXCEPTION_LOAD_GPR6 - l.j _dispatch_do_dpage_fault - l.nop + EXCEPTION_HANDLE(_dtlb_miss_page_fault_handler) /* ==============================================[ ITLB miss handler ]=== */ ENTRY(itlb_miss_handler) @@ -1192,8 +1192,7 @@ i_pte_not_present: EXCEPTION_LOAD_GPR4 EXCEPTION_LOAD_GPR5 EXCEPTION_LOAD_GPR6 - l.j _dispatch_do_ipage_fault - l.nop + EXCEPTION_HANDLE(_itlb_miss_page_fault_handler) /* ==============================================[ boot tlb handlers ]=== */ diff --git a/arch/openrisc/kernel/idle.c b/arch/openrisc/kernel/idle.c deleted file mode 100644 index 7d618feb1b7..00000000000 --- a/arch/openrisc/kernel/idle.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * OpenRISC idle.c - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * Modifications for the OpenRISC architecture: - * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> - * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> - * - * 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. - * - * Idle daemon for or32. Idle daemon will handle any action - * that needs to be taken when the system becomes idle. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/tick.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/mmu.h> -#include <asm/cache.h> -#include <asm/pgalloc.h> - -void (*powersave) (void) = NULL; - -static inline void pm_idle(void) -{ - barrier(); -} - -void cpu_idle(void) -{ - set_thread_flag(TIF_POLLING_NRFLAG); - - /* endless idle loop with no priority at all */ - while (1) { - tick_nohz_idle_enter(); - rcu_idle_enter(); - - while (!need_resched()) { - check_pgt_cache(); - rmb(); - - clear_thread_flag(TIF_POLLING_NRFLAG); - - local_irq_disable(); - /* Don't trace irqs off for idle */ - stop_critical_timings(); - if (!need_resched() && powersave != NULL) - powersave(); - start_critical_timings(); - local_irq_enable(); - set_thread_flag(TIF_POLLING_NRFLAG); - } - - rcu_idle_exit(); - tick_nohz_idle_exit(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } -} diff --git a/arch/openrisc/kernel/module.c b/arch/openrisc/kernel/module.c index 10ff50f0202..ef872ae4c87 100644 --- a/arch/openrisc/kernel/module.c +++ b/arch/openrisc/kernel/module.c @@ -47,12 +47,10 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, *location = value; break; case R_OR32_CONST: - location = (uint16_t *)location + 1; - *((uint16_t *)location) = (uint16_t) (value); + *((uint16_t *)location + 1) = value; break; case R_OR32_CONSTH: - location = (uint16_t *)location + 1; - *((uint16_t *)location) = (uint16_t) (value >> 16); + *((uint16_t *)location + 1) = value >> 16; break; case R_OR32_JUMPTARG: value -= (uint32_t)location; diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 00c233bf0d0..386af258591 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -90,6 +90,7 @@ void show_regs(struct pt_regs *regs) { extern void show_registers(struct pt_regs *regs); + show_regs_print_info(KERN_DEFAULT); /* __PHX__ cleanup this mess */ show_registers(regs); } diff --git a/arch/openrisc/kernel/prom.c b/arch/openrisc/kernel/prom.c index 5869e3fa5dd..6a44340d1b1 100644 --- a/arch/openrisc/kernel/prom.c +++ b/arch/openrisc/kernel/prom.c @@ -18,89 +18,15 @@ * */ -#include <stdarg.h> -#include <linux/kernel.h> -#include <linux/string.h> #include <linux/init.h> -#include <linux/threads.h> -#include <linux/spinlock.h> #include <linux/types.h> -#include <linux/pci.h> -#include <linux/stringify.h> -#include <linux/delay.h> -#include <linux/initrd.h> -#include <linux/bitops.h> -#include <linux/module.h> -#include <linux/kexec.h> -#include <linux/debugfs.h> -#include <linux/irq.h> #include <linux/memblock.h> #include <linux/of_fdt.h> -#include <asm/prom.h> #include <asm/page.h> -#include <asm/processor.h> -#include <asm/irq.h> -#include <linux/io.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/sections.h> -#include <asm/setup.h> - -extern char cmd_line[COMMAND_LINE_SIZE]; - -void __init early_init_dt_add_memory_arch(u64 base, u64 size) -{ - size &= PAGE_MASK; - memblock_add(base, size); -} - -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) -{ - return __va(memblock_alloc(size, align)); -} void __init early_init_devtree(void *params) { - void *alloc; - - /* Setup flat device-tree pointer */ - initial_boot_params = params; - - - /* Retrieve various informations from the /chosen node of the - * device-tree, including the platform type, initrd location and - * size, TCE reserve, and more ... - */ - of_scan_flat_dt(early_init_dt_scan_chosen, cmd_line); - - /* Scan memory nodes and rebuild MEMBLOCKs */ - of_scan_flat_dt(early_init_dt_scan_root, NULL); - of_scan_flat_dt(early_init_dt_scan_memory, NULL); - - /* Save command line for /proc/cmdline and then parse parameters */ - strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); - + early_init_dt_scan(params); memblock_allow_resize(); - - /* We must copy the flattend device tree from init memory to regular - * memory because the device tree references the strings in it - * directly. - */ - - alloc = __va(memblock_alloc(initial_boot_params->totalsize, PAGE_SIZE)); - - memcpy(alloc, initial_boot_params, initial_boot_params->totalsize); - - initial_boot_params = alloc; -} - -#ifdef CONFIG_BLK_DEV_INITRD -void __init early_init_dt_setup_initrd_arch(unsigned long start, - unsigned long end) -{ - initrd_start = (unsigned long)__va(start); - initrd_end = (unsigned long)__va(end); - initrd_below_start_ok = 1; } -#endif diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c index f4d5bedc3b4..4fc7ccc0a2c 100644 --- a/arch/openrisc/kernel/setup.c +++ b/arch/openrisc/kernel/setup.c @@ -40,6 +40,7 @@ #include <linux/device.h> #include <linux/of_platform.h> +#include <asm/sections.h> #include <asm/segment.h> #include <asm/pgtable.h> #include <asm/types.h> @@ -50,8 +51,6 @@ #include "vmlinux.h" -char __initdata cmd_line[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; - static unsigned long __init setup_memory(void) { unsigned long bootmap_size; @@ -77,7 +76,7 @@ static unsigned long __init setup_memory(void) ram_start_pfn = PFN_UP(memory_start); /* free_ram_start_pfn is first page after kernel */ - free_ram_start_pfn = PFN_UP(__pa(&_end)); + free_ram_start_pfn = PFN_UP(__pa(_end)); ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM()); max_pfn = ram_end_pfn; @@ -209,15 +208,15 @@ void __init setup_cpuinfo(void) * Falls back on built-in device tree in case null pointer is passed. */ -void __init or32_early_setup(unsigned int fdt) +void __init or32_early_setup(void *fdt) { - if (fdt) { - early_init_devtree((void*) fdt); - printk(KERN_INFO "FDT at 0x%08x\n", fdt); - } else { - early_init_devtree(__dtb_start); - printk(KERN_INFO "Compiled-in FDT at %p\n", __dtb_start); + if (fdt) + pr_info("FDT at %p\n", fdt); + else { + fdt = __dtb_start; + pr_info("Compiled-in FDT at %p\n", fdt); } + early_init_devtree(fdt); } static int __init openrisc_device_probe(void) @@ -267,7 +266,7 @@ void __init detect_unit_config(unsigned long upr, unsigned long mask, * */ -void __cpuinit calibrate_delay(void) +void calibrate_delay(void) { const int *val; struct device_node *cpu = NULL; @@ -285,15 +284,15 @@ void __init setup_arch(char **cmdline_p) { unsigned long max_low_pfn; - unflatten_device_tree(); + unflatten_and_copy_device_tree(); setup_cpuinfo(); /* process 1's initial memory region is the kernel code/data */ - init_mm.start_code = (unsigned long)&_stext; - init_mm.end_code = (unsigned long)&_etext; - init_mm.end_data = (unsigned long)&_edata; - init_mm.brk = (unsigned long)&_end; + init_mm.start_code = (unsigned long)_stext; + init_mm.end_code = (unsigned long)_etext; + init_mm.end_data = (unsigned long)_edata; + init_mm.brk = (unsigned long)_end; #ifdef CONFIG_BLK_DEV_INITRD initrd_start = (unsigned long)&__initrd_start; @@ -316,7 +315,7 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif - *cmdline_p = cmd_line; + *cmdline_p = boot_command_line; printk(KERN_INFO "OpenRISC Linux -- http://openrisc.net\n"); } diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index ddedc8a7786..66775bc07a8 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -28,30 +28,24 @@ #include <linux/tracehook.h> #include <asm/processor.h> +#include <asm/syscall.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #define DEBUG_SIG 0 -asmlinkage long -_sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) -{ - return do_sigaltstack(uss, uoss, regs->sp); -} - struct rt_sigframe { - struct siginfo *pinfo; - void *puc; struct siginfo info; struct ucontext uc; unsigned char retcode[16]; /* trampoline code */ }; -static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +static int restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc) { - unsigned int err = 0; + int err = 0; - /* Alwys make any pending restarted system call return -EINTR */ + /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; /* @@ -59,25 +53,21 @@ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) * (sc is already checked for VERIFY_READ since the sigframe was * checked in sys_sigreturn previously) */ - if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long))) - goto badframe; - if (__copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long))) - goto badframe; - if (__copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long))) - goto badframe; + err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)); + err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long)); + err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long)); /* make sure the SM-bit is cleared so user-mode cannot fool us */ regs->sr &= ~SPR_SR_SM; + regs->orig_gpr11 = -1; /* Avoid syscall restart checks */ + /* TODO: the other ports use regs->orig_XX to disable syscall checks * after this completes, but we don't use that mechanism. maybe we can * use it now ? */ return err; - -badframe: - return 1; } asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) @@ -103,9 +93,7 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) + if (restore_altstack(&frame->uc.uc_stack)) goto badframe; return regs->gpr[11]; @@ -119,21 +107,18 @@ badframe: * Set up a signal frame. */ -static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, - unsigned long mask) +static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; /* copy the regs */ - + /* There should be no need to save callee-saved registers here... + * ...but we save them anyway. Revisit this + */ err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long)); err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long)); - /* then some other stuff */ - - err |= __put_user(mask, &sc->oldmask); - return err; } @@ -181,58 +166,53 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, * trampoline which performs the syscall sigreturn, or a provided * user-mode trampoline. */ -static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) +static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, + struct pt_regs *regs) { struct rt_sigframe *frame; unsigned long return_ip; int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; + return -EFAULT; - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); + /* Create siginfo. */ + if (ksig->ka.sa.sa_flags & SA_SIGINFO) + err |= copy_siginfo_to_user(&frame->info, &ksig->info); - if (ka->sa.sa_flags & SA_SIGINFO) - err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto give_sigsegv; - - /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(NULL, &frame->uc.uc_link); - err |= __put_user((void *)current->sas_ss_sp, - &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + err |= __save_altstack(&frame->uc.uc_stack, regs->sp); + err |= setup_sigcontext(regs, &frame->uc.uc_mcontext); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) - goto give_sigsegv; + return -EFAULT; /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; - /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */ - err |= __put_user(0xa960, (short *)(frame->retcode + 0)); - err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); + /* This is: + l.ori r11,r0,__NR_sigreturn + l.sys 1 + */ + err |= __put_user(0xa960, (short *)(frame->retcode + 0)); + err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2)); err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4)); err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8)); if (err) - goto give_sigsegv; + return -EFAULT; /* TODO what is the current->exec_domain stuff and invmap ? */ /* Set up registers for signal handler */ - regs->pc = (unsigned long)ka->sa.sa_handler; /* what we enter NOW */ + regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */ regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */ - regs->gpr[3] = (unsigned long)sig; /* arg 1: signo */ + regs->gpr[3] = (unsigned long)ksig->sig; /* arg 1: signo */ regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */ regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */ @@ -240,25 +220,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->sp = (unsigned long)frame; return 0; - -give_sigsegv: - force_sigsegv(sig, current); - return -EFAULT; } static inline void -handle_signal(unsigned long sig, - siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) +handle_signal(struct ksignal *ksig, struct pt_regs *regs) { int ret; - ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs); - if (ret) - return; + ret = setup_rt_frame(ksig, sigmask_to_save(), regs); - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP)); } /* @@ -273,82 +244,99 @@ handle_signal(unsigned long sig, * mode below. */ -void do_signal(struct pt_regs *regs) +int do_signal(struct pt_regs *regs, int syscall) { - siginfo_t info; - int signr; - struct k_sigaction ka; - - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - - /* If we are coming out of a syscall then we need - * to check if the syscall was interrupted and wants to be - * restarted after handling the signal. If so, the original - * syscall number is put back into r11 and the PC rewound to - * point at the l.sys instruction that resulted in the - * original syscall. Syscall results other than the four - * below mean that the syscall executed to completion and no - * restart is necessary. - */ - if (regs->orig_gpr11) { - int restart = 0; - - switch (regs->gpr[11]) { + struct ksignal ksig; + unsigned long continue_addr = 0; + unsigned long restart_addr = 0; + unsigned long retval = 0; + int restart = 0; + + if (syscall) { + continue_addr = regs->pc; + restart_addr = continue_addr - 4; + retval = regs->gpr[11]; + + /* + * Setup syscall restart here so that a debugger will + * see the already changed PC. + */ + switch (retval) { case -ERESTART_RESTARTBLOCK: + restart = -2; + /* Fall through */ case -ERESTARTNOHAND: - /* Restart if there is no signal handler */ - restart = (signr <= 0); - break; case -ERESTARTSYS: - /* Restart if there no signal handler or - * SA_RESTART flag is set */ - restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART)); - break; case -ERESTARTNOINTR: - /* Always restart */ - restart = 1; + restart++; + regs->gpr[11] = regs->orig_gpr11; + regs->pc = restart_addr; break; } - - if (restart) { - if (regs->gpr[11] == -ERESTART_RESTARTBLOCK) - regs->gpr[11] = __NR_restart_syscall; - else - regs->gpr[11] = regs->orig_gpr11; - regs->pc -= 4; - } else { - regs->gpr[11] = -EINTR; - } } - if (signr <= 0) { - /* no signal to deliver so we just put the saved sigmask - * back */ + /* + * Get the signal to deliver. During the call to get_signal the + * debugger may change all our registers so we may need to revert + * the decision to restart the syscall; specifically, if the PC is + * changed, don't restart the syscall. + */ + if (get_signal(&ksig)) { + if (unlikely(restart) && regs->pc == restart_addr) { + if (retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK + || (retval == -ERESTARTSYS + && !(ksig.ka.sa.sa_flags & SA_RESTART))) { + /* No automatic restart */ + regs->gpr[11] = -EINTR; + regs->pc = continue_addr; + } + } + handle_signal(&ksig, regs); + } else { + /* no handler */ restore_saved_sigmask(); - } else { /* signr > 0 */ - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + /* + * Restore pt_regs PC as syscall restart will be handled by + * kernel without return to userspace + */ + if (unlikely(restart) && regs->pc == restart_addr) { + regs->pc = continue_addr; + return restart; + } } - return; + return 0; } -asmlinkage void do_notify_resume(struct pt_regs *regs) +asmlinkage int +do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { - if (current_thread_info()->flags & _TIF_SIGPENDING) - do_signal(regs); - - if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } + do { + if (likely(thread_flags & _TIF_NEED_RESCHED)) { + schedule(); + } else { + if (unlikely(!user_mode(regs))) + return 0; + local_irq_enable(); + if (thread_flags & _TIF_SIGPENDING) { + int restart = do_signal(regs, syscall); + if (unlikely(restart)) { + /* + * Restart without handlers. + * Deal with it without leaving + * the kernel space. + */ + return restart; + } + syscall = 0; + } else { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } + } + local_irq_disable(); + thread_flags = current_thread_info()->flags; + } while (thread_flags & _TIF_WORK_MASK); + return 0; } diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 5cce396016d..3d3f6062f49 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -105,17 +105,6 @@ void show_trace_task(struct task_struct *tsk) */ } -/* - * The architecture-independent backtrace generator - */ -void dump_stack(void) -{ - unsigned long stack; - - show_stack(current, &stack); -} -EXPORT_SYMBOL(dump_stack); - void show_registers(struct pt_regs *regs) { int i; diff --git a/arch/openrisc/kernel/vmlinux.h b/arch/openrisc/kernel/vmlinux.h index ee842a2d3f3..bbcdf21b0b3 100644 --- a/arch/openrisc/kernel/vmlinux.h +++ b/arch/openrisc/kernel/vmlinux.h @@ -1,12 +1,8 @@ #ifndef __OPENRISC_VMLINUX_H_ #define __OPENRISC_VMLINUX_H_ -extern char _stext, _etext, _edata, _end; #ifdef CONFIG_BLK_DEV_INITRD extern char __initrd_start, __initrd_end; -extern char __initramfs_start; #endif -extern u32 __dtb_start[]; - #endif |
