From 4af410a868ddddfc6aa9b19379599feac7e79d95 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 31 May 2007 17:43:40 -0700 Subject: [XTENSA] Spelling fixes in arch/xtensa Spelling fixes in arch/xtensa/. Signed-off-by: Simon Arlott Signed-off-by: Chris Zankel --- arch/xtensa/kernel/pci.c | 2 +- arch/xtensa/mm/init.c | 2 +- arch/xtensa/platform-iss/network.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 45571ccb72d6..77deae5290f0 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -401,7 +401,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, * Also, think for a moment about likes of floppy.c that * include architecture specific parts. They may want to redefine ins/outs. * - * We do not use horroble macroses here because we want to + * We do not use horrible macros here because we want to * advance pointer by sizeof(size). */ void outsb(unsigned long addr, const void *src, unsigned long count) { diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index e1ec2d1e8189..8415c76f11c2 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -205,7 +205,7 @@ void __init init_mmu (void) /* Writing zeros to the TLBCFG special registers ensure * that valid values exist in the register. For existing * PGSZID fields, zero selects the first element of the - * page-size array. For nonexistant PGSZID fields, zero is + * page-size array. For nonexistent PGSZID fields, zero is * the best value to write. Also, when changing PGSZID * fields, the corresponding TLB must be flushed. */ diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c index 4bfe333be229..f09962fa98c0 100644 --- a/arch/xtensa/platform-iss/network.c +++ b/arch/xtensa/platform-iss/network.c @@ -473,7 +473,7 @@ static int iss_net_open(struct net_device *dev) netif_start_queue(dev); /* clear buffer - it can happen that the host side of the interface - * is full when we gethere. In this case, new data is never queued, + * is full when we get here. In this case, new data is never queued, * SIGIOs never arrive, and the net never works. */ while ((err = iss_net_rx(dev)) > 0) -- cgit v1.2.2 From a0bb46ba074d2442e96f55c997293767340f4ce9 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 31 May 2007 17:44:31 -0700 Subject: [XTENSA] fix sources using deprecated assembler directive The assembler directive '.begin literal' is deprecated in the newer versions of the binutils (strncopy_user.S and strnlen_user.S). Signed-off-by: Chris Zankel --- arch/xtensa/lib/strncpy_user.S | 33 +++++++++++++++++---------------- arch/xtensa/lib/strnlen_user.S | 33 +++++++++++++++++---------------- 2 files changed, 34 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S index a834057bda6b..b2655d94558d 100644 --- a/arch/xtensa/lib/strncpy_user.S +++ b/arch/xtensa/lib/strncpy_user.S @@ -25,18 +25,18 @@ /* * char *__strncpy_user(char *dst, const char *src, size_t len) */ -.text -.begin literal -.align 4 -.Lmask0: - .byte 0xff, 0x00, 0x00, 0x00 -.Lmask1: - .byte 0x00, 0xff, 0x00, 0x00 -.Lmask2: - .byte 0x00, 0x00, 0xff, 0x00 -.Lmask3: - .byte 0x00, 0x00, 0x00, 0xff -.end literal + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif # Register use # a0/ return address @@ -53,6 +53,7 @@ # a11/ dst # a12/ tmp +.text .align 4 .global __strncpy_user .type __strncpy_user,@function @@ -61,10 +62,10 @@ __strncpy_user: # a2/ dst, a3/ src, a4/ len mov a11, a2 # leave dst in return value register beqz a4, .Lret # if len is zero - l32r a5, .Lmask0 # mask for byte 0 - l32r a6, .Lmask1 # mask for byte 1 - l32r a7, .Lmask2 # mask for byte 2 - l32r a8, .Lmask3 # mask for byte 3 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned .Lsrcaligned: # return here when src is word-aligned diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S index 5e9c1e709b2e..ad3f616322ca 100644 --- a/arch/xtensa/lib/strnlen_user.S +++ b/arch/xtensa/lib/strnlen_user.S @@ -24,18 +24,18 @@ /* * size_t __strnlen_user(const char *s, size_t len) */ -.text -.begin literal -.align 4 -.Lmask0: - .byte 0xff, 0x00, 0x00, 0x00 -.Lmask1: - .byte 0x00, 0xff, 0x00, 0x00 -.Lmask2: - .byte 0x00, 0x00, 0xff, 0x00 -.Lmask3: - .byte 0x00, 0x00, 0x00, 0xff -.end literal + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif # Register use: # a2/ src @@ -48,6 +48,7 @@ # a9/ tmp # a10/ tmp +.text .align 4 .global __strnlen_user .type __strnlen_user,@function @@ -56,10 +57,10 @@ __strnlen_user: # a2/ s, a3/ len addi a4, a2, -4 # because we overincrement at the end; # we compensate with load offsets of 4 - l32r a5, .Lmask0 # mask for byte 0 - l32r a6, .Lmask1 # mask for byte 1 - l32r a7, .Lmask2 # mask for byte 2 - l32r a8, .Lmask3 # mask for byte 3 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 bbsi.l a2, 0, .L1mod2 # if only 8-bit aligned bbsi.l a2, 1, .L2mod4 # if only 16-bit aligned -- cgit v1.2.2 From 54213baf643dd14d3bc06ca7575a817d79a350c2 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 31 May 2007 17:45:23 -0700 Subject: [XTENSA] Remove multi-exported symbols from xtensa_ksyms.c This patch removes the following symbols from arch/xtensa/kernel/xtensa_ksyms.c that were already exported: memcmp, memchr, strcat, strchr, strlen, stncat, strnlen, strrchr, strstr, enable_irq, and disable_irq Signed-off-by: Chris Zankel --- arch/xtensa/kernel/xtensa_ksyms.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'arch') diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index cd7e6a020602..60dbdb43fb4c 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -38,21 +38,10 @@ /* * String functions */ -EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); /* -- cgit v1.2.2 From de4f6e5b41bef50fc981410ae8380f27f4e93bf8 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 31 May 2007 17:47:01 -0700 Subject: [XTENSA] clean-up header files The header files in the asm-xtensa directory are not clean and 'make headers_check' fails. This is a first patch to fix most of the header files. It removes unnecessary include statements and adds some that are required for building the kernel. The linker script required some updates or the linking stage would fail. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/setup.c | 1 + arch/xtensa/kernel/vmlinux.lds.S | 78 ++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 47 deletions(-) (limited to 'arch') diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 1ecf6716c327..2e8d398cf196 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -41,6 +41,7 @@ #include #include #include +#include #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16}; diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index 4b7b4ff79973..b0582c3c5f8d 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -84,9 +84,7 @@ SECTIONS { /* The .head.text section must be the first section! */ *(.head.text) - *(.literal) - TEXT_TEXT - *(.srom.text) + *(.literal .text) VMLINUX_SYMBOL(__sched_text_start) = .; *(.sched.literal .sched.text) VMLINUX_SYMBOL(__sched_text_end) = .; @@ -96,6 +94,7 @@ SECTIONS } _etext = .; + PROVIDE (etext = .); . = ALIGN(16); @@ -103,32 +102,6 @@ SECTIONS /* Relocation table */ - . = ALIGN(16); - __boot_reloc_table_start = ABSOLUTE(.); - - __relocate : { - - RELOCATE_ENTRY(_WindowVectors_text, - .WindowVectors.text); -#if 0 - RELOCATE_ENTRY(_KernelExceptionVector_literal, - .KernelExceptionVector.literal); -#endif - RELOCATE_ENTRY(_KernelExceptionVector_text, - .KernelExceptionVector.text); -#if 0 - RELOCATE_ENTRY(_UserExceptionVector_literal, - .UserExceptionVector.literal); -#endif - RELOCATE_ENTRY(_UserExceptionVector_text, - .UserExceptionVector.text); - RELOCATE_ENTRY(_DoubleExceptionVector_literal, - .DoubleExceptionVector.literal); - RELOCATE_ENTRY(_DoubleExceptionVector_text, - .DoubleExceptionVector.text); - } - __boot_reloc_table_end = ABSOLUTE(.) ; - .fixup : { *(.fixup) } . = ALIGN(16); @@ -145,8 +118,7 @@ SECTIONS _fdata = .; .data : { - DATA_DATA - CONSTRUCTORS + *(.data) CONSTRUCTORS . = ALIGN(XCHAL_ICACHE_LINESIZE); *(.data.cacheline_aligned) } @@ -174,6 +146,22 @@ SECTIONS __tagtable_begin = .; *(.taglist) __tagtable_end = .; + + . = ALIGN(16); + __boot_reloc_table_start = ABSOLUTE(.); + + RELOCATE_ENTRY(_WindowVectors_text, + .WindowVectors.text); + RELOCATE_ENTRY(_KernelExceptionVector_text, + .KernelExceptionVector.text); + RELOCATE_ENTRY(_UserExceptionVector_text, + .UserExceptionVector.text); + RELOCATE_ENTRY(_DoubleExceptionVector_literal, + .DoubleExceptionVector.literal); + RELOCATE_ENTRY(_DoubleExceptionVector_text, + .DoubleExceptionVector.text); + + __boot_reloc_table_end = ABSOLUTE(.) ; } . = ALIGN(XCHAL_ICACHE_LINESIZE); @@ -194,16 +182,6 @@ SECTIONS SECURITY_INIT - . = ALIGN(4); - - __start___ftr_fixup = .; - __ftr_fixup : { *(__ftr_fixup) } - __stop___ftr_fixup = .; - - . = ALIGN(4096); - __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } - __per_cpu_end = .; #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); @@ -212,6 +190,12 @@ SECTIONS __initramfs_end = .; #endif + . = ALIGN(4096); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + + /* We need this dummy segment here */ . = ALIGN(4); @@ -273,9 +257,9 @@ SECTIONS /* BSS section */ _bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : { *(COMMON) *(.bss) } + .bss : { *(.bss.page_aligned) *(.bss) } _bss_end = .; + _end = .; /* only used by the boot loader */ @@ -293,16 +277,16 @@ SECTIONS *(.ResetVector.text) } - /* Sections to be discarded */ /DISCARD/ : { - *(.text.exit) - *(.text.exit.literal) - *(.data.exit) + *(.exit.literal .exit.text) + *(.exit.data) *(.exitcall.exit) } + .xt.lit : { *(.xt.lit) } + .xt.prop : { *(.xt.prop) } .debug 0 : { *(.debug) } .line 0 : { *(.line) } -- cgit v1.2.2 From adba09f01577ea441a761a85aacb1e43b58d35c4 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 31 May 2007 17:48:07 -0700 Subject: [XTENSA] Move common sections into bss sections Move the fields of the COMMON sections 'swapper_pg_dir' and 'empty_zero_page' to the BSS section. Remove the unused COMMON sections 'emtpy_bad_page_table' and 'empty_bad_page'. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/head.S | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index ea89910efa44..67e69139520b 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -19,6 +19,8 @@ #include #include +#include + /* * This module contains the entry code for kernel images. It performs the * minimal setup needed to call the generic C routines. @@ -227,13 +229,14 @@ _startup: should_never_return: j should_never_return - /* Define some common data structures here. We define them - * here in this assembly file due to their unusual alignment - * requirements. - */ - .comm swapper_pg_dir,PAGE_SIZE,PAGE_SIZE - .comm empty_bad_page_table,PAGE_SIZE,PAGE_SIZE - .comm empty_bad_page,PAGE_SIZE,PAGE_SIZE - .comm empty_zero_page,PAGE_SIZE,PAGE_SIZE +/* + * BSS section + */ + +.section ".bss.page_aligned", "w" +ENTRY(swapper_pg_dir) + .fill PAGE_SIZE, 1, 0 +ENTRY(empty_zero_page) + .fill PAGE_SIZE, 1, 0 -- cgit v1.2.2 From 29c4dfd92edc26c2cd2c0c64c9201d5b91d6418e Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Thu, 31 May 2007 17:49:32 -0700 Subject: [XTENSA] Remove non-rt signal handling The non-rt signal handling was never really used, so we don't break anything. This patch also cleans up the signal stack-frame to make it independent from the processor configuration. It also improves the method used for controlling single-stepping. We now save and restore the 'icountlevel' register that controls single stepping and set or clear the saved state to enable or disable it. Signed-off-by: Chris Zankel --- arch/xtensa/kernel/asm-offsets.c | 1 + arch/xtensa/kernel/entry.S | 36 +- arch/xtensa/kernel/signal.c | 795 ++++++++++++++++----------------------- 3 files changed, 334 insertions(+), 498 deletions(-) (limited to 'arch') diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 698079b3a336..d0323cd6a2ea 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -39,6 +39,7 @@ int main(void) DEFINE(PT_LEND, offsetof (struct pt_regs, lend)); DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount)); DEFINE(PT_SAR, offsetof (struct pt_regs, sar)); + DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel)); DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall)); DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0])); DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0])); diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 9e271ba009bf..8dc7a2c26ff9 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -125,8 +125,9 @@ _user_exception: movi a2, 0 rsr a3, SAR - wsr a2, ICOUNTLEVEL + xsr a2, ICOUNTLEVEL s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL /* Rotate ws so that the current windowbase is at bit0. */ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ @@ -276,8 +277,9 @@ _kernel_exception: movi a2, 0 rsr a3, SAR - wsr a2, ICOUNTLEVEL + xsr a2, ICOUNTLEVEL s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL /* Rotate ws so that the current windowbase is at bit0. */ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ @@ -330,14 +332,16 @@ _kernel_exception: common_exception: - /* Save EXCVADDR, DEBUGCAUSE, and PC, and clear LCOUNT */ + /* Save some registers, disable loops and clear the syscall flag. */ rsr a2, DEBUGCAUSE rsr a3, EPC_1 s32i a2, a1, PT_DEBUGCAUSE s32i a3, a1, PT_PC + movi a2, -1 rsr a3, EXCVADDR + s32i a2, a1, PT_SYSCALL movi a2, 0 s32i a3, a1, PT_EXCVADDR xsr a2, LCOUNT @@ -450,27 +454,8 @@ common_exception_return: /* Restore the state of the task and return from the exception. */ - - /* If we are returning from a user exception, and the process - * to run next has PT_SINGLESTEP set, we want to setup - * ICOUNT and ICOUNTLEVEL to step one instruction. - * PT_SINGLESTEP is set by sys_ptrace (ptrace.c) - */ - 4: /* a2 holds GET_CURRENT(a2,a1) */ - l32i a3, a2, TI_TASK - l32i a3, a3, TASK_PTRACE - bbci.l a3, PT_SINGLESTEP_BIT, 1f # jump if single-step flag is not set - - movi a3, -2 # PT_SINGLESTEP flag is set, - movi a4, 1 # icountlevel of 1 means it won't - wsr a3, ICOUNT # start counting until after rfe - wsr a4, ICOUNTLEVEL # so setup icount & icountlevel. - isync - -1: - #if XCHAL_EXTRA_SA_SIZE /* For user exceptions, restore the extra state from the user's TCB. */ @@ -665,6 +650,13 @@ common_exception_exit: wsr a3, LEND wsr a2, LCOUNT + /* We control single stepping through the ICOUNTLEVEL register. */ + + l32i a2, a1, PT_ICOUNTLEVEL + movi a3, -2 + wsr a2, ICOUNTLEVEL + wsr a3, ICOUNT + /* Check if it was double exception. */ l32i a0, a1, PT_DEPC diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 58107672a619..033aae0336d2 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -1,397 +1,239 @@ -// TODO coprocessor stuff /* - * linux/arch/xtensa/kernel/signal.c + * arch/xtensa/kernel/signal.c * - * Copyright (C) 1991, 1992 Linus Torvalds - * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * - * Joe Taylor - * Chris Zankel + * Default platform functions. * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * + * Copyright (C) 2005, 2006 Tensilica Inc. + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * + * Chris Zankel + * Joe Taylor */ -#include -#include -#include -#include -#include -#include #include #include -#include #include -#include -#include #include +#include + #include #include -#include #include +#include +#include #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, - struct rusage * ru); asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); extern struct task_struct *coproc_owners[]; +extern void release_all_cp (struct task_struct *); -/* - * Atomically swap in the new signal mask, and wait for a signal. +struct rt_sigframe +{ + struct siginfo info; + struct ucontext uc; + cp_state_t cpstate; + unsigned char retcode[6]; + unsigned int window[4]; +}; + +/* + * Flush register windows stored in pt_regs to stack. + * Returns 1 for errors. + * + * Note that windowbase, windowstart, and wmask are not updated! */ -int xtensa_sigsuspend(struct pt_regs *regs) +int +flush_window_regs_user(struct pt_regs *regs) { - old_sigset_t mask = (old_sigset_t) regs->areg[3]; - sigset_t saveset; + const unsigned long ws = regs->windowstart; + const unsigned long wb = regs->windowbase; + unsigned long sp = 0; + unsigned long wm; + int err = 1; + int base; - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + /* Return if no other frames. */ - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} + if (regs->wmask == 1) + return 0; -asmlinkage int -xtensa_rt_sigsuspend(struct pt_regs *regs) -{ - sigset_t *unewset = (sigset_t *) regs->areg[4]; - size_t sigsetsize = (size_t) regs->areg[3]; - sigset_t saveset, newset; - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; + /* Rotate windowmask and skip empty frames. */ - 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); + wm = (ws >> wb) | (ws << (XCHAL_NUM_AREGS / 4 - wb)); + base = (XCHAL_NUM_AREGS / 4) - (regs->wmask >> 4); + + /* For call8 or call12 frames, we need the previous stack pointer. */ - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} + if ((regs->wmask & 2) == 0) + if (__get_user(sp, (int*)(regs->areg[base * 4 + 1] - 12))) + goto errout; -asmlinkage int -xtensa_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; + /* Spill frames to stack. */ - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } + while (base < XCHAL_NUM_AREGS / 4) { - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + int m = (wm >> base); + int inc = 0; - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + /* Save registers a4..a7 (call8) or a4...a11 (call12) */ - return ret; -} + if (m & 2) { /* call4 */ + inc = 1; -asmlinkage int -xtensa_sigaltstack(struct pt_regs *regs) -{ - const stack_t *uss = (stack_t *) regs->areg[4]; - stack_t *uoss = (stack_t *) regs->areg[3]; + } else if (m & 4) { /* call8 */ + if (copy_to_user((void*)(sp - 32), + ®s->areg[(base + 1) * 4], 16)) + goto errout; + inc = 2; - if (regs->depc > 64) - panic ("Double exception sys_sigreturn\n"); + } else if (m & 8) { /* call12 */ + if (copy_to_user((void*)(sp - 48), + ®s->areg[(base + 1) * 4], 32)) + goto errout; + inc = 3; + } + /* Save current frame a0..a3 under next SP */ - return do_sigaltstack(uss, uoss, regs->areg[1]); -} + sp = regs->areg[((base + inc) * 4 + 1) % XCHAL_NUM_AREGS]; + if (copy_to_user((void*)(sp - 16), ®s->areg[base * 4], 16)) + goto errout; + + /* Get current stack pointer for next loop iteration. */ + + sp = regs->areg[base * 4 + 1]; + base += inc; + } + + return 0; +errout: + return err; +} /* - * Do a signal return; undo the signal stack. + * Note: We don't copy double exception 'regs', we have to finish double exc. + * first before we return to signal handler! This dbl.exc.handler might cause + * another double exception, but I think we are fine as the situation is the + * same as if we had returned to the signal handerl and got an interrupt + * immediately... */ -struct sigframe -{ - struct sigcontext sc; - struct _cpstate cpstate; - unsigned long extramask[_NSIG_WORDS-1]; - unsigned char retcode[6]; - unsigned int reserved[4]; /* Reserved area for chaining */ - unsigned int window[4]; /* Window of 4 registers for initial context */ -}; - -struct rt_sigframe +static int +setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, + struct pt_regs *regs, unsigned long mask) { - struct siginfo info; - struct ucontext uc; - struct _cpstate cpstate; - unsigned char retcode[6]; - unsigned int reserved[4]; /* Reserved area for chaining */ - unsigned int window[4]; /* Window of 4 registers for initial context */ -}; + int err = 0; -extern void release_all_cp (struct task_struct *); +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(pc); + COPY(ps); + COPY(lbeg); + COPY(lend); + COPY(lcount); + COPY(sar); +#undef COPY + err |= flush_window_regs_user(regs); + err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); -// FIXME restore_cpextra -static inline int -restore_cpextra (struct _cpstate *buf) -{ -#if 0 - /* The signal handler may have used coprocessors in which - * case they are still enabled. We disable them to force a - * reloading of the original task's CP state by the lazy - * context-switching mechanisms of CP exception handling. - * Also, we essentially discard any coprocessor state that the - * signal handler created. */ + // err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4) - struct task_struct *tsk = current; - release_all_cp(tsk); - return __copy_from_user(tsk->thread.cpextra, buf, XTENSA_CP_EXTRA_SIZE); +#if XCHAL_HAVE_CP +# error Coprocessors unsupported + err |= save_cpextra(cpstate); + err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); #endif - return 0; -} - -/* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately... - */ + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + return err; +} static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { - struct thread_struct *thread; unsigned int err = 0; unsigned long ps; - struct _cpstate *buf; #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) COPY(pc); - COPY(depc); - COPY(wmask); COPY(lbeg); COPY(lend); COPY(lcount); COPY(sar); - COPY(windowbase); - COPY(windowstart); #undef COPY + /* All registers were flushed to stack. Start with a prestine frame. */ + + regs->wmask = 1; + regs->windowbase = 0; + regs->windowstart = 1; + /* For PS, restore only PS.CALLINC. * Assume that all other bits are either the same as for the signal * handler, or the user mode value doesn't matter (e.g. PS.OWB). */ err |= __get_user(ps, &sc->sc_ps); - regs->ps = (regs->ps & ~PS_CALLINC_MASK) - | (ps & PS_CALLINC_MASK); + regs->ps = (regs->ps & ~PS_CALLINC_MASK) | (ps & PS_CALLINC_MASK); /* Additional corruption checks */ - if ((regs->windowbase >= (XCHAL_NUM_AREGS/4)) - || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) ) - err = 1; if ((regs->lcount > 0) - && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) + && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) err = 1; - /* Restore extended register state. - * See struct thread_struct in processor.h. - */ - thread = ¤t->thread; - - err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4); - err |= __get_user(buf, &sc->sc_cpstate); - if (buf) { - if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_cpextra(buf); - } - - regs->syscall = -1; /* disable syscall checks */ - return err; - -badframe: - return 1; -} - -static inline void -flush_my_cpstate(struct task_struct *tsk) -{ - unsigned long flags; - local_irq_save(flags); - -#if 0 // FIXME - for (i = 0; i < XCHAL_CP_NUM; i++) { - if (tsk == coproc_owners[i]) { - xthal_validate_cp(i); - xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i); + err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); - /* Invalidate and "disown" the cp to allow - * callers the chance to reset cp state in the - * task_struct. */ +#if XCHAL_HAVE_CP +# error Coprocessors unsupported + /* The signal handler may have used coprocessors in which + * case they are still enabled. We disable them to force a + * reloading of the original task's CP state by the lazy + * context-switching mechanisms of CP exception handling. + * Also, we essentially discard any coprocessor state that the + * signal handler created. */ - xthal_invalidate_cp(i); - coproc_owners[i] = 0; - } + if (!err) { + struct task_struct *tsk = current; + release_all_cp(tsk); + err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, + XTENSA_CP_EXTRA_SIZE); } #endif - local_irq_restore(flags); -} - -/* Return codes: - 0: nothing saved - 1: stuff to save, successful - -1: stuff to save, error happened -*/ -static int -save_cpextra (struct _cpstate *buf) -{ -#if XCHAL_CP_NUM == 0 - return 0; -#else - - /* FIXME: If a task has never used a coprocessor, there is - * no need to save and restore anything. Tracking this - * information would allow us to optimize this section. - * Perhaps we can use current->used_math or (current->flags & - * PF_USEDFPU) or define a new field in the thread - * structure. */ - - /* We flush any live, task-owned cp state to the task_struct, - * then copy it all to the sigframe. Then we clear all - * cp/extra state in the task_struct, effectively - * clearing/resetting all cp/extra state for the signal - * handler (cp-exception handling will load these new values - * into the cp/extra registers.) This step is important for - * things like a floating-point cp, where the OS must reset - * the FCR to the default rounding mode. */ - - int err = 0; - struct task_struct *tsk = current; - - flush_my_cpstate(tsk); - /* Note that we just copy everything: 'extra' and 'cp' state together.*/ - err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); - memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE); - -#if (XTENSA_CP_EXTRA_SIZE == 0) -#error Sanity check on memset above, cpextra_size should not be zero. -#endif - - return err ? -1 : 1; -#endif -} - -static int -setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate, - struct pt_regs *regs, unsigned long mask) -{ - struct thread_struct *thread; - int err = 0; - -//printk("setup_sigcontext\n"); -#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) - COPY(pc); - COPY(ps); - COPY(depc); - COPY(wmask); - COPY(lbeg); - COPY(lend); - COPY(lcount); - COPY(sar); - COPY(windowbase); - COPY(windowstart); -#undef COPY - - /* Save extended register state. - * See struct thread_struct in processor.h. - */ - thread = ¤t->thread; - err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4); - err |= save_cpextra(cpstate); - err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); - /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); + regs->syscall = -1; /* disable syscall checks */ return err; } -asmlinkage int xtensa_sigreturn(struct pt_regs *regs) -{ - struct sigframe *frame = (struct sigframe *)regs->areg[1]; - sigset_t set; - if (regs->depc > 64) - panic ("Double exception sys_sigreturn\n"); - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->sc)) - goto badframe; - return regs->areg[2]; -badframe: - force_sig(SIGSEGV, current); - return 0; -} +/* + * Do a signal return; undo the signal stack. + */ -asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) +asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, + long a4, long a5, struct pt_regs *regs) { - struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1]; + struct rt_sigframe __user *frame; sigset_t set; - stack_t st; int ret; + if (regs->depc > 64) - { - printk("!!!!!!! DEPC !!!!!!!\n"); - return 0; - } + panic("rt_sigreturn in double exception!\n"); + + frame = (struct rt_sigframe __user *) regs->areg[1]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -407,13 +249,11 @@ asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + ret = regs->areg[2]; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->areg[1]) == -EFAULT) goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->areg[1]); return ret; @@ -422,77 +262,50 @@ badframe: return 0; } -/* - * Set up a signal frame. - */ + /* - * Determine which stack to use.. + * Set up a signal frame. */ -static inline void * -get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) -{ - if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void *)((sp - frame_size) & -16ul); -} - -#define USE_SIGRETURN 0 -#define USE_RT_SIGRETURN 1 static int -gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) +gen_return_code(unsigned char *codemem) { - unsigned int retcall; int err = 0; -#if 0 - /* Ignoring SA_RESTORER for now; it's supposed to be obsolete, - * and the xtensa glibc doesn't use it. + /* + * The 12-bit immediate is really split up within the 24-bit MOVI + * instruction. As long as the above system call numbers fit within + * 8-bits, the following code works fine. See the Xtensa ISA for + * details. */ - if (ka->sa.sa_flags & SA_RESTORER) { - regs->pr = (unsigned long) ka->sa.sa_restorer; - } else -#endif /* 0 */ - { - -#if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255) - -/* The 12-bit immediate is really split up within the 24-bit MOVI - * instruction. As long as the above system call numbers fit within - * 8-bits, the following code works fine. See the Xtensa ISA for - * details. - */ -#error Generating the MOVI instruction below breaks! +#if __NR_rt_sigreturn > 255 +# error Generating the MOVI instruction below breaks! #endif - retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn; - #ifdef __XTENSA_EB__ /* Big Endian version */ - /* Generate instruction: MOVI a2, retcall */ - err |= __put_user(0x22, &codemem[0]); - err |= __put_user(0x0a, &codemem[1]); - err |= __put_user(retcall, &codemem[2]); - /* Generate instruction: SYSCALL */ - err |= __put_user(0x00, &codemem[3]); - err |= __put_user(0x05, &codemem[4]); - err |= __put_user(0x00, &codemem[5]); + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0x0a, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x05, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); #elif defined __XTENSA_EL__ /* Little Endian version */ - /* Generate instruction: MOVI a2, retcall */ - err |= __put_user(0x22, &codemem[0]); - err |= __put_user(0xa0, &codemem[1]); - err |= __put_user(retcall, &codemem[2]); - /* Generate instruction: SYSCALL */ - err |= __put_user(0x00, &codemem[3]); - err |= __put_user(0x50, &codemem[4]); - err |= __put_user(0x00, &codemem[5]); + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0xa0, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x50, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); #else -#error Must use compiler for Xtensa processors. +# error Must use compiler for Xtensa processors. #endif - } /* Flush generated code out of the data cache */ @@ -504,97 +317,29 @@ gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) return err; } -static void -set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr, - void *handler, unsigned long arg1, void *arg2, void *arg3) -{ - /* Set up registers for signal handler */ - start_thread(regs, (unsigned long) handler, (unsigned long) stack); - - /* Set up a stack frame for a call4 - * Note: PS.CALLINC is set to one by start_thread - */ - regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000; - regs->areg[6] = arg1; - regs->areg[7] = (unsigned long) arg2; - regs->areg[8] = (unsigned long) arg3; -} -static void setup_frame(int sig, struct k_sigaction *ka, +static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { - struct sigframe *frame; + struct rt_sigframe *frame; int err = 0; int signal; + unsigned long sp, ra; - frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); - if (regs->depc > 64) - { - printk("!!!!!!! DEPC !!!!!!!\n"); - return; - } - - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - signal = current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig; - - err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]); + sp = regs->areg[1]; - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) { + sp = current->sas_ss_sp + current->sas_ss_size; } - /* Create sys_sigreturn syscall in stack frame */ - err |= gen_return_code(frame->retcode, USE_SIGRETURN); - - if (err) - goto give_sigsegv; - - /* Create signal handler execution context. - * Return context not modified until this point. - */ - set_thread_state(regs, frame, frame->retcode, - ka->sa.sa_handler, signal, &frame->sc, NULL); - - /* Set access mode to USER_DS. Nomenclature is outdated, but - * functionality is used in uaccess.h - */ - set_fs(USER_DS); - - -#if DEBUG_SIG - printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n", - current->comm, current->pid, signal, frame, regs->pc); -#endif - - return; - -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); -} - -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - struct rt_sigframe *frame; - int err = 0; - int signal; + frame = (void *)((sp - sizeof(*frame)) & -16ul); - frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); if (regs->depc > 64) panic ("Double exception sys_sigreturn\n"); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) { goto give_sigsegv; + } signal = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap @@ -602,9 +347,12 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; - err |= copy_siginfo_to_user(&frame->info, info); + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + } + + /* Create the user context. */ - /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, @@ -617,16 +365,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Create sys_rt_sigreturn syscall in stack frame */ - err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN); - if (err) + err |= gen_return_code(frame->retcode); + + if (err) { goto give_sigsegv; + } + - /* Create signal handler execution context. + /* + * Create signal handler execution context. * Return context not modified until this point. */ - set_thread_state(regs, frame, frame->retcode, - ka->sa.sa_handler, signal, &frame->info, &frame->uc); + + /* Set up registers for signal handler */ + start_thread(regs, (unsigned long) ka->sa.sa_handler, + (unsigned long) frame); + + /* Set up a stack frame for a call4 + * Note: PS.CALLINC is set to one by start_thread + */ + ra = (unsigned long) frame->retcode; + regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + regs->areg[6] = (unsigned long) signal; + regs->areg[7] = (unsigned long) &frame->info; + regs->areg[8] = (unsigned long) &frame->uc; /* Set access mode to USER_DS. Nomenclature is outdated, but * functionality is used in uaccess.h @@ -646,6 +409,48 @@ give_sigsegv: force_sig(SIGSEGV, current); } +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ + +asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, + size_t sigsetsize, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + 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); + + regs->areg[2] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(regs, &saveset)) + return -EINTR; + } +} + +asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, + stack_t __user *uoss, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->areg[1]); +} + /* @@ -663,51 +468,89 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) int signr; struct k_sigaction ka; + if (!user_mode(regs)) + return 0; + + if (try_to_freeze()) + goto no_signal; + if (!oldset) oldset = ¤t->blocked; + task_pt_regs(current)->icountlevel = 0; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); - /* Are we from a system call? */ - if (regs->syscall >= 0) { - /* If so, check system call restarting.. */ - switch (regs->areg[2]) { - case ERESTARTNOHAND: - case ERESTART_RESTARTBLOCK: - regs->areg[2] = -EINTR; - break; + if (signr > 0) { + + /* Are we from a system call? */ + + if ((signed)regs->syscall >= 0) { - case ERESTARTSYS: - if (!(ka.sa.sa_flags & SA_RESTART)) { + /* If so, check system call restarting.. */ + + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: regs->areg[2] = -EINTR; break; - } - /* fallthrough */ - case ERESTARTNOINTR: - regs->areg[2] = regs->syscall; - regs->pc -= 3; + + case -ERESTARTSYS: + if (!(ka.sa.sa_flags & SA_RESTART)) { + regs->areg[2] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + + default: + /* nothing to do */ + if (regs->areg[2] != 0) + break; + } } - } - if (signr == 0) - return 0; /* no signals delivered */ + /* Whee! Actually deliver the signal. */ + /* Set up the stack frame */ + setup_frame(signr, &ka, &info, oldset, regs); - /* Whee! Actually deliver the signal. */ + if (ka.sa.sa_flags & SA_ONESHOT) + ka.sa.sa_handler = SIG_DFL; - /* Set up the stack frame */ - if (ka.sa.sa_flags & SA_SIGINFO) - setup_rt_frame(signr, &ka, &info, oldset, regs); - else - setup_frame(signr, &ka, oldset, regs); + 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); + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; - if (ka.sa.sa_flags & SA_ONESHOT) - ka.sa.sa_handler = SIG_DFL; + return 1; + } - 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 1; +no_signal: + /* Did we come from a system call? */ + if ((signed) regs->syscall >= 0) { + /* Restart the system call - no handlers present */ + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + case -ERESTART_RESTARTBLOCK: + regs->areg[2] = __NR_restart_syscall; + regs->pc -= 3; + break; + } + } + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; + return 0; } + -- cgit v1.2.2