diff options
Diffstat (limited to 'arch/frv')
-rw-r--r-- | arch/frv/Kconfig | 1 | ||||
-rw-r--r-- | arch/frv/include/asm/bitops.h | 29 | ||||
-rw-r--r-- | arch/frv/include/asm/elf.h | 1 | ||||
-rw-r--r-- | arch/frv/include/asm/pci.h | 7 | ||||
-rw-r--r-- | arch/frv/include/asm/ptrace.h | 11 | ||||
-rw-r--r-- | arch/frv/include/asm/syscall.h | 123 | ||||
-rw-r--r-- | arch/frv/include/asm/thread_info.h | 10 | ||||
-rw-r--r-- | arch/frv/kernel/entry.S | 13 | ||||
-rw-r--r-- | arch/frv/kernel/ptrace.c | 755 | ||||
-rw-r--r-- | arch/frv/kernel/signal.c | 10 | ||||
-rw-r--r-- | arch/frv/kernel/uaccess.c | 6 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-dma-nommu.c | 6 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-dma.c | 6 |
13 files changed, 399 insertions, 579 deletions
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index 9d1552a9ee2..8a5bd7a9c6f 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -6,6 +6,7 @@ config FRV bool default y select HAVE_IDE + select HAVE_ARCH_TRACEHOOK config ZONE_DMA bool diff --git a/arch/frv/include/asm/bitops.h b/arch/frv/include/asm/bitops.h index 287f6f697ce..50ae91b2967 100644 --- a/arch/frv/include/asm/bitops.h +++ b/arch/frv/include/asm/bitops.h @@ -112,7 +112,7 @@ extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsig #define atomic_clear_mask(mask, v) atomic_test_and_ANDNOT_mask((mask), (v)) #define atomic_set_mask(mask, v) atomic_test_and_OR_mask((mask), (v)) -static inline int test_and_clear_bit(int nr, volatile void *addr) +static inline int test_and_clear_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *ptr = addr; unsigned long mask = 1UL << (nr & 31); @@ -120,7 +120,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr) return (atomic_test_and_ANDNOT_mask(mask, ptr) & mask) != 0; } -static inline int test_and_set_bit(int nr, volatile void *addr) +static inline int test_and_set_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *ptr = addr; unsigned long mask = 1UL << (nr & 31); @@ -128,7 +128,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr) return (atomic_test_and_OR_mask(mask, ptr) & mask) != 0; } -static inline int test_and_change_bit(int nr, volatile void *addr) +static inline int test_and_change_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *ptr = addr; unsigned long mask = 1UL << (nr & 31); @@ -136,22 +136,22 @@ static inline int test_and_change_bit(int nr, volatile void *addr) return (atomic_test_and_XOR_mask(mask, ptr) & mask) != 0; } -static inline void clear_bit(int nr, volatile void *addr) +static inline void clear_bit(unsigned long nr, volatile void *addr) { test_and_clear_bit(nr, addr); } -static inline void set_bit(int nr, volatile void *addr) +static inline void set_bit(unsigned long nr, volatile void *addr) { test_and_set_bit(nr, addr); } -static inline void change_bit(int nr, volatile void * addr) +static inline void change_bit(unsigned long nr, volatile void *addr) { test_and_change_bit(nr, addr); } -static inline void __clear_bit(int nr, volatile void * addr) +static inline void __clear_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *a = addr; int mask; @@ -161,7 +161,7 @@ static inline void __clear_bit(int nr, volatile void * addr) *a &= ~mask; } -static inline void __set_bit(int nr, volatile void * addr) +static inline void __set_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *a = addr; int mask; @@ -171,7 +171,7 @@ static inline void __set_bit(int nr, volatile void * addr) *a |= mask; } -static inline void __change_bit(int nr, volatile void *addr) +static inline void __change_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *a = addr; int mask; @@ -181,7 +181,7 @@ static inline void __change_bit(int nr, volatile void *addr) *a ^= mask; } -static inline int __test_and_clear_bit(int nr, volatile void * addr) +static inline int __test_and_clear_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *a = addr; int mask, retval; @@ -193,7 +193,7 @@ static inline int __test_and_clear_bit(int nr, volatile void * addr) return retval; } -static inline int __test_and_set_bit(int nr, volatile void * addr) +static inline int __test_and_set_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *a = addr; int mask, retval; @@ -205,7 +205,7 @@ static inline int __test_and_set_bit(int nr, volatile void * addr) return retval; } -static inline int __test_and_change_bit(int nr, volatile void * addr) +static inline int __test_and_change_bit(unsigned long nr, volatile void *addr) { volatile unsigned long *a = addr; int mask, retval; @@ -220,12 +220,13 @@ static inline int __test_and_change_bit(int nr, volatile void * addr) /* * This routine doesn't need to be atomic. */ -static inline int __constant_test_bit(int nr, const volatile void * addr) +static inline int +__constant_test_bit(unsigned long nr, const volatile void *addr) { return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; } -static inline int __test_bit(int nr, const volatile void * addr) +static inline int __test_bit(unsigned long nr, const volatile void *addr) { int * a = (int *) addr; int mask; diff --git a/arch/frv/include/asm/elf.h b/arch/frv/include/asm/elf.h index 7279ec07d62..7bbf6e47f8c 100644 --- a/arch/frv/include/asm/elf.h +++ b/arch/frv/include/asm/elf.h @@ -116,6 +116,7 @@ do { \ } while(0) #define USE_ELF_CORE_DUMP +#define CORE_DUMP_USE_REGSET #define ELF_FDPIC_CORE_EFLAGS EF_FRV_FDPIC #define ELF_EXEC_PAGESIZE 16384 diff --git a/arch/frv/include/asm/pci.h b/arch/frv/include/asm/pci.h index 585d9b49949..cc685e60b0f 100644 --- a/arch/frv/include/asm/pci.h +++ b/arch/frv/include/asm/pci.h @@ -87,8 +87,7 @@ static inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { - if (direction == PCI_DMA_NONE) - BUG(); + BUG_ON(direction == PCI_DMA_NONE); frv_cache_wback_inv((unsigned long)bus_to_virt(dma_handle), (unsigned long)bus_to_virt(dma_handle) + size); @@ -105,9 +104,7 @@ static inline void pci_dma_sync_sg(struct pci_dev *hwdev, int nelems, int direction) { int i; - - if (direction == PCI_DMA_NONE) - BUG(); + BUG_ON(direction == PCI_DMA_NONE); for (i = 0; i < nelems; i++) frv_cache_wback_inv(sg_dma_address(&sg[i]), diff --git a/arch/frv/include/asm/ptrace.h b/arch/frv/include/asm/ptrace.h index cf6934012b6..a54b535c9e4 100644 --- a/arch/frv/include/asm/ptrace.h +++ b/arch/frv/include/asm/ptrace.h @@ -65,6 +65,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +struct task_struct; + /* * we dedicate GR28 to keeping a pointer to the current exception frame * - gr28 is destroyed on entry to the kernel from userspace @@ -73,11 +75,18 @@ register struct pt_regs *__frame asm("gr28"); #define user_mode(regs) (!((regs)->psr & PSR_S)) #define instruction_pointer(regs) ((regs)->pc) +#define user_stack_pointer(regs) ((regs)->sp) extern unsigned long user_stack(const struct pt_regs *); extern void show_regs(struct pt_regs *); #define profile_pc(regs) ((regs)->pc) -#endif + +#define task_pt_regs(task) ((task)->thread.frame0) + +#define arch_has_single_step() (1) +extern void user_enable_single_step(struct task_struct *); +extern void user_disable_single_step(struct task_struct *); #endif /* !__ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_PTRACE_H */ diff --git a/arch/frv/include/asm/syscall.h b/arch/frv/include/asm/syscall.h new file mode 100644 index 00000000000..70689eb29b9 --- /dev/null +++ b/arch/frv/include/asm/syscall.h @@ -0,0 +1,123 @@ +/* syscall parameter access functions + * + * Copyright (C) 2009 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 Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _ASM_SYSCALL_H +#define _ASM_SYSCALL_H + +#include <linux/err.h> +#include <asm/ptrace.h> + +/* + * Get the system call number or -1 + */ +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->syscallno; +} + +/* + * Restore the clobbered GR8 register + * (1st syscall arg was overwritten with syscall return or error) + */ +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + regs->gr8 = regs->orig_gr8; +} + +/* + * See if the syscall return value is an error, returning it if it is and 0 if + * not + */ +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->gr8) ? regs->gr8 : 0; +} + +/* + * Get the syscall return value + */ +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->gr8; +} + +/* + * Set the syscall return value + */ +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + if (error) + regs->gr8 = -error; + else + regs->gr8 = val; +} + +/* + * Retrieve the system call arguments + */ +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + /* + * Do this simply for now. If we need to start supporting + * fetching arguments from arbitrary indices, this will need some + * extra logic. Presently there are no in-tree users that depend + * on this behaviour. + */ + BUG_ON(i); + + /* Argument pattern is: GR8, GR9, GR10, GR11, GR12, GR13 */ + switch (n) { + case 6: args[5] = regs->gr13; + case 5: args[4] = regs->gr12; + case 4: args[3] = regs->gr11; + case 3: args[2] = regs->gr10; + case 2: args[1] = regs->gr9; + case 1: args[0] = regs->gr8; + break; + default: + BUG(); + } +} + +/* + * Alter the system call arguments + */ +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + /* Same note as above applies */ + BUG_ON(i); + + switch (n) { + case 6: regs->gr13 = args[5]; + case 5: regs->gr12 = args[4]; + case 4: regs->gr11 = args[3]; + case 3: regs->gr10 = args[2]; + case 2: regs->gr9 = args[1]; + case 1: regs->gr8 = args[0]; + break; + default: + BUG(); + } +} + +#endif /* _ASM_SYSCALL_H */ diff --git a/arch/frv/include/asm/thread_info.h b/arch/frv/include/asm/thread_info.h index bb53ab753ff..e8a5ed7be02 100644 --- a/arch/frv/include/asm/thread_info.h +++ b/arch/frv/include/asm/thread_info.h @@ -109,20 +109,20 @@ register struct thread_info *__current_thread_info asm("gr15"); * - other flags in MSW */ #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ -#define TIF_SIGPENDING 1 /* signal pending */ -#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */ -#define TIF_IRET 4 /* return with iret */ +#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 17 /* OOM killer killed process */ #define TIF_FREEZE 18 /* freezing for suspend */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) -#define _TIF_IRET (1 << TIF_IRET) #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_FREEZE (1 << TIF_FREEZE) diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index 1da523b3298..356e0e327a8 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -886,7 +886,6 @@ system_call: bnc icc0,#0,__syscall_badsys ldi @(gr15,#TI_FLAGS),gr4 - ori gr4,#_TIF_SYSCALL_TRACE,gr4 andicc gr4,#_TIF_SYSCALL_TRACE,gr0,icc0 bne icc0,#0,__syscall_trace_entry @@ -1150,11 +1149,10 @@ __entry_work_notifysig: # perform syscall entry tracing __syscall_trace_entry: LEDS 0x6320 - setlos.p #0,gr8 - call do_syscall_trace + call syscall_trace_entry - ldi @(gr28,#REG_SYSCALLNO),gr7 - lddi @(gr28,#REG_GR(8)) ,gr8 + lddi.p @(gr28,#REG_GR(8)) ,gr8 + ori gr8,#0,gr7 ; syscall_trace_entry() returned new syscallno lddi @(gr28,#REG_GR(10)),gr10 lddi.p @(gr28,#REG_GR(12)),gr12 @@ -1169,11 +1167,10 @@ __syscall_exit_work: beq icc0,#1,__entry_work_pending movsg psr,gr23 - andi gr23,#~PSR_PIL,gr23 ; could let do_syscall_trace() call schedule() + andi gr23,#~PSR_PIL,gr23 ; could let syscall_trace_exit() call schedule() movgs gr23,psr - setlos.p #1,gr8 - call do_syscall_trace + call syscall_trace_exit bra __entry_resume_userspace __syscall_badsys: diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c index 5e7d401d21e..60eeed3694c 100644 --- a/arch/frv/kernel/ptrace.c +++ b/arch/frv/kernel/ptrace.c @@ -19,6 +19,9 @@ #include <linux/user.h> #include <linux/security.h> #include <linux/signal.h> +#include <linux/regset.h> +#include <linux/elf.h> +#include <linux/tracehook.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -33,6 +36,169 @@ */ /* + * retrieve the contents of FRV userspace general registers + */ +static int genregs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct user_int_regs *iregs = &target->thread.user->i; + int ret; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + iregs, 0, sizeof(*iregs)); + if (ret < 0) + return ret; + + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(*iregs), -1); +} + +/* + * update the contents of the FRV userspace general registers + */ +static int genregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct user_int_regs *iregs = &target->thread.user->i; + unsigned int offs_gr0, offs_gr1; + int ret; + + /* not allowed to set PSR or __status */ + if (pos < offsetof(struct user_int_regs, psr) + sizeof(long) && + pos + count > offsetof(struct user_int_regs, psr)) + return -EIO; + + if (pos < offsetof(struct user_int_regs, __status) + sizeof(long) && + pos + count > offsetof(struct user_int_regs, __status)) + return -EIO; + + /* set the control regs */ + offs_gr0 = offsetof(struct user_int_regs, gr[0]); + offs_gr1 = offsetof(struct user_int_regs, gr[1]); + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + iregs, 0, offs_gr0); + if (ret < 0) + return ret; + + /* skip GR0/TBR */ + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + offs_gr0, offs_gr1); + if (ret < 0) + return ret; + + /* set the general regs */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &iregs->gr[1], offs_gr1, sizeof(*iregs)); + if (ret < 0) + return ret; + + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + sizeof(*iregs), -1); +} + +/* + * retrieve the contents of FRV userspace FP/Media registers + */ +static int fpmregs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct user_fpmedia_regs *fpregs = &target->thread.user->f; + int ret; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + fpregs, 0, sizeof(*fpregs)); + if (ret < 0) + return ret; + + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(*fpregs), -1); +} + +/* + * update the contents of the FRV userspace FP/Media registers + */ +static int fpmregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct user_fpmedia_regs *fpregs = &target->thread.user->f; + int ret; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, 0, sizeof(*fpregs)); + if (ret < 0) + return ret; + + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + sizeof(*fpregs), -1); +} + +/* + * determine if the FP/Media registers have actually been used + */ +static int fpmregs_active(struct task_struct *target, + const struct user_regset *regset) +{ + return tsk_used_math(target) ? regset->n : 0; +} + +/* + * Define the register sets available on the FRV under Linux + */ +enum frv_regset { + REGSET_GENERAL, + REGSET_FPMEDIA, +}; + +static const struct user_regset frv_regsets[] = { + /* + * General register format is: + * PSR, ISR, CCR, CCCR, LR, LCR, PC, (STATUS), SYSCALLNO, ORIG_G8 + * GNER0-1, IACC0, TBR, GR1-63 + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = ELF_NGREG, + .size = sizeof(long), + .align = sizeof(long), + .get = genregs_get, + .set = genregs_set, + }, + /* + * FPU/Media register format is: + * FR0-63, FNER0-1, MSR0-1, ACC0-7, ACCG0-8, FSR + */ + [REGSET_FPMEDIA] = { + .core_note_type = NT_PRFPREG, + .n = sizeof(struct user_fpmedia_regs) / sizeof(long), + .size = sizeof(long), + .align = sizeof(long), + .get = fpmregs_get, + .set = fpmregs_set, + .active = fpmregs_active, + }, +}; + +static const struct user_regset_view user_frv_native_view = { + .name = "frv", + .e_machine = EM_FRV, + .regsets = frv_regsets, + .n = ARRAY_SIZE(frv_regsets), +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_frv_native_view; +} + +/* * Get contents of register REGNO in task TASK. */ static inline long get_reg(struct task_struct *task, int regno) @@ -69,40 +235,23 @@ static inline int put_reg(struct task_struct *task, int regno, } /* - * check that an address falls within the bounds of the target process's memory - * mappings - */ -static inline int is_user_addr_valid(struct task_struct *child, - unsigned long start, unsigned long len) -{ -#ifdef CONFIG_MMU - if (start >= PAGE_OFFSET || len > PAGE_OFFSET - start) - return -EIO; - return 0; -#else - struct vm_area_struct *vma; - - vma = find_vma(child->mm, start); - if (vma && start >= vma->vm_start && start + len <= vma->vm_end) - return 0; - - return -EIO; -#endif -} - -/* * Called by kernel/ptrace.c when detaching.. * * Control h/w single stepping */ -void ptrace_disable(struct task_struct *child) +void user_enable_single_step(struct task_struct *child) +{ + child->thread.frame0->__status |= REG__STATUS_STEP; +} + +void user_disable_single_step(struct task_struct *child) { child->thread.frame0->__status &= ~REG__STATUS_STEP; } -void ptrace_enable(struct task_struct *child) +void ptrace_disable(struct task_struct *child) { - child->thread.frame0->__status |= REG__STATUS_STEP; + user_disable_single_step(child); } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -111,15 +260,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int ret; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = -EIO; - if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) - break; - ret = generic_ptrace_peekdata(child, addr, data); - break; - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { tmp = 0; @@ -163,15 +303,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = -EIO; - if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) - break; - ret = generic_ptrace_pokedata(child, addr, data); - break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; if ((addr & 3) || addr < 0) @@ -179,7 +310,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = 0; switch (addr >> 2) { - case 0 ... PT__END-1: + case 0 ... PT__END - 1: ret = put_reg(child, addr >> 2, data); break; @@ -189,95 +320,29 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - ptrace_disable(child); - wake_up_process(child); - ret = 0; - break; - - /* make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - clear_tsk_thread_flag(child, TIF_SINGLESTEP); - ptrace_disable(child); - wake_up_process(child); - break; - - case PTRACE_SINGLESTEP: /* set the trap flag. */ - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - ptrace_enable(child); - child->exit_code = data; - wake_up_process(child); - ret = 0; - break; - - case PTRACE_DETACH: /* detach a process that was attached. */ - ret = ptrace_detach(child, data); - break; - - case PTRACE_GETREGS: { /* Get all integer regs from the child. */ - int i; - for (i = 0; i < PT__GPEND; i++) { - tmp = get_reg(child, i); - if (put_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - data += sizeof(long); - } - ret = 0; - break; - } - - case PTRACE_SETREGS: { /* Set all integer regs in the child. */ - int i; - for (i = 0; i < PT__GPEND; i++) { - if (get_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - put_reg(child, i, tmp); - data += sizeof(long); - } - ret = 0; - break; - } - - case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */ - ret = 0; - if (copy_to_user((void *) data, - &child->thread.user->f, - sizeof(child->thread.user->f))) - ret = -EFAULT; - break; - } - - case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */ - ret = 0; - if (copy_from_user(&child->thread.user->f, - (void *) data, - sizeof(child->thread.user->f))) - ret = -EFAULT; - break; - } + case PTRACE_GETREGS: /* Get all integer regs from the child. */ + return copy_regset_to_user(child, &user_frv_native_view, + REGSET_GENERAL, + 0, sizeof(child->thread.user->i), + (void __user *)data); + + case PTRACE_SETREGS: /* Set all integer regs in the child. */ + return copy_regset_from_user(child, &user_frv_native_view, + REGSET_GENERAL, + 0, sizeof(child->thread.user->i), + (const void __user *)data); + + case PTRACE_GETFPREGS: /* Get the child FP/Media state. */ + return copy_regset_to_user(child, &user_frv_native_view, + REGSET_FPMEDIA, + 0, sizeof(child->thread.user->f), + (void __user *)data); + + case PTRACE_SETFPREGS: /* Set the child FP/Media state. */ + return copy_regset_from_user(child, &user_frv_native_view, + REGSET_FPMEDIA, + 0, sizeof(child->thread.user->f), + (const void __user *)data); case PTRACE_GETFDPIC: tmp = 0; @@ -300,414 +365,36 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } return ret; } -int __nongprelbss kstrace; - -static const struct { - const char *name; - unsigned argmask; -} __syscall_name_table[NR_syscalls] = { - [0] = { "restart_syscall" }, - [1] = { "exit", 0x000001 }, - [2] = { "fork", 0xffffff }, - [3] = { "read", 0x000141 }, - [4] = { "write", 0x000141 }, - [5] = { "open", 0x000235 }, - [6] = { "close", 0x000001 }, - [7] = { "waitpid", 0x000141 }, - [8] = { "creat", 0x000025 }, - [9] = { "link", 0x000055 }, - [10] = { "unlink", 0x000005 }, - [11] = { "execve", 0x000445 }, - [12] = { "chdir", 0x000005 }, - [13] = { "time", 0x000004 }, - [14] = { "mknod", 0x000325 }, - [15] = { "chmod", 0x000025 }, - [16] = { "lchown", 0x000025 }, - [17] = { "break" }, - [18] = { "oldstat", 0x000045 }, - [19] = { "lseek", 0x000131 }, - [20] = { "getpid", 0xffffff }, - [21] = { "mount", 0x043555 }, - [22] = { "umount", 0x000005 }, - [23] = { "setuid", 0x000001 }, - [24] = { "getuid", 0xffffff }, - [25] = { "stime", 0x000004 }, - [26] = { "ptrace", 0x004413 }, - [27] = { "alarm", 0x000001 }, - [28] = { "oldfstat", 0x000041 }, - [29] = { "pause", 0xffffff }, - [30] = { "utime", 0x000045 }, - [31] = { "stty" }, - [32] = { "gtty" }, - [33] = { "access", 0x000025 }, - [34] = { "nice", 0x000001 }, - [35] = { "ftime" }, - [36] = { "sync", 0xffffff }, - [37] = { "kill", 0x000011 }, - [38] = { "rename", 0x000055 }, - [39] = { "mkdir", 0x000025 }, - [40] = { "rmdir", 0x000005 }, - [41] = { "dup", 0x000001 }, - [42] = { "pipe", 0x000004 }, - [43] = { "times", 0x000004 }, - [44] = { "prof" }, - [45] = { "brk", 0x000004 }, - [46] = { "setgid", 0x000001 }, - [47] = { "getgid", 0xffffff }, - [48] = { "signal", 0x000041 }, - [49] = { "geteuid", 0xffffff }, - [50] = { "getegid", 0xffffff }, - [51] = { "acct", 0x000005 }, - [52] = { "umount2", 0x000035 }, - [53] = { "lock" }, - [54] = { "ioctl", 0x000331 }, - [55] = { "fcntl", 0x000331 }, - [56] = { "mpx" }, - [57] = { "setpgid", 0x000011 }, - [58] = { "ulimit" }, - [60] = { "umask", 0x000002 }, - [61] = { "chroot", 0x000005 }, - [62] = { "ustat", 0x000043 }, - [63] = { "dup2", 0x000011 }, - [64] = { "getppid", 0xffffff }, - [65] = { "getpgrp", 0xffffff }, - [66] = { "setsid", 0xffffff }, - [67] = { "sigaction" }, - [68] = { "sgetmask" }, - [69] = { "ssetmask" }, - [70] = { "setreuid" }, - [71] = { "setregid" }, - [72] = { "sigsuspend" }, - [73] = { "sigpending" }, - [74] = { "sethostname" }, - [75] = { "setrlimit" }, - [76] = { "getrlimit" }, - [77] = { "getrusage" }, - [78] = { "gettimeofday" }, - [79] = { "settimeofday" }, - [80] = { "getgroups" }, - [81] = { "setgroups" }, - [82] = { "select" }, - [83] = { "symlink" }, - [84] = { "oldlstat" }, - [85] = { "readlink" }, - [86] = { "uselib" }, - [87] = { "swapon" }, - [88] = { "reboot" }, - [89] = { "readdir" }, - [91] = { "munmap", 0x000034 }, - [92] = { "truncate" }, - [93] = { "ftruncate" }, - [94] = { "fchmod" }, - [95] = { "fchown" }, - [96] = { "getpriority" }, - [97] = { "setpriority" }, - [99] = { "statfs" }, - [100] = { "fstatfs" }, - [102] = { "socketcall" }, - [103] = { "syslog" }, - [104] = { "setitimer" }, - [105] = { "getitimer" }, - [106] = { "stat" }, - [107] = { "lstat" }, - [108] = { "fstat" }, - [111] = { "vhangup" }, - [114] = { "wait4" }, - [115] = { "swapoff" }, - [116] = { "sysinfo" }, - [117] = { "ipc" }, - [118] = { "fsync" }, - [119] = { "sigreturn" }, - [120] = { "clone" }, - [121] = { "setdomainname" }, - [122] = { "uname" }, - [123] = { "modify_ldt" }, - [123] = { "cacheflush" }, - [124] = { "adjtimex" }, - [125] = { "mprotect" }, - [126] = { "sigprocmask" }, - [127] = { "create_module" }, - [128] = { "init_module" }, - [129] = { "delete_module" }, - [130] = { "get_kernel_syms" }, - [131] = { "quotactl" }, - [132] = { "getpgid" }, - [133] = { "fchdir" }, - [134] = { "bdflush" }, - [135] = { "sysfs" }, - [136] = { "personality" }, - [137] = { "afs_syscall" }, - [138] = { "setfsuid" }, - [139] = { "setfsgid" }, - [140] = { "_llseek", 0x014331 }, - [141] = { "getdents" }, - [142] = { "_newselect", 0x000141 }, - [143] = { "flock" }, - [144] = { "msync" }, - [145] = { "readv" }, - [146] = { "writev" }, - [147] = { "getsid", 0x000001 }, - [148] = { "fdatasync", 0x000001 }, - [149] = { "_sysctl", 0x000004 }, - [150] = { "mlock" }, - [151] = { "munlock" }, - [152] = { "mlockall" }, - [153] = { "munlockall" }, - [154] = { "sched_setparam" }, - [155] = { "sched_getparam" }, - [156] = { "sched_setscheduler" }, - [157] = { "sched_getscheduler" }, - [158] = { "sched_yield" }, - [159] = { "sched_get_priority_max" }, - [160] = { "sched_get_priority_min" }, - [161] = { "sched_rr_get_interval" }, - [162] = { "nanosleep", 0x000044 }, - [163] = { "mremap" }, - [164] = { "setresuid" }, - [165] = { "getresuid" }, - [166] = { "vm86" }, - [167] = { "query_module" }, - [168] = { "poll" }, - [169] = { "nfsservctl" }, - [170] = { "setresgid" }, - [171] = { "getresgid" }, - [172] = { "prctl", 0x333331 }, - [173] = { "rt_sigreturn", 0xffffff }, - [174] = { "rt_sigaction", 0x001441 }, - [175] = { "rt_sigprocmask", 0x001441 }, - [176] = { "rt_sigpending", 0x000014 }, - [177] = { "rt_sigtimedwait", 0x001444 }, - [178] = { "rt_sigqueueinfo", 0x000411 }, - [179] = { "rt_sigsuspend", 0x000014 }, - [180] = { "pread", 0x003341 }, - [181] = { "pwrite", 0x003341 }, - [182] = { "chown", 0x000115 }, - [183] = { "getcwd" }, - [184] = { "capget" }, - [185] = { "capset" }, - [186] = { "sigaltstack" }, - [187] = { "sendfile" }, - [188] = { "getpmsg" }, - [189] = { "putpmsg" }, - [190] = { "vfork", 0xffffff }, - [191] = { "ugetrlimit" }, - [192] = { "mmap2", 0x313314 }, - [193] = { "truncate64" }, - [194] = { "ftruncate64" }, - [195] = { "stat64", 0x000045 }, - [196] = { "lstat64", 0x000045 }, - [197] = { "fstat64", 0x000041 }, - [198] = { "lchown32" }, - [199] = { "getuid32", 0xffffff }, - [200] = { "getgid32", 0xffffff }, - [201] = { "geteuid32", 0xffffff }, - [202] = { "getegid32", 0xffffff }, - [203] = { "setreuid32" }, - [204] = { "setregid32" }, - [205] = { "getgroups32" }, - [206] = { "setgroups32" }, - [207] = { "fchown32" }, - [208] = { "setresuid32" }, - [209] = { "getresuid32" }, - [210] = { "setresgid32" }, - [211] = { "getresgid32" }, - [212] = { "chown32" }, - [213] = { "setuid32" }, - [214] = { "setgid32" }, - [215] = { "setfsuid32" }, - [216] = { "setfsgid32" }, - [217] = { "pivot_root" }, - [218] = { "mincore" }, - [219] = { "madvise" }, - [220] = { "getdents64" }, - [221] = { "fcntl64" }, - [223] = { "security" }, - [224] = { "gettid" }, - [225] = { "readahead" }, - [226] = { "setxattr" }, - [227] = { "lsetxattr" }, - [228] = { "fsetxattr" }, - [229] = { "getxattr" }, - [230] = { "lgetxattr" }, - [231] = { "fgetxattr" }, - [232] = { "listxattr" }, - [233] = { "llistxattr" }, - [234] = { "flistxattr" }, - [235] = { "removexattr" }, - [236] = { "lremovexattr" }, - [237] = { "fremovexattr" }, - [238] = { "tkill" }, - [239] = { "sendfile64" }, - [240] = { "futex" }, - [241] = { "sched_setaffinity" }, - [242] = { "sched_getaffinity" }, - [243] = { "set_thread_area" }, - [244] = { "get_thread_area" }, - [245] = { "io_setup" }, - [246] = { "io_destroy" }, - [247] = { "io_getevents" }, - [248] = { "io_submit" }, - [249] = { "io_cancel" }, - [250] = { "fadvise64" }, - [252] = { "exit_group", 0x000001 }, - [253] = { "lookup_dcookie" }, - [254] = { "epoll_create" }, - [255] = { "epoll_ctl" }, - [256] = { "epoll_wait" }, - [257] = { "remap_file_pages" }, - [258] = { "set_tid_address" }, - [259] = { "timer_create" }, - [260] = { "timer_settime" }, - [261] = { "timer_gettime" }, - [262] = { "timer_getoverrun" }, - [263] = { "timer_delete" }, - [264] = { "clock_settime" }, - [265] = { "clock_gettime" }, - [266] = { "clock_getres" }, - [267] = { "clock_nanosleep" }, - [268] = { "statfs64" }, - [269] = { "fstatfs64" }, - [270] = { "tgkill" }, - [271] = { "utimes" }, - [272] = { "fadvise64_64" }, - [273] = { "vserver" }, - [274] = { "mbind" }, - [275] = { "get_mempolicy" }, - [276] = { "set_mempolicy" }, - [277] = { "mq_open" }, - [278] = { "mq_unlink" }, - [279] = { "mq_timedsend" }, - [280] = { "mq_timedreceive" }, - [281] = { "mq_notify" }, - [282] = { "mq_getsetattr" }, - [283] = { "sys_kexec_load" }, -}; - -asmlinkage void do_syscall_trace(int leaving) +/* + * handle tracing of system call entry + * - return the revised system call number or ULONG_MAX to cause ENOSYS + */ +asmlinkage unsigned long syscall_trace_entry(void) { -#if 0 - unsigned long *argp; - const char *name; - unsigned argmask; - char buffer[16]; - - if (!kstrace) - return; - - if (!current->mm) - return; - - if (__frame->gr7 == __NR_close) - return; - -#if 0 - if (__frame->gr7 != __NR_mmap2 && - __frame->gr7 != __NR_vfork && - __frame->gr7 != __NR_execve && - __frame->gr7 != __NR_exit) - return; -#endif - - argmask = 0; - name = NULL; - if (__frame->gr7 < NR_syscalls) { - name = __syscall_name_table[__frame->gr7].name; - argmask = __syscall_name_table[__frame->gr7].argmask; - } - if (!name) { - sprintf(buffer, "sys_%lx", __frame->gr7); - name = buffer; - } - - if (!leaving) { - if (!argmask) { - printk(KERN_CRIT "[%d] %s(%lx,%lx,%lx,%lx,%lx,%lx)\n", - current->pid, - name, - __frame->gr8, - __frame->gr9, - __frame->gr10, - __frame->gr11, - __frame->gr12, - __frame->gr13); - } - else if (argmask == 0xffffff) { - printk(KERN_CRIT "[%d] %s()\n", - current->pid, - name); - } - else { - printk(KERN_CRIT "[%d] %s(", - current->pid, - name); - - argp = &__frame->gr8; - - do { - switch (argmask & 0xf) { - case 1: - printk("%ld", (long) *argp); - break; - case 2: - printk("%lo", *argp); - break; - case 3: - printk("%lx", *argp); - break; - case 4: - printk("%p", (void *) *argp); - break; - case 5: - printk("\"%s\"", (char *) *argp); - break; - } - - argp++; - argmask >>= 4; - if (argmask) - printk(","); - - } while (argmask); - - printk(")\n"); - } - } - else { - if ((int)__frame->gr8 > -4096 && (int)__frame->gr8 < 4096) - printk(KERN_CRIT "[%d] %s() = %ld\n", current->pid, name, __frame->gr8); - else - printk(KERN_CRIT "[%d] %s() = %lx\n", current->pid, name, __frame->gr8); + __frame->__status |= REG__STATUS_SYSC_ENTRY; + if (tracehook_report_syscall_entry(__frame)) { + /* tracing decided this syscall should not happen, so + * We'll return a bogus call number to get an ENOSYS + * error, but leave the original number in + * __frame->syscallno + */ + return ULONG_MAX; } - return; -#endif - - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - - if (!(current->ptrace & PT_PTRACED)) - return; - /* we need to indicate entry or exit to strace */ - if (leaving) - __frame->__status |= REG__STATUS_SYSC_EXIT; - else - __frame->__status |= REG__STATUS_SYSC_ENTRY; - - ptrace_notify(SIGTRAP); + return __frame->syscallno; +} - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } +/* + * handle tracing of system call exit + */ +asmlinkage void syscall_trace_exit(void) +{ + __frame->__status |= REG__STATUS_SYSC_EXIT; + tracehook_report_syscall_exit(__frame, 0); } diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 3bdb368292a..4a7a62c6e78 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -21,6 +21,7 @@ #include <linux/unistd.h> #include <linux/personality.h> #include <linux/freezer.h> +#include <linux/tracehook.h> #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/cacheflush.h> @@ -516,6 +517,9 @@ static void do_signal(void) * clear the TIF_RESTORE_SIGMASK flag */ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, __frame, + test_thread_flag(TIF_SINGLESTEP)); } return; @@ -564,4 +568,10 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(); + /* deal with notification on about to resume userspace execution */ + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(__frame); + } + } /* end do_notify_resume() */ diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c index 9fb771a20df..374f88d6cc0 100644 --- a/arch/frv/kernel/uaccess.c +++ b/arch/frv/kernel/uaccess.c @@ -23,8 +23,7 @@ long strncpy_from_user(char *dst, const char __user *src, long count) char *p, ch; long err = -EFAULT; - if (count < 0) - BUG(); + BUG_ON(count < 0); p = dst; @@ -76,8 +75,7 @@ long strnlen_user(const char __user *src, long count) long err = 0; char ch; - if (count < 0) - BUG(); + BUG_ON(count < 0); #ifndef CONFIG_MMU if ((unsigned long) src < memory_start) diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c index 52ff9aec799..4e1ba0b1544 100644 --- a/arch/frv/mb93090-mb00/pci-dma-nommu.c +++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c @@ -116,8 +116,7 @@ EXPORT_SYMBOL(dma_free_coherent); dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction direction) { - if (direction == DMA_NONE) - BUG(); + BUG_ON(direction == DMA_NONE); frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size); @@ -151,8 +150,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, frv_cache_wback_inv(sg_dma_address(&sg[i]), sg_dma_address(&sg[i]) + sg_dma_len(&sg[i])); - if (direction == DMA_NONE) - BUG(); + BUG_ON(direction == DMA_NONE); return nents; } diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c index 3ddedebc4eb..45954f0813d 100644 --- a/arch/frv/mb93090-mb00/pci-dma.c +++ b/arch/frv/mb93090-mb00/pci-dma.c @@ -48,8 +48,7 @@ EXPORT_SYMBOL(dma_free_coherent); dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction direction) { - if (direction == DMA_NONE) - BUG(); + BUG_ON(direction == DMA_NONE); frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size); @@ -81,8 +80,7 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, void *vaddr; int i; - if (direction == DMA_NONE) - BUG(); + BUG_ON(direction == DMA_NONE); dampr2 = __get_DAMPR(2); |