1/* MN10300 Process tracing 2 * 3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd. 4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 5 * Modified by David Howells (dhowells@redhat.com) 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public Licence 9 * as published by the Free Software Foundation; either version 10 * 2 of the Licence, or (at your option) any later version. 11 */ 12#include <linux/kernel.h> 13#include <linux/sched.h> 14#include <linux/mm.h> 15#include <linux/smp.h> 16#include <linux/errno.h> 17#include <linux/ptrace.h> 18#include <linux/user.h> 19#include <linux/regset.h> 20#include <linux/elf.h> 21#include <linux/tracehook.h> 22#include <asm/uaccess.h> 23#include <asm/pgtable.h> 24#include <asm/processor.h> 25#include <asm/cacheflush.h> 26#include <asm/fpu.h> 27#include <asm/asm-offsets.h> 28 29/* 30 * translate ptrace register IDs into struct pt_regs offsets 31 */ 32static const u8 ptrace_regid_to_frame[] = { 33 [PT_A3 << 2] = REG_A3, 34 [PT_A2 << 2] = REG_A2, 35 [PT_D3 << 2] = REG_D3, 36 [PT_D2 << 2] = REG_D2, 37 [PT_MCVF << 2] = REG_MCVF, 38 [PT_MCRL << 2] = REG_MCRL, 39 [PT_MCRH << 2] = REG_MCRH, 40 [PT_MDRQ << 2] = REG_MDRQ, 41 [PT_E1 << 2] = REG_E1, 42 [PT_E0 << 2] = REG_E0, 43 [PT_E7 << 2] = REG_E7, 44 [PT_E6 << 2] = REG_E6, 45 [PT_E5 << 2] = REG_E5, 46 [PT_E4 << 2] = REG_E4, 47 [PT_E3 << 2] = REG_E3, 48 [PT_E2 << 2] = REG_E2, 49 [PT_SP << 2] = REG_SP, 50 [PT_LAR << 2] = REG_LAR, 51 [PT_LIR << 2] = REG_LIR, 52 [PT_MDR << 2] = REG_MDR, 53 [PT_A1 << 2] = REG_A1, 54 [PT_A0 << 2] = REG_A0, 55 [PT_D1 << 2] = REG_D1, 56 [PT_D0 << 2] = REG_D0, 57 [PT_ORIG_D0 << 2] = REG_ORIG_D0, 58 [PT_EPSW << 2] = REG_EPSW, 59 [PT_PC << 2] = REG_PC, 60}; 61 62static inline int get_stack_long(struct task_struct *task, int offset) 63{ 64 return *(unsigned long *) 65 ((unsigned long) task->thread.uregs + offset); 66} 67 68static inline 69int put_stack_long(struct task_struct *task, int offset, unsigned long data) 70{ 71 unsigned long stack; 72 73 stack = (unsigned long) task->thread.uregs + offset; 74 *(unsigned long *) stack = data; 75 return 0; 76} 77 78/* 79 * retrieve the contents of MN10300 userspace general registers 80 */ 81static int genregs_get(struct task_struct *target, 82 const struct user_regset *regset, 83 unsigned int pos, unsigned int count, 84 void *kbuf, void __user *ubuf) 85{ 86 const struct pt_regs *regs = task_pt_regs(target); 87 int ret; 88 89 /* we need to skip regs->next */ 90 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 91 regs, 0, PT_ORIG_D0 * sizeof(long)); 92 if (ret < 0) 93 return ret; 94 95 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 96 ®s->orig_d0, PT_ORIG_D0 * sizeof(long), 97 NR_PTREGS * sizeof(long)); 98 if (ret < 0) 99 return ret; 100 101 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 102 NR_PTREGS * sizeof(long), -1); 103} 104 105/* 106 * update the contents of the MN10300 userspace general registers 107 */ 108static int genregs_set(struct task_struct *target, 109 const struct user_regset *regset, 110 unsigned int pos, unsigned int count, 111 const void *kbuf, const void __user *ubuf) 112{ 113 struct pt_regs *regs = task_pt_regs(target); 114 unsigned long tmp; 115 int ret; 116 117 /* we need to skip regs->next */ 118 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 119 regs, 0, PT_ORIG_D0 * sizeof(long)); 120 if (ret < 0) 121 return ret; 122 123 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 124 ®s->orig_d0, PT_ORIG_D0 * sizeof(long), 125 PT_EPSW * sizeof(long)); 126 if (ret < 0) 127 return ret; 128 129 /* we need to mask off changes to EPSW */ 130 tmp = regs->epsw; 131 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 132 &tmp, PT_EPSW * sizeof(long), 133 PT_PC * sizeof(long)); 134 tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z; 135 tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | 136 EPSW_FLAG_Z); 137 regs->epsw = tmp; 138 139 if (ret < 0) 140 return ret; 141 142 /* and finally load the PC */ 143 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 144 ®s->pc, PT_PC * sizeof(long), 145 NR_PTREGS * sizeof(long)); 146 147 if (ret < 0) 148 return ret; 149 150 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 151 NR_PTREGS * sizeof(long), -1); 152} 153 154/* 155 * retrieve the contents of MN10300 userspace FPU registers 156 */ 157static int fpuregs_get(struct task_struct *target, 158 const struct user_regset *regset, 159 unsigned int pos, unsigned int count, 160 void *kbuf, void __user *ubuf) 161{ 162 const struct fpu_state_struct *fpregs = &target->thread.fpu_state; 163 int ret; 164 165 unlazy_fpu(target); 166 167 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, 168 fpregs, 0, sizeof(*fpregs)); 169 if (ret < 0) 170 return ret; 171 172 return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, 173 sizeof(*fpregs), -1); 174} 175 176/* 177 * update the contents of the MN10300 userspace FPU registers 178 */ 179static int fpuregs_set(struct task_struct *target, 180 const struct user_regset *regset, 181 unsigned int pos, unsigned int count, 182 const void *kbuf, const void __user *ubuf) 183{ 184 struct fpu_state_struct fpu_state = target->thread.fpu_state; 185 int ret; 186 187 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 188 &fpu_state, 0, sizeof(fpu_state)); 189 if (ret < 0) 190 return ret; 191 192 fpu_kill_state(target); 193 target->thread.fpu_state = fpu_state; 194 set_using_fpu(target); 195 196 return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 197 sizeof(fpu_state), -1); 198} 199 200/* 201 * determine if the FPU registers have actually been used 202 */ 203static int fpuregs_active(struct task_struct *target, 204 const struct user_regset *regset) 205{ 206 return is_using_fpu(target) ? regset->n : 0; 207} 208 209/* 210 * Define the register sets available on the MN10300 under Linux 211 */ 212enum mn10300_regset { 213 REGSET_GENERAL, 214 REGSET_FPU, 215}; 216 217static const struct user_regset mn10300_regsets[] = { 218 /* 219 * General register format is: 220 * A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ 221 * E1, E0, E7...E2, SP, LAR, LIR, MDR 222 * A1, A0, D1, D0, ORIG_D0, EPSW, PC 223 */ 224 [REGSET_GENERAL] = { 225 .core_note_type = NT_PRSTATUS, 226 .n = ELF_NGREG, 227 .size = sizeof(long), 228 .align = sizeof(long), 229 .get = genregs_get, 230 .set = genregs_set, 231 }, 232 /* 233 * FPU register format is: 234 * FS0-31, FPCR 235 */ 236 [REGSET_FPU] = { 237 .core_note_type = NT_PRFPREG, 238 .n = sizeof(struct fpu_state_struct) / sizeof(long), 239 .size = sizeof(long), 240 .align = sizeof(long), 241 .get = fpuregs_get, 242 .set = fpuregs_set, 243 .active = fpuregs_active, 244 }, 245}; 246 247static const struct user_regset_view user_mn10300_native_view = { 248 .name = "mn10300", 249 .e_machine = EM_MN10300, 250 .regsets = mn10300_regsets, 251 .n = ARRAY_SIZE(mn10300_regsets), 252}; 253 254const struct user_regset_view *task_user_regset_view(struct task_struct *task) 255{ 256 return &user_mn10300_native_view; 257} 258 259/* 260 * set the single-step bit 261 */ 262void user_enable_single_step(struct task_struct *child) 263{ 264#ifndef CONFIG_MN10300_USING_JTAG 265 struct user *dummy = NULL; 266 long tmp; 267 268 tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw); 269 tmp |= EPSW_T; 270 put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp); 271#endif 272} 273 274/* 275 * make sure the single-step bit is not set 276 */ 277void user_disable_single_step(struct task_struct *child) 278{ 279#ifndef CONFIG_MN10300_USING_JTAG 280 struct user *dummy = NULL; 281 long tmp; 282 283 tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw); 284 tmp &= ~EPSW_T; 285 put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp); 286#endif 287} 288 289void ptrace_disable(struct task_struct *child) 290{ 291 user_disable_single_step(child); 292} 293 294/* 295 * handle the arch-specific side of process tracing 296 */ 297long arch_ptrace(struct task_struct *child, long request, 298 unsigned long addr, unsigned long data) 299{ 300 unsigned long tmp; 301 int ret; 302 unsigned long __user *datap = (unsigned long __user *) data; 303 304 switch (request) { 305 /* read the word at location addr in the USER area. */ 306 case PTRACE_PEEKUSR: 307 ret = -EIO; 308 if ((addr & 3) || addr > sizeof(struct user) - 3) 309 break; 310 311 tmp = 0; /* Default return condition */ 312 if (addr < NR_PTREGS << 2) 313 tmp = get_stack_long(child, 314 ptrace_regid_to_frame[addr]); 315 ret = put_user(tmp, datap); 316 break; 317 318 /* write the word at location addr in the USER area */ 319 case PTRACE_POKEUSR: 320 ret = -EIO; 321 if ((addr & 3) || addr > sizeof(struct user) - 3) 322 break; 323 324 ret = 0; 325 if (addr < NR_PTREGS << 2) 326 ret = put_stack_long(child, ptrace_regid_to_frame[addr], 327 data); 328 break; 329 330 case PTRACE_GETREGS: /* Get all integer regs from the child. */ 331 return copy_regset_to_user(child, &user_mn10300_native_view, 332 REGSET_GENERAL, 333 0, NR_PTREGS * sizeof(long), 334 datap); 335 336 case PTRACE_SETREGS: /* Set all integer regs in the child. */ 337 return copy_regset_from_user(child, &user_mn10300_native_view, 338 REGSET_GENERAL, 339 0, NR_PTREGS * sizeof(long), 340 datap); 341 342 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 343 return copy_regset_to_user(child, &user_mn10300_native_view, 344 REGSET_FPU, 345 0, sizeof(struct fpu_state_struct), 346 datap); 347 348 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 349 return copy_regset_from_user(child, &user_mn10300_native_view, 350 REGSET_FPU, 351 0, sizeof(struct fpu_state_struct), 352 datap); 353 354 default: 355 ret = ptrace_request(child, request, addr, data); 356 break; 357 } 358 359 return ret; 360} 361 362/* 363 * handle tracing of system call entry 364 * - return the revised system call number or ULONG_MAX to cause ENOSYS 365 */ 366asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs) 367{ 368 if (tracehook_report_syscall_entry(regs)) 369 /* tracing decided this syscall should not happen, so 370 * We'll return a bogus call number to get an ENOSYS 371 * error, but leave the original number in 372 * regs->orig_d0 373 */ 374 return ULONG_MAX; 375 376 return regs->orig_d0; 377} 378 379/* 380 * handle tracing of system call exit 381 */ 382asmlinkage void syscall_trace_exit(struct pt_regs *regs) 383{ 384 tracehook_report_syscall_exit(regs, 0); 385} 386