Merge tag 'for-6.12/block-20240925' of git://git.kernel.dk/linux
[linux-2.6-block.git] / arch / x86 / um / ptrace_32.c
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 }