diff options
author | Eli Cooper <elicooper@gmx.com> | 2016-03-19 12:58:41 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2016-05-21 17:38:06 -0400 |
commit | a78ff1112263fdd871d3506dbcff44f6f12e8423 (patch) | |
tree | e57ced8c83977e3686b8a69343cc5541565b8b94 /arch/x86/um/os-Linux | |
parent | b6024b21fec8367ef961a771cc9dde31f1831965 (diff) |
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>
Diffstat (limited to 'arch/x86/um/os-Linux')
-rw-r--r-- | arch/x86/um/os-Linux/registers.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index 41bfe84e11ab..00f54a91bb4b 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c | |||
@@ -11,21 +11,56 @@ | |||
11 | #endif | 11 | #endif |
12 | #include <longjmp.h> | 12 | #include <longjmp.h> |
13 | #include <sysdep/ptrace_user.h> | 13 | #include <sysdep/ptrace_user.h> |
14 | #include <sys/uio.h> | ||
15 | #include <asm/sigcontext.h> | ||
16 | #include <linux/elf.h> | ||
14 | 17 | ||
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) | ||
16 | { | 21 | { |
17 | if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) | 22 | if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) |
18 | return -errno; | 23 | return -errno; |
19 | return 0; | 24 | return 0; |
20 | } | 25 | } |
21 | 26 | ||
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) | ||
23 | { | 43 | { |
24 | if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) | 44 | if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) |
25 | return -errno; | 45 | return -errno; |
26 | return 0; | 46 | return 0; |
27 | } | 47 | } |
28 | 48 | ||
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 | |||
29 | #ifdef __i386__ | 64 | #ifdef __i386__ |
30 | int have_fpx_regs = 1; | 65 | int have_fpx_regs = 1; |
31 | int save_fpx_registers(int pid, unsigned long *fp_regs) | 66 | int save_fpx_registers(int pid, unsigned long *fp_regs) |
@@ -85,6 +120,16 @@ int put_fp_registers(int pid, unsigned long *regs) | |||
85 | return restore_fp_registers(pid, regs); | 120 | return restore_fp_registers(pid, regs); |
86 | } | 121 | } |
87 | 122 | ||
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 | } | ||
88 | #endif | 133 | #endif |
89 | 134 | ||
90 | unsigned long get_thread_reg(int reg, jmp_buf *buf) | 135 | unsigned long get_thread_reg(int reg, jmp_buf *buf) |