1/* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6#include <linux/mm.h> 7#include <linux/sched.h> 8#include <asm/uaccess.h> 9#include <asm/ptrace-abi.h> 10#include <skas.h> 11 12extern int arch_switch_tls(struct task_struct *to); 13 14void arch_switch_to(struct task_struct *to) 15{ 16 int err = arch_switch_tls(to); 17 if (!err) 18 return; 19 20 if (err != -EINVAL) 21 printk(KERN_WARNING "arch_switch_tls failed, errno %d, " 22 "not EINVAL\n", -err); 23 else 24 printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n"); 25} 26 27int is_syscall(unsigned long addr) 28{ 29 unsigned short instr; 30 int n; 31 32 n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); 33 if (n) { 34 /* access_process_vm() grants access to vsyscall and stub, 35 * while copy_from_user doesn't. Maybe access_process_vm is 36 * slow, but that doesn't matter, since it will be called only 37 * in case of singlestepping, if copy_from_user failed. 38 */ 39 n = access_process_vm(current, addr, &instr, sizeof(instr), 0); 40 if (n != sizeof(instr)) { 41 printk(KERN_ERR "is_syscall : failed to read " 42 "instruction from 0x%lx\n", addr); 43 return 1; 44 } 45 } 46 /* int 0x80 or sysenter */ 47 return (instr == 0x80cd) || (instr == 0x340f); 48} 49 50/* determines which flags the user has access to. */ 51/* 1 = access 0 = no access */ 52#define FLAG_MASK 0x00044dd5 53 54static const int reg_offsets[] = { 55 [EBX] = HOST_BX, 56 [ECX] = HOST_CX, 57 [EDX] = HOST_DX, 58 [ESI] = HOST_SI, 59 [EDI] = HOST_DI, 60 [EBP] = HOST_BP, 61 [EAX] = HOST_AX, 62 [DS] = HOST_DS, 63 [ES] = HOST_ES, 64 [FS] = HOST_FS, 65 [GS] = HOST_GS, 66 [EIP] = HOST_IP, 67 [CS] = HOST_CS, 68 [EFL] = HOST_EFLAGS, 69 [UESP] = HOST_SP, 70 [SS] = HOST_SS, 71}; 72 73int putreg(struct task_struct *child, int regno, unsigned long value) 74{ 75 regno >>= 2; 76 switch (regno) { 77 case EBX: 78 case ECX: 79 case EDX: 80 case ESI: 81 case EDI: 82 case EBP: 83 case EAX: 84 case EIP: 85 case UESP: 86 break; 87 case FS: 88 if (value && (value & 3) != 3) 89 return -EIO; 90 break; 91 case GS: 92 if (value && (value & 3) != 3) 93 return -EIO; 94 break; 95 case DS: 96 case ES: 97 if (value && (value & 3) != 3) 98 return -EIO; 99 value &= 0xffff; 100 break; 101 case SS: 102 case CS: 103 if ((value & 3) != 3) 104 return -EIO; 105 value &= 0xffff; 106 break; 107 case EFL: 108 value &= FLAG_MASK; 109 child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 110 return 0; 111 case ORIG_EAX: 112 child->thread.regs.regs.syscall = value; 113 return 0; 114 default : 115 panic("Bad register in putreg() : %d\n", regno); 116 } 117 child->thread.regs.regs.gp[reg_offsets[regno]] = value; 118 return 0; 119} 120 121int poke_user(struct task_struct *child, long addr, long data) 122{ 123 if ((addr & 3) || addr < 0) 124 return -EIO; 125 126 if (addr < MAX_REG_OFFSET) 127 return putreg(child, addr, data); 128 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 129 (addr <= offsetof(struct user, u_debugreg[7]))) { 130 addr -= offsetof(struct user, u_debugreg[0]); 131 addr = addr >> 2; 132 if ((addr == 4) || (addr == 5)) 133 return -EIO; 134 child->thread.arch.debugregs[addr] = data; 135 return 0; 136 } 137 return -EIO; 138} 139 140unsigned long getreg(struct task_struct *child, int regno) 141{ 142 unsigned long mask = ~0UL; 143 144 regno >>= 2; 145 switch (regno) { 146 case ORIG_EAX: 147 return child->thread.regs.regs.syscall; 148 case FS: 149 case GS: 150 case DS: 151 case ES: 152 case SS: 153 case CS: 154 mask = 0xffff; 155 break; 156 case EIP: 157 case UESP: 158 case EAX: 159 case EBX: 160 case ECX: 161 case EDX: 162 case ESI: 163 case EDI: 164 case EBP: 165 case EFL: 166 break; 167 default: 168 panic("Bad register in getreg() : %d\n", regno); 169 } 170 return mask & child->thread.regs.regs.gp[reg_offsets[regno]]; 171} 172 173/* read the word at location addr in the USER area. */ 174int peek_user(struct task_struct *child, long addr, long data) 175{ 176 unsigned long tmp; 177 178 if ((addr & 3) || addr < 0) 179 return -EIO; 180 181 tmp = 0; /* Default return condition */ 182 if (addr < MAX_REG_OFFSET) { 183 tmp = getreg(child, addr); 184 } 185 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 186 (addr <= offsetof(struct user, u_debugreg[7]))) { 187 addr -= offsetof(struct user, u_debugreg[0]); 188 addr = addr >> 2; 189 tmp = child->thread.arch.debugregs[addr]; 190 } 191 return put_user(tmp, (unsigned long __user *) data); 192} 193 194static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 195{ 196 int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 197 struct user_i387_struct fpregs; 198 199 err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs); 200 if (err) 201 return err; 202 203 n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 204 if(n > 0) 205 return -EFAULT; 206 207 return n; 208} 209 210static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 211{ 212 int n, cpu = ((struct thread_info *) child->stack)->cpu; 213 struct user_i387_struct fpregs; 214 215 n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 216 if (n > 0) 217 return -EFAULT; 218 219 return restore_fp_registers(userspace_pid[cpu], 220 (unsigned long *) &fpregs); 221} 222 223static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 224{ 225 int err, n, cpu = ((struct thread_info *) child->stack)->cpu; 226 struct user_fxsr_struct fpregs; 227 228 err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs); 229 if (err) 230 return err; 231 232 n = copy_to_user(buf, &fpregs, sizeof(fpregs)); 233 if(n > 0) 234 return -EFAULT; 235 236 return n; 237} 238 239static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) 240{ 241 int n, cpu = ((struct thread_info *) child->stack)->cpu; 242 struct user_fxsr_struct fpregs; 243 244 n = copy_from_user(&fpregs, buf, sizeof(fpregs)); 245 if (n > 0) 246 return -EFAULT; 247 248 return restore_fpx_registers(userspace_pid[cpu], 249 (unsigned long *) &fpregs); 250} 251 252long subarch_ptrace(struct task_struct *child, long request, 253 unsigned long addr, unsigned long data) 254{ 255 int ret = -EIO; 256 void __user *datap = (void __user *) data; 257 switch (request) { 258 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 259 ret = get_fpregs(datap, child); 260 break; 261 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 262 ret = set_fpregs(datap, child); 263 break; 264 case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 265 ret = get_fpxregs(datap, child); 266 break; 267 case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 268 ret = set_fpxregs(datap, child); 269 break; 270 default: 271 ret = -EIO; 272 } 273 return ret; 274} 275