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