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