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