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 <linux/regset.h> 10 #include <asm/ptrace-abi.h> 11 #include <registers.h> 12 #include <skas.h> 13 14 void 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 27 /* determines which flags the user has access to. */ 28 /* 1 = access 0 = no access */ 29 #define FLAG_MASK 0x00044dd5 30 31 static const int reg_offsets[] = { 32 [EBX] = HOST_BX, 33 [ECX] = HOST_CX, 34 [EDX] = HOST_DX, 35 [ESI] = HOST_SI, 36 [EDI] = HOST_DI, 37 [EBP] = HOST_BP, 38 [EAX] = HOST_AX, 39 [DS] = HOST_DS, 40 [ES] = HOST_ES, 41 [FS] = HOST_FS, 42 [GS] = HOST_GS, 43 [EIP] = HOST_IP, 44 [CS] = HOST_CS, 45 [EFL] = HOST_EFLAGS, 46 [UESP] = HOST_SP, 47 [SS] = HOST_SS, 48 [ORIG_EAX] = HOST_ORIG_AX, 49 }; 50 51 int putreg(struct task_struct *child, int regno, unsigned long value) 52 { 53 regno >>= 2; 54 switch (regno) { 55 case EBX: 56 case ECX: 57 case EDX: 58 case ESI: 59 case EDI: 60 case EBP: 61 case EAX: 62 case EIP: 63 case UESP: 64 break; 65 case ORIG_EAX: 66 /* Update the syscall number. */ 67 UPT_SYSCALL_NR(&child->thread.regs.regs) = value; 68 break; 69 case FS: 70 if (value && (value & 3) != 3) 71 return -EIO; 72 break; 73 case GS: 74 if (value && (value & 3) != 3) 75 return -EIO; 76 break; 77 case DS: 78 case ES: 79 if (value && (value & 3) != 3) 80 return -EIO; 81 value &= 0xffff; 82 break; 83 case SS: 84 case CS: 85 if ((value & 3) != 3) 86 return -EIO; 87 value &= 0xffff; 88 break; 89 case EFL: 90 value &= FLAG_MASK; 91 child->thread.regs.regs.gp[HOST_EFLAGS] |= value; 92 return 0; 93 default : 94 panic("Bad register in putreg() : %d\n", regno); 95 } 96 child->thread.regs.regs.gp[reg_offsets[regno]] = value; 97 return 0; 98 } 99 100 int poke_user(struct task_struct *child, long addr, long data) 101 { 102 if ((addr & 3) || addr < 0) 103 return -EIO; 104 105 if (addr < MAX_REG_OFFSET) 106 return putreg(child, addr, data); 107 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 108 (addr <= offsetof(struct user, u_debugreg[7]))) { 109 addr -= offsetof(struct user, u_debugreg[0]); 110 addr = addr >> 2; 111 if ((addr == 4) || (addr == 5)) 112 return -EIO; 113 child->thread.arch.debugregs[addr] = data; 114 return 0; 115 } 116 return -EIO; 117 } 118 119 unsigned long getreg(struct task_struct *child, int regno) 120 { 121 unsigned long mask = ~0UL; 122 123 regno >>= 2; 124 switch (regno) { 125 case FS: 126 case GS: 127 case DS: 128 case ES: 129 case SS: 130 case CS: 131 mask = 0xffff; 132 break; 133 case EIP: 134 case UESP: 135 case EAX: 136 case EBX: 137 case ECX: 138 case EDX: 139 case ESI: 140 case EDI: 141 case EBP: 142 case EFL: 143 case ORIG_EAX: 144 break; 145 default: 146 panic("Bad register in getreg() : %d\n", regno); 147 } 148 return mask & child->thread.regs.regs.gp[reg_offsets[regno]]; 149 } 150 151 /* read the word at location addr in the USER area. */ 152 int peek_user(struct task_struct *child, long addr, long data) 153 { 154 unsigned long tmp; 155 156 if ((addr & 3) || addr < 0) 157 return -EIO; 158 159 tmp = 0; /* Default return condition */ 160 if (addr < MAX_REG_OFFSET) { 161 tmp = getreg(child, addr); 162 } 163 else if ((addr >= offsetof(struct user, u_debugreg[0])) && 164 (addr <= offsetof(struct user, u_debugreg[7]))) { 165 addr -= offsetof(struct user, u_debugreg[0]); 166 addr = addr >> 2; 167 tmp = child->thread.arch.debugregs[addr]; 168 } 169 return put_user(tmp, (unsigned long __user *) data); 170 } 171 172 long subarch_ptrace(struct task_struct *child, long request, 173 unsigned long addr, unsigned long data) 174 { 175 int ret = -EIO; 176 void __user *datap = (void __user *) data; 177 switch (request) { 178 case PTRACE_GETFPREGS: /* Get the child FPU state. */ 179 return copy_regset_to_user(child, task_user_regset_view(child), 180 REGSET_FP_LEGACY, 181 0, sizeof(struct user_i387_struct), 182 datap); 183 case PTRACE_SETFPREGS: /* Set the child FPU state. */ 184 return copy_regset_from_user(child, task_user_regset_view(child), 185 REGSET_FP_LEGACY, 186 0, sizeof(struct user_i387_struct), 187 datap); 188 case PTRACE_GETFPXREGS: /* Get the child FPU state. */ 189 return copy_regset_to_user(child, task_user_regset_view(child), 190 REGSET_FP, 191 0, sizeof(struct user_fxsr_struct), 192 datap); 193 case PTRACE_SETFPXREGS: /* Set the child FPU state. */ 194 return copy_regset_from_user(child, task_user_regset_view(child), 195 REGSET_FP, 196 0, sizeof(struct user_fxsr_struct), 197 datap); 198 default: 199 ret = -EIO; 200 } 201 return ret; 202 } 203