1/* 2 * Port on Texas Instruments TMS320C6x architecture 3 * 4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated 5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) 6 * 7 * Updated for 2.6.34: Mark Salter <msalter@redhat.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13#include <linux/ptrace.h> 14#include <linux/tracehook.h> 15#include <linux/regset.h> 16#include <linux/elf.h> 17 18#include <asm/cacheflush.h> 19 20#define PT_REG_SIZE (sizeof(struct pt_regs)) 21 22/* 23 * Called by kernel/ptrace.c when detaching. 24 */ 25void ptrace_disable(struct task_struct *child) 26{ 27 /* nothing to do */ 28} 29 30/* 31 * Get a register number from live pt_regs for the specified task. 32 */ 33static inline long get_reg(struct task_struct *task, int regno) 34{ 35 long *addr = (long *)task_pt_regs(task); 36 37 if (regno == PT_TSR || regno == PT_CSR) 38 return 0; 39 40 return addr[regno]; 41} 42 43/* 44 * Write contents of register REGNO in task TASK. 45 */ 46static inline int put_reg(struct task_struct *task, 47 int regno, 48 unsigned long data) 49{ 50 unsigned long *addr = (unsigned long *)task_pt_regs(task); 51 52 if (regno != PT_TSR && regno != PT_CSR) 53 addr[regno] = data; 54 55 return 0; 56} 57 58/* regset get/set implementations */ 59 60static int gpr_get(struct task_struct *target, 61 const struct user_regset *regset, 62 unsigned int pos, unsigned int count, 63 void *kbuf, void __user *ubuf) 64{ 65 struct pt_regs *regs = task_pt_regs(target); 66 67 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 68 regs, 69 0, sizeof(*regs)); 70} 71 72static int gpr_set(struct task_struct *target, 73 const struct user_regset *regset, 74 unsigned int pos, unsigned int count, 75 const void *kbuf, const void __user *ubuf) 76{ 77 int ret; 78 struct pt_regs *regs = task_pt_regs(target); 79 80 /* Don't copyin TSR or CSR */ 81 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 82 ®s, 83 0, PT_TSR * sizeof(long)); 84 if (ret) 85 return ret; 86 87 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 88 PT_TSR * sizeof(long), 89 (PT_TSR + 1) * sizeof(long)); 90 if (ret) 91 return ret; 92 93 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 94 ®s, 95 (PT_TSR + 1) * sizeof(long), 96 PT_CSR * sizeof(long)); 97 if (ret) 98 return ret; 99 100 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 101 PT_CSR * sizeof(long), 102 (PT_CSR + 1) * sizeof(long)); 103 if (ret) 104 return ret; 105 106 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 107 ®s, 108 (PT_CSR + 1) * sizeof(long), -1); 109 return ret; 110} 111 112enum c6x_regset { 113 REGSET_GPR, 114}; 115 116static const struct user_regset c6x_regsets[] = { 117 [REGSET_GPR] = { 118 .core_note_type = NT_PRSTATUS, 119 .n = ELF_NGREG, 120 .size = sizeof(u32), 121 .align = sizeof(u32), 122 .get = gpr_get, 123 .set = gpr_set 124 }, 125}; 126 127static const struct user_regset_view user_c6x_native_view = { 128 .name = "tic6x", 129 .e_machine = EM_TI_C6000, 130 .regsets = c6x_regsets, 131 .n = ARRAY_SIZE(c6x_regsets), 132}; 133 134const struct user_regset_view *task_user_regset_view(struct task_struct *task) 135{ 136 return &user_c6x_native_view; 137} 138 139/* 140 * Perform ptrace request 141 */ 142long arch_ptrace(struct task_struct *child, long request, 143 unsigned long addr, unsigned long data) 144{ 145 int ret = 0; 146 147 switch (request) { 148 /* 149 * write the word at location addr. 150 */ 151 case PTRACE_POKETEXT: 152 ret = generic_ptrace_pokedata(child, addr, data); 153 if (ret == 0 && request == PTRACE_POKETEXT) 154 flush_icache_range(addr, addr + 4); 155 break; 156 default: 157 ret = ptrace_request(child, request, addr, data); 158 break; 159 } 160 161 return ret; 162} 163 164/* 165 * handle tracing of system call entry 166 * - return the revised system call number or ULONG_MAX to cause ENOSYS 167 */ 168asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs) 169{ 170 if (tracehook_report_syscall_entry(regs)) 171 /* tracing decided this syscall should not happen, so 172 * We'll return a bogus call number to get an ENOSYS 173 * error, but leave the original number in 174 * regs->orig_a4 175 */ 176 return ULONG_MAX; 177 178 return regs->b0; 179} 180 181/* 182 * handle tracing of system call exit 183 */ 184asmlinkage void syscall_trace_exit(struct pt_regs *regs) 185{ 186 tracehook_report_syscall_exit(regs, 0); 187} 188