From 6bc9a3966f0395419b09b2ec90f89f7f00341b37 Mon Sep 17 00:00:00 2001 From: Chen Liqin Date: Fri, 12 Jun 2009 22:01:00 +0800 Subject: score: Add support for Sunplus S+core architecture This is the complete set of new arch Score's files for linux. Score instruction set support 16bits, 32bits and 64bits instruction, Score SOC had been used in game machine and LCD TV. Signed-off-by: Chen Liqin Signed-off-by: Arnd Bergmann --- arch/score/kernel/ptrace.c | 465 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 arch/score/kernel/ptrace.c (limited to 'arch/score/kernel/ptrace.c') diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c new file mode 100644 index 00000000000..8fe7209355a --- /dev/null +++ b/arch/score/kernel/ptrace.c @@ -0,0 +1,465 @@ +/* + * arch/score/kernel/ptrace.c + * + * Score Processor version. + * + * Copyright (C) 2009 Sunplus Core Technology Co., Ltd. + * Chen Liqin + * Lennox Wu + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include + +static int is_16bitinsn(unsigned long insn) +{ + if ((insn & INSN32_MASK) == INSN32_MASK) + return 0; + else + return 1; +} + +int +read_tsk_long(struct task_struct *child, + unsigned long addr, unsigned long *res) +{ + int copied; + + copied = access_process_vm(child, addr, res, sizeof(*res), 0); + + return copied != sizeof(*res) ? -EIO : 0; +} + +int +read_tsk_short(struct task_struct *child, + unsigned long addr, unsigned short *res) +{ + int copied; + + copied = access_process_vm(child, addr, res, sizeof(*res), 0); + + return copied != sizeof(*res) ? -EIO : 0; +} + +static int +write_tsk_short(struct task_struct *child, + unsigned long addr, unsigned short val) +{ + int copied; + + copied = access_process_vm(child, addr, &val, sizeof(val), 1); + + return copied != sizeof(val) ? -EIO : 0; +} + +static int +write_tsk_long(struct task_struct *child, + unsigned long addr, unsigned long val) +{ + int copied; + + copied = access_process_vm(child, addr, &val, sizeof(val), 1); + + return copied != sizeof(val) ? -EIO : 0; +} + +void set_single_step(struct task_struct *child) +{ + /* far_epc is the target of branch */ + unsigned int epc, far_epc = 0; + unsigned long epc_insn, far_epc_insn; + int ninsn_type; /* next insn type 0=16b, 1=32b */ + unsigned int tmp, tmp2; + struct pt_regs *regs = task_pt_regs(child); + child->thread.single_step = 1; + child->thread.ss_nextcnt = 1; + epc = regs->cp0_epc; + + read_tsk_long(child, epc, &epc_insn); + + if (is_16bitinsn(epc_insn)) { + if ((epc_insn & J16M) == J16) { + tmp = epc_insn & 0xFFE; + epc = (epc & 0xFFFFF000) | tmp; + } else if ((epc_insn & B16M) == B16) { + child->thread.ss_nextcnt = 2; + tmp = (epc_insn & 0xFF) << 1; + tmp = tmp << 23; + tmp = (unsigned int)((int) tmp >> 23); + far_epc = epc + tmp; + epc += 2; + } else if ((epc_insn & BR16M) == BR16) { + child->thread.ss_nextcnt = 2; + tmp = (epc_insn >> 4) & 0xF; + far_epc = regs->regs[tmp]; + epc += 2; + } else + epc += 2; + } else { + if ((epc_insn & J32M) == J32) { + tmp = epc_insn & 0x03FFFFFE; + tmp2 = tmp & 0x7FFF; + tmp = (((tmp >> 16) & 0x3FF) << 15) | tmp2; + epc = (epc & 0xFFC00000) | tmp; + } else if ((epc_insn & B32M) == B32) { + child->thread.ss_nextcnt = 2; + tmp = epc_insn & 0x03FFFFFE; /* discard LK bit */ + tmp2 = tmp & 0x3FF; + tmp = (((tmp >> 16) & 0x3FF) << 10) | tmp2; /* 20bit */ + tmp = tmp << 12; + tmp = (unsigned int)((int) tmp >> 12); + far_epc = epc + tmp; + epc += 4; + } else if ((epc_insn & BR32M) == BR32) { + child->thread.ss_nextcnt = 2; + tmp = (epc_insn >> 16) & 0x1F; + far_epc = regs->regs[tmp]; + epc += 4; + } else + epc += 4; + } + + if (child->thread.ss_nextcnt == 1) { + read_tsk_long(child, epc, &epc_insn); + + if (is_16bitinsn(epc_insn)) { + write_tsk_short(child, epc, SINGLESTEP16_INSN); + ninsn_type = 0; + } else { + write_tsk_long(child, epc, SINGLESTEP32_INSN); + ninsn_type = 1; + } + + if (ninsn_type == 0) { /* 16bits */ + child->thread.insn1_type = 0; + child->thread.addr1 = epc; + /* the insn may have 32bit data */ + child->thread.insn1 = (short)epc_insn; + } else { + child->thread.insn1_type = 1; + child->thread.addr1 = epc; + child->thread.insn1 = epc_insn; + } + } else { + /* branch! have two target child->thread.ss_nextcnt=2 */ + read_tsk_long(child, epc, &epc_insn); + read_tsk_long(child, far_epc, &far_epc_insn); + if (is_16bitinsn(epc_insn)) { + write_tsk_short(child, epc, SINGLESTEP16_INSN); + ninsn_type = 0; + } else { + write_tsk_long(child, epc, SINGLESTEP32_INSN); + ninsn_type = 1; + } + + if (ninsn_type == 0) { /* 16bits */ + child->thread.insn1_type = 0; + child->thread.addr1 = epc; + /* the insn may have 32bit data */ + child->thread.insn1 = (short)epc_insn; + } else { + child->thread.insn1_type = 1; + child->thread.addr1 = epc; + child->thread.insn1 = epc_insn; + } + + if (is_16bitinsn(far_epc_insn)) { + write_tsk_short(child, far_epc, SINGLESTEP16_INSN); + ninsn_type = 0; + } else { + write_tsk_long(child, far_epc, SINGLESTEP32_INSN); + ninsn_type = 1; + } + + if (ninsn_type == 0) { /* 16bits */ + child->thread.insn2_type = 0; + child->thread.addr2 = far_epc; + /* the insn may have 32bit data */ + child->thread.insn2 = (short)far_epc_insn; + } else { + child->thread.insn2_type = 1; + child->thread.addr2 = far_epc; + child->thread.insn2 = far_epc_insn; + } + } +} + +void clear_single_step(struct task_struct *child) +{ + if (child->thread.insn1_type == 0) + write_tsk_short(child, child->thread.addr1, + child->thread.insn1); + + if (child->thread.insn1_type == 1) + write_tsk_long(child, child->thread.addr1, + child->thread.insn1); + + if (child->thread.ss_nextcnt == 2) { /* branch */ + if (child->thread.insn1_type == 0) + write_tsk_short(child, child->thread.addr1, + child->thread.insn1); + if (child->thread.insn1_type == 1) + write_tsk_long(child, child->thread.addr1, + child->thread.insn1); + if (child->thread.insn2_type == 0) + write_tsk_short(child, child->thread.addr2, + child->thread.insn2); + if (child->thread.insn2_type == 1) + write_tsk_long(child, child->thread.addr2, + child->thread.insn2); + } + + child->thread.single_step = 0; + child->thread.ss_nextcnt = 0; +} + + +void ptrace_disable(struct task_struct *child) {} + +long +arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + int ret; + + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + return -EPERM; + + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + return 0; + } + + ret = -ESRCH; + if (!child) + return ret; + + ret = -EPERM; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + return ret; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + return ret; + + switch (request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + + ret = put_user(tmp, (unsigned long *) data); + return ret; + } + + /* Read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + struct pt_regs *regs; + unsigned long tmp; + + regs = task_pt_regs(child); + + tmp = 0; /* Default return value. */ + switch (addr) { + case 0 ... 31: + tmp = regs->regs[addr]; + break; + case PC: + tmp = regs->cp0_epc; + break; + case ECR: + tmp = regs->cp0_ecr; + break; + case EMA: + tmp = regs->cp0_ema; + break; + case CEH: + tmp = regs->ceh; + break; + case CEL: + tmp = regs->cel; + break; + case CONDITION: + tmp = regs->cp0_condition; + break; + case PSR: + tmp = regs->cp0_psr; + break; + case COUNTER: + tmp = regs->sr0; + break; + case LDCR: + tmp = regs->sr1; + break; + case STCR: + tmp = regs->sr2; + break; + default: + tmp = 0; + return -EIO; + } + + ret = put_user(tmp, (unsigned long *) data); + return ret; + } + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) + == sizeof(data)) + break; + ret = -EIO; + return ret; + + case PTRACE_POKEUSR: { + struct pt_regs *regs; + ret = 0; + regs = task_pt_regs(child); + + switch (addr) { + case 0 ... 31: + regs->regs[addr] = data; + break; + case PC: + regs->cp0_epc = data; + break; + case CEH: + regs->ceh = data; + break; + case CEL: + regs->cel = data; + break; + case CONDITION: + regs->cp0_condition = data; + break; + case PSR: + case COUNTER: + case STCR: + case LDCR: + break; /* user can't write the reg */ + default: + /* The rest are not allowed. */ + ret = -EIO; + break; + } + 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; + 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->state == EXIT_ZOMBIE) /* already dead. */ + break; + child->exit_code = SIGKILL; + clear_single_step(child); + wake_up_process(child); + break; + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + set_single_step(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + case PTRACE_SETOPTIONS: + if (data & PTRACE_O_TRACESYSGOOD) + child->ptrace |= PT_TRACESYSGOOD; + else + child->ptrace &= ~PT_TRACESYSGOOD; + ret = 0; + break; + + default: + ret = -EIO; + break; + } + + return ret; +} + +/* + * Notification of system call entry/exit + * - triggered by current->work.syscall_trace + */ +asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) +{ + if (!(current->ptrace & PT_PTRACED)) + return; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + /* The 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery. */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? + 0x80 : 0)); + + /* + * 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; + } +} -- cgit v1.2.3 From 0402c91af944c61bf788370f03326959a35cb8be Mon Sep 17 00:00:00 2001 From: Chen Liqin Date: Fri, 19 Jun 2009 13:53:49 +0800 Subject: score: update files according to review comments modified: arch/score/include/asm/cacheflush.h modified: arch/score/include/asm/delay.h modified: arch/score/include/asm/errno.h modified: arch/score/include/asm/pgtable-bits.h modified: arch/score/include/asm/pgtable.h modified: arch/score/include/asm/ptrace.h modified: arch/score/include/asm/unistd.h modified: arch/score/kernel/entry.S modified: arch/score/kernel/process.c modified: arch/score/kernel/ptrace.c modified: arch/score/kernel/signal.c modified: arch/score/kernel/sys_score.c modified: arch/score/kernel/traps.c modified: arch/score/mm/cache.c Signed-off-by: Chen Liqin Signed-off-by: Arnd Bergmann --- arch/score/kernel/ptrace.c | 144 ++++++++++++--------------------------------- 1 file changed, 39 insertions(+), 105 deletions(-) (limited to 'arch/score/kernel/ptrace.c') diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 8fe7209355a..19911e3187b 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c @@ -80,7 +80,35 @@ write_tsk_long(struct task_struct *child, return copied != sizeof(val) ? -EIO : 0; } -void set_single_step(struct task_struct *child) +/* + * Get all user integer registers. + */ +static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs *regs = task_pt_regs(tsk); + + return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; +} + +/* + * Set all user integer registers. + */ +static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) +{ + struct pt_regs newregs; + int ret; + + ret = -EFAULT; + if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { + struct pt_regs *regs = task_pt_regs(tsk); + *regs = newregs; + ret = 0; + } + + return ret; +} + +void user_enable_single_step(struct task_struct *child) { /* far_epc is the target of branch */ unsigned int epc, far_epc = 0; @@ -201,7 +229,7 @@ void set_single_step(struct task_struct *child) } } -void clear_single_step(struct task_struct *child) +void user_disable_single_step(struct task_struct *child) { if (child->thread.insn1_type == 0) write_tsk_short(child, child->thread.addr1, @@ -230,54 +258,17 @@ void clear_single_step(struct task_struct *child) child->thread.ss_nextcnt = 0; } - -void ptrace_disable(struct task_struct *child) {} +void ptrace_disable(struct task_struct *child) +{ + user_disable_single_step(child); +} long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - return -EPERM; - - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - return 0; - } - - ret = -ESRCH; - if (!child) - return ret; - - ret = -EPERM; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - return ret; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - return ret; - switch (request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - - ret = put_user(tmp, (unsigned long *) data); - return ret; - } - /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; @@ -329,15 +320,6 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) - == sizeof(data)) - break; - ret = -EIO; - return ret; - case PTRACE_POKEUSR: { struct pt_regs *regs; ret = 0; @@ -372,64 +354,16 @@ 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; - 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->state == EXIT_ZOMBIE) /* already dead. */ - break; - child->exit_code = SIGKILL; - clear_single_step(child); - wake_up_process(child); + case PTRACE_GETREGS: + ret = ptrace_getregs(child, (void __user *)data); break; - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - set_single_step(child); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } - - case PTRACE_DETACH: /* detach a process that was attached. */ - ret = ptrace_detach(child, data); - break; - - case PTRACE_SETOPTIONS: - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; + case PTRACE_SETREGS: + ret = ptrace_setregs(child, (void __user *)data); break; default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } -- cgit v1.2.3 From a1f8213b9518d0e9124a48a34bdd58b4bc2650e5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 27 Jun 2009 15:05:30 +0200 Subject: score: add address space annotations Annotate the address space for pointers that are used correctly with __user and __iomem, so that sparse can better warn about incorrect casts. Signed-off-by: Arnd Bergmann --- arch/score/kernel/ptrace.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/score/kernel/ptrace.c') diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 19911e3187b..1db876b1147 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c @@ -267,6 +267,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; + unsigned long __user *datap = (void __user *)data; switch (request) { /* Read the word at location addr in the USER area. */ @@ -316,7 +317,7 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) return -EIO; } - ret = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, (unsigned int __user *) datap); return ret; } @@ -355,11 +356,11 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_GETREGS: - ret = ptrace_getregs(child, (void __user *)data); + ret = ptrace_getregs(child, (void __user *)datap); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (void __user *)data); + ret = ptrace_setregs(child, (void __user *)datap); break; default: -- cgit v1.2.3 From 798983b2d5f9985655ca22a7a8c504b821e3f4e0 Mon Sep 17 00:00:00 2001 From: Chen Liqin Date: Sun, 30 Aug 2009 12:34:08 +0800 Subject: score: update files according to review comments. --- arch/score/kernel/ptrace.c | 212 +++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 115 deletions(-) (limited to 'arch/score/kernel/ptrace.c') diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 1db876b1147..174c6422b09 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c @@ -23,11 +23,100 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include +#include #include +#include #include +/* + * retrieve the contents of SCORE 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 pt_regs *regs = task_pt_regs(target); + int ret; + + /* skip 9 * sizeof(unsigned long) not use for pt_regs */ + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 0, offsetof(struct pt_regs, regs)); + + /* r0 - r31, cel, ceh, sr0, sr1, sr2, epc, ema, psr, ecr, condition */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs->regs, + offsetof(struct pt_regs, regs), + offsetof(struct pt_regs, cp0_condition)); + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(struct pt_regs), -1); + + return ret; +} + +/* + * update the contents of the SCORE 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 pt_regs *regs = task_pt_regs(target); + int ret; + + /* skip 9 * sizeof(unsigned long) */ + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 0, offsetof(struct pt_regs, regs)); + + /* r0 - r31, cel, ceh, sr0, sr1, sr2, epc, ema, psr, ecr, condition */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + regs->regs, + offsetof(struct pt_regs, regs), + offsetof(struct pt_regs, cp0_condition)); + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + sizeof(struct pt_regs), -1); + + return ret; +} + +/* + * Define the register sets available on the score7 under Linux + */ +enum score7_regset { + REGSET_GENERAL, +}; + +static const struct user_regset score7_regsets[] = { + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = ELF_NGREG, + .size = sizeof(long), + .align = sizeof(long), + .get = genregs_get, + .set = genregs_set, + }, +}; + +static const struct user_regset_view user_score_native_view = { + .name = "score7", + .e_machine = EM_SCORE7, + .regsets = score7_regsets, + .n = ARRAY_SIZE(score7_regsets), +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_score_native_view; +} + static int is_16bitinsn(unsigned long insn) { if ((insn & INSN32_MASK) == INSN32_MASK) @@ -80,34 +169,6 @@ write_tsk_long(struct task_struct *child, return copied != sizeof(val) ? -EIO : 0; } -/* - * Get all user integer registers. - */ -static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) -{ - struct pt_regs *regs = task_pt_regs(tsk); - - return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; -} - -/* - * Set all user integer registers. - */ -static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) -{ - struct pt_regs newregs; - int ret; - - ret = -EFAULT; - if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { - struct pt_regs *regs = task_pt_regs(tsk); - *regs = newregs; - ret = 0; - } - - return ret; -} - void user_enable_single_step(struct task_struct *child) { /* far_epc is the target of branch */ @@ -270,97 +331,18 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned long __user *datap = (void __user *)data; switch (request) { - /* Read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - struct pt_regs *regs; - unsigned long tmp; - - regs = task_pt_regs(child); - - tmp = 0; /* Default return value. */ - switch (addr) { - case 0 ... 31: - tmp = regs->regs[addr]; - break; - case PC: - tmp = regs->cp0_epc; - break; - case ECR: - tmp = regs->cp0_ecr; - break; - case EMA: - tmp = regs->cp0_ema; - break; - case CEH: - tmp = regs->ceh; - break; - case CEL: - tmp = regs->cel; - break; - case CONDITION: - tmp = regs->cp0_condition; - break; - case PSR: - tmp = regs->cp0_psr; - break; - case COUNTER: - tmp = regs->sr0; - break; - case LDCR: - tmp = regs->sr1; - break; - case STCR: - tmp = regs->sr2; - break; - default: - tmp = 0; - return -EIO; - } - - ret = put_user(tmp, (unsigned int __user *) datap); - return ret; - } - - case PTRACE_POKEUSR: { - struct pt_regs *regs; - ret = 0; - regs = task_pt_regs(child); - - switch (addr) { - case 0 ... 31: - regs->regs[addr] = data; - break; - case PC: - regs->cp0_epc = data; - break; - case CEH: - regs->ceh = data; - break; - case CEL: - regs->cel = data; - break; - case CONDITION: - regs->cp0_condition = data; - break; - case PSR: - case COUNTER: - case STCR: - case LDCR: - break; /* user can't write the reg */ - default: - /* The rest are not allowed. */ - ret = -EIO; - break; - } - break; - } - case PTRACE_GETREGS: - ret = ptrace_getregs(child, (void __user *)datap); + ret = copy_regset_to_user(child, &user_score_native_view, + REGSET_GENERAL, + 0, sizeof(struct pt_regs), + (void __user *)datap); break; case PTRACE_SETREGS: - ret = ptrace_setregs(child, (void __user *)datap); + ret = copy_regset_from_user(child, &user_score_native_view, + REGSET_GENERAL, + 0, sizeof(struct pt_regs), + (const void __user *)datap); break; default: -- cgit v1.2.3