Skip to content

Commit a78ff11

Browse files
Eli Cooperrichardweinberger
authored andcommitted
um: add extended processor state save/restore support
This patch extends save_fp_registers() and restore_fp_registers() to use PTRACE_GETREGSET and PTRACE_SETREGSET with the XSTATE note type, adding support for new processor state extensions between context switches. When the new ptrace requests are unavailable, it falls back to the old PTRACE_GETFPREGS and PTRACE_SETFPREGS methods, which have been renamed to save_i387_registers() and restore_i387_registers(). Now these functions expect *fp_regs to have the space of an _xstate struct. Thus, this also makes ptrace in UML responde to PTRACE_GETFPREGS/_SETFPREG requests with a user_i387_struct (thus independent from HOST_FP_SIZE), and by calling save_i387_registers() and restore_i387_registers() instead of the extended save_fp_registers() and restore_fp_registers() functions. Signed-off-by: Eli Cooper <elicooper@gmx.com>
1 parent b6024b2 commit a78ff11

File tree

6 files changed

+62
-16
lines changed

6 files changed

+62
-16
lines changed

arch/um/include/shared/registers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <sysdep/ptrace.h>
1010
#include <sysdep/archsetjmp.h>
1111

12+
extern int save_i387_registers(int pid, unsigned long *fp_regs);
13+
extern int restore_i387_registers(int pid, unsigned long *fp_regs);
1214
extern int save_fp_registers(int pid, unsigned long *fp_regs);
1315
extern int restore_fp_registers(int pid, unsigned long *fp_regs);
1416
extern int save_fpx_registers(int pid, unsigned long *fp_regs);

arch/um/kernel/process.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,6 @@ int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
402402
{
403403
int cpu = current_thread_info()->cpu;
404404

405-
return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
405+
return save_i387_registers(userspace_pid[cpu], (unsigned long *) fpu);
406406
}
407407

arch/x86/um/os-Linux/registers.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,56 @@
1111
#endif
1212
#include <longjmp.h>
1313
#include <sysdep/ptrace_user.h>
14+
#include <sys/uio.h>
15+
#include <asm/sigcontext.h>
16+
#include <linux/elf.h>
1417

15-
int save_fp_registers(int pid, unsigned long *fp_regs)
18+
int have_xstate_support;
19+
20+
int save_i387_registers(int pid, unsigned long *fp_regs)
1621
{
1722
if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
1823
return -errno;
1924
return 0;
2025
}
2126

22-
int restore_fp_registers(int pid, unsigned long *fp_regs)
27+
int save_fp_registers(int pid, unsigned long *fp_regs)
28+
{
29+
struct iovec iov;
30+
31+
if (have_xstate_support) {
32+
iov.iov_base = fp_regs;
33+
iov.iov_len = sizeof(struct _xstate);
34+
if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
35+
return -errno;
36+
return 0;
37+
} else {
38+
return save_i387_registers(pid, fp_regs);
39+
}
40+
}
41+
42+
int restore_i387_registers(int pid, unsigned long *fp_regs)
2343
{
2444
if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
2545
return -errno;
2646
return 0;
2747
}
2848

49+
int restore_fp_registers(int pid, unsigned long *fp_regs)
50+
{
51+
struct iovec iov;
52+
53+
if (have_xstate_support) {
54+
iov.iov_base = fp_regs;
55+
iov.iov_len = sizeof(struct _xstate);
56+
if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
57+
return -errno;
58+
return 0;
59+
} else {
60+
return restore_i387_registers(pid, fp_regs);
61+
}
62+
}
63+
2964
#ifdef __i386__
3065
int have_fpx_regs = 1;
3166
int save_fpx_registers(int pid, unsigned long *fp_regs)
@@ -85,6 +120,16 @@ int put_fp_registers(int pid, unsigned long *regs)
85120
return restore_fp_registers(pid, regs);
86121
}
87122

123+
void arch_init_registers(int pid)
124+
{
125+
struct _xstate fp_regs;
126+
struct iovec iov;
127+
128+
iov.iov_base = &fp_regs;
129+
iov.iov_len = sizeof(struct _xstate);
130+
if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
131+
have_xstate_support = 1;
132+
}
88133
#endif
89134

90135
unsigned long get_thread_reg(int reg, jmp_buf *buf)

arch/x86/um/ptrace_32.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c
194194
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
195195
struct user_i387_struct fpregs;
196196

197-
err = save_fp_registers(userspace_pid[cpu], (unsigned long *) &fpregs);
197+
err = save_i387_registers(userspace_pid[cpu],
198+
(unsigned long *) &fpregs);
198199
if (err)
199200
return err;
200201

@@ -214,7 +215,7 @@ static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *c
214215
if (n > 0)
215216
return -EFAULT;
216217

217-
return restore_fp_registers(userspace_pid[cpu],
218+
return restore_i387_registers(userspace_pid[cpu],
218219
(unsigned long *) &fpregs);
219220
}
220221

arch/x86/um/ptrace_64.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,14 @@ int is_syscall(unsigned long addr)
222222
static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
223223
{
224224
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
225-
long fpregs[HOST_FP_SIZE];
225+
struct user_i387_struct fpregs;
226226

227-
BUG_ON(sizeof(*buf) != sizeof(fpregs));
228-
err = save_fp_registers(userspace_pid[cpu], fpregs);
227+
err = save_i387_registers(userspace_pid[cpu],
228+
(unsigned long *) &fpregs);
229229
if (err)
230230
return err;
231231

232-
n = copy_to_user(buf, fpregs, sizeof(fpregs));
232+
n = copy_to_user(buf, &fpregs, sizeof(fpregs));
233233
if (n > 0)
234234
return -EFAULT;
235235

@@ -239,14 +239,14 @@ static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *c
239239
static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
240240
{
241241
int n, cpu = ((struct thread_info *) child->stack)->cpu;
242-
long fpregs[HOST_FP_SIZE];
242+
struct user_i387_struct fpregs;
243243

244-
BUG_ON(sizeof(*buf) != sizeof(fpregs));
245-
n = copy_from_user(fpregs, buf, sizeof(fpregs));
244+
n = copy_from_user(&fpregs, buf, sizeof(fpregs));
246245
if (n > 0)
247246
return -EFAULT;
248247

249-
return restore_fp_registers(userspace_pid[cpu], fpregs);
248+
return restore_i387_registers(userspace_pid[cpu],
249+
(unsigned long *) &fpregs);
250250
}
251251

252252
long subarch_ptrace(struct task_struct *child, long request,

arch/x86/um/shared/sysdep/ptrace_64.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@
5757
#define UPT_SYSCALL_ARG5(r) UPT_R8(r)
5858
#define UPT_SYSCALL_ARG6(r) UPT_R9(r)
5959

60-
static inline void arch_init_registers(int pid)
61-
{
62-
}
60+
extern void arch_init_registers(int pid);
6361

6462
#endif

0 commit comments

Comments
 (0)