diff options
| -rw-r--r-- | arch/score/kernel/ptrace.c | 212 |
1 files changed, 97 insertions, 115 deletions
diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 1db876b11476..174c6422b096 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c | |||
| @@ -23,11 +23,100 @@ | |||
| 23 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 23 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/elf.h> | ||
| 26 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
| 28 | #include <linux/mm.h> | ||
| 27 | #include <linux/ptrace.h> | 29 | #include <linux/ptrace.h> |
| 30 | #include <linux/regset.h> | ||
| 28 | 31 | ||
| 29 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 30 | 33 | ||
| 34 | /* | ||
| 35 | * retrieve the contents of SCORE userspace general registers | ||
| 36 | */ | ||
| 37 | static int genregs_get(struct task_struct *target, | ||
| 38 | const struct user_regset *regset, | ||
| 39 | unsigned int pos, unsigned int count, | ||
| 40 | void *kbuf, void __user *ubuf) | ||
| 41 | { | ||
| 42 | const struct pt_regs *regs = task_pt_regs(target); | ||
| 43 | int ret; | ||
| 44 | |||
| 45 | /* skip 9 * sizeof(unsigned long) not use for pt_regs */ | ||
| 46 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 47 | 0, offsetof(struct pt_regs, regs)); | ||
| 48 | |||
| 49 | /* r0 - r31, cel, ceh, sr0, sr1, sr2, epc, ema, psr, ecr, condition */ | ||
| 50 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
| 51 | regs->regs, | ||
| 52 | offsetof(struct pt_regs, regs), | ||
| 53 | offsetof(struct pt_regs, cp0_condition)); | ||
| 54 | |||
| 55 | if (!ret) | ||
| 56 | ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 57 | sizeof(struct pt_regs), -1); | ||
| 58 | |||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* | ||
| 63 | * update the contents of the SCORE userspace general registers | ||
| 64 | */ | ||
| 65 | static int genregs_set(struct task_struct *target, | ||
| 66 | const struct user_regset *regset, | ||
| 67 | unsigned int pos, unsigned int count, | ||
| 68 | const void *kbuf, const void __user *ubuf) | ||
| 69 | { | ||
| 70 | struct pt_regs *regs = task_pt_regs(target); | ||
| 71 | int ret; | ||
| 72 | |||
| 73 | /* skip 9 * sizeof(unsigned long) */ | ||
| 74 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 75 | 0, offsetof(struct pt_regs, regs)); | ||
| 76 | |||
| 77 | /* r0 - r31, cel, ceh, sr0, sr1, sr2, epc, ema, psr, ecr, condition */ | ||
| 78 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
| 79 | regs->regs, | ||
| 80 | offsetof(struct pt_regs, regs), | ||
| 81 | offsetof(struct pt_regs, cp0_condition)); | ||
| 82 | |||
| 83 | if (!ret) | ||
| 84 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 85 | sizeof(struct pt_regs), -1); | ||
| 86 | |||
| 87 | return ret; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Define the register sets available on the score7 under Linux | ||
| 92 | */ | ||
| 93 | enum score7_regset { | ||
| 94 | REGSET_GENERAL, | ||
| 95 | }; | ||
| 96 | |||
| 97 | static const struct user_regset score7_regsets[] = { | ||
| 98 | [REGSET_GENERAL] = { | ||
| 99 | .core_note_type = NT_PRSTATUS, | ||
| 100 | .n = ELF_NGREG, | ||
| 101 | .size = sizeof(long), | ||
| 102 | .align = sizeof(long), | ||
| 103 | .get = genregs_get, | ||
| 104 | .set = genregs_set, | ||
| 105 | }, | ||
| 106 | }; | ||
| 107 | |||
| 108 | static const struct user_regset_view user_score_native_view = { | ||
| 109 | .name = "score7", | ||
| 110 | .e_machine = EM_SCORE7, | ||
| 111 | .regsets = score7_regsets, | ||
| 112 | .n = ARRAY_SIZE(score7_regsets), | ||
| 113 | }; | ||
| 114 | |||
| 115 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
| 116 | { | ||
| 117 | return &user_score_native_view; | ||
| 118 | } | ||
| 119 | |||
| 31 | static int is_16bitinsn(unsigned long insn) | 120 | static int is_16bitinsn(unsigned long insn) |
| 32 | { | 121 | { |
| 33 | if ((insn & INSN32_MASK) == INSN32_MASK) | 122 | if ((insn & INSN32_MASK) == INSN32_MASK) |
| @@ -80,34 +169,6 @@ write_tsk_long(struct task_struct *child, | |||
| 80 | return copied != sizeof(val) ? -EIO : 0; | 169 | return copied != sizeof(val) ? -EIO : 0; |
| 81 | } | 170 | } |
| 82 | 171 | ||
| 83 | /* | ||
| 84 | * Get all user integer registers. | ||
| 85 | */ | ||
| 86 | static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) | ||
| 87 | { | ||
| 88 | struct pt_regs *regs = task_pt_regs(tsk); | ||
| 89 | |||
| 90 | return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* | ||
| 94 | * Set all user integer registers. | ||
| 95 | */ | ||
| 96 | static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) | ||
| 97 | { | ||
| 98 | struct pt_regs newregs; | ||
| 99 | int ret; | ||
| 100 | |||
| 101 | ret = -EFAULT; | ||
| 102 | if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { | ||
| 103 | struct pt_regs *regs = task_pt_regs(tsk); | ||
| 104 | *regs = newregs; | ||
| 105 | ret = 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | |||
| 111 | void user_enable_single_step(struct task_struct *child) | 172 | void user_enable_single_step(struct task_struct *child) |
| 112 | { | 173 | { |
| 113 | /* far_epc is the target of branch */ | 174 | /* far_epc is the target of branch */ |
| @@ -270,97 +331,18 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 270 | unsigned long __user *datap = (void __user *)data; | 331 | unsigned long __user *datap = (void __user *)data; |
| 271 | 332 | ||
| 272 | switch (request) { | 333 | switch (request) { |
| 273 | /* Read the word at location addr in the USER area. */ | ||
| 274 | case PTRACE_PEEKUSR: { | ||
| 275 | struct pt_regs *regs; | ||
| 276 | unsigned long tmp; | ||
| 277 | |||
| 278 | regs = task_pt_regs(child); | ||
| 279 | |||
| 280 | tmp = 0; /* Default return value. */ | ||
| 281 | switch (addr) { | ||
| 282 | case 0 ... 31: | ||
| 283 | tmp = regs->regs[addr]; | ||
| 284 | break; | ||
| 285 | case PC: | ||
| 286 | tmp = regs->cp0_epc; | ||
| 287 | break; | ||
| 288 | case ECR: | ||
| 289 | tmp = regs->cp0_ecr; | ||
| 290 | break; | ||
| 291 | case EMA: | ||
| 292 | tmp = regs->cp0_ema; | ||
| 293 | break; | ||
| 294 | case CEH: | ||
| 295 | tmp = regs->ceh; | ||
| 296 | break; | ||
| 297 | case CEL: | ||
| 298 | tmp = regs->cel; | ||
| 299 | break; | ||
| 300 | case CONDITION: | ||
| 301 | tmp = regs->cp0_condition; | ||
| 302 | break; | ||
| 303 | case PSR: | ||
| 304 | tmp = regs->cp0_psr; | ||
| 305 | break; | ||
| 306 | case COUNTER: | ||
| 307 | tmp = regs->sr0; | ||
| 308 | break; | ||
| 309 | case LDCR: | ||
| 310 | tmp = regs->sr1; | ||
| 311 | break; | ||
| 312 | case STCR: | ||
| 313 | tmp = regs->sr2; | ||
| 314 | break; | ||
| 315 | default: | ||
| 316 | tmp = 0; | ||
| 317 | return -EIO; | ||
| 318 | } | ||
| 319 | |||
| 320 | ret = put_user(tmp, (unsigned int __user *) datap); | ||
| 321 | return ret; | ||
| 322 | } | ||
| 323 | |||
| 324 | case PTRACE_POKEUSR: { | ||
| 325 | struct pt_regs *regs; | ||
| 326 | ret = 0; | ||
| 327 | regs = task_pt_regs(child); | ||
| 328 | |||
| 329 | switch (addr) { | ||
| 330 | case 0 ... 31: | ||
| 331 | regs->regs[addr] = data; | ||
| 332 | break; | ||
| 333 | case PC: | ||
| 334 | regs->cp0_epc = data; | ||
| 335 | break; | ||
| 336 | case CEH: | ||
| 337 | regs->ceh = data; | ||
| 338 | break; | ||
| 339 | case CEL: | ||
| 340 | regs->cel = data; | ||
| 341 | break; | ||
| 342 | case CONDITION: | ||
| 343 | regs->cp0_condition = data; | ||
| 344 | break; | ||
| 345 | case PSR: | ||
| 346 | case COUNTER: | ||
| 347 | case STCR: | ||
| 348 | case LDCR: | ||
| 349 | break; /* user can't write the reg */ | ||
| 350 | default: | ||
| 351 | /* The rest are not allowed. */ | ||
| 352 | ret = -EIO; | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | break; | ||
| 356 | } | ||
| 357 | |||
| 358 | case PTRACE_GETREGS: | 334 | case PTRACE_GETREGS: |
| 359 | ret = ptrace_getregs(child, (void __user *)datap); | 335 | ret = copy_regset_to_user(child, &user_score_native_view, |
| 336 | REGSET_GENERAL, | ||
| 337 | 0, sizeof(struct pt_regs), | ||
| 338 | (void __user *)datap); | ||
| 360 | break; | 339 | break; |
| 361 | 340 | ||
| 362 | case PTRACE_SETREGS: | 341 | case PTRACE_SETREGS: |
| 363 | ret = ptrace_setregs(child, (void __user *)datap); | 342 | ret = copy_regset_from_user(child, &user_score_native_view, |
| 343 | REGSET_GENERAL, | ||
| 344 | 0, sizeof(struct pt_regs), | ||
| 345 | (const void __user *)datap); | ||
| 364 | break; | 346 | break; |
| 365 | 347 | ||
| 366 | default: | 348 | default: |
