aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/i387.h12
-rw-r--r--arch/x86/include/asm/user.h58
-rw-r--r--arch/x86/include/asm/xsave.h2
-rw-r--r--arch/x86/kernel/i387.c83
-rw-r--r--arch/x86/kernel/ptrace.c34
-rw-r--r--arch/x86/kernel/xsave.c1
-rw-r--r--include/linux/elf.h1
7 files changed, 187 insertions, 4 deletions
diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h
index ebfb8a9e11f7..da2930924501 100644
--- a/arch/x86/include/asm/i387.h
+++ b/arch/x86/include/asm/i387.h
@@ -33,8 +33,16 @@ extern void init_thread_xstate(void);
33extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); 33extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
34 34
35extern user_regset_active_fn fpregs_active, xfpregs_active; 35extern user_regset_active_fn fpregs_active, xfpregs_active;
36extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; 36extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
37extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; 37 xstateregs_get;
38extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
39 xstateregs_set;
40
41/*
42 * xstateregs_active == fpregs_active. Please refer to the comment
43 * at the definition of fpregs_active.
44 */
45#define xstateregs_active fpregs_active
38 46
39extern struct _fpx_sw_bytes fx_sw_reserved; 47extern struct _fpx_sw_bytes fx_sw_reserved;
40#ifdef CONFIG_IA32_EMULATION 48#ifdef CONFIG_IA32_EMULATION
diff --git a/arch/x86/include/asm/user.h b/arch/x86/include/asm/user.h
index 999873b22e7f..24532c7da3d6 100644
--- a/arch/x86/include/asm/user.h
+++ b/arch/x86/include/asm/user.h
@@ -1,5 +1,63 @@
1#ifndef _ASM_X86_USER_H
2#define _ASM_X86_USER_H
3
1#ifdef CONFIG_X86_32 4#ifdef CONFIG_X86_32
2# include "user_32.h" 5# include "user_32.h"
3#else 6#else
4# include "user_64.h" 7# include "user_64.h"
5#endif 8#endif
9
10#include <asm/types.h>
11
12struct user_ymmh_regs {
13 /* 16 * 16 bytes for each YMMH-reg */
14 __u32 ymmh_space[64];
15};
16
17struct user_xsave_hdr {
18 __u64 xstate_bv;
19 __u64 reserved1[2];
20 __u64 reserved2[5];
21};
22
23/*
24 * The structure layout of user_xstateregs, used for exporting the
25 * extended register state through ptrace and core-dump (NT_X86_XSTATE note)
26 * interfaces will be same as the memory layout of xsave used by the processor
27 * (except for the bytes 464..511, which can be used by the software) and hence
28 * the size of this structure varies depending on the features supported by the
29 * processor and OS. The size of the structure that users need to use can be
30 * obtained by doing:
31 * cpuid_count(0xd, 0, &eax, &ptrace_xstateregs_struct_size, &ecx, &edx);
32 * i.e., cpuid.(eax=0xd,ecx=0).ebx will be the size that user (debuggers, etc.)
33 * need to use.
34 *
35 * For now, only the first 8 bytes of the software usable bytes[464..471] will
36 * be used and will be set to OS enabled xstate mask (which is same as the
37 * 64bit mask returned by the xgetbv's xCR0). Users (analyzing core dump
38 * remotely, etc.) can use this mask as well as the mask saved in the
39 * xstate_hdr bytes and interpret what states the processor/OS supports
40 * and what states are in modified/initialized conditions for the
41 * particular process/thread.
42 *
43 * Also when the user modifies certain state FP/SSE/etc through the
44 * ptrace interface, they must ensure that the xsave_hdr.xstate_bv
45 * bytes[512..519] of the memory layout are updated correspondingly.
46 * i.e., for example when FP state is modified to a non-init state,
47 * xsave_hdr.xstate_bv's bit 0 must be set to '1', when SSE is modified to
48 * non-init state, xsave_hdr.xstate_bv's bit 1 must to be set to '1', etc.
49 */
50#define USER_XSTATE_FX_SW_WORDS 6
51#define USER_XSTATE_XCR0_WORD 0
52
53struct user_xstateregs {
54 struct {
55 __u64 fpx_space[58];
56 __u64 xstate_fx_sw[USER_XSTATE_FX_SW_WORDS];
57 } i387;
58 struct user_xsave_hdr xsave_hdr;
59 struct user_ymmh_regs ymmh;
60 /* further processor state extensions go here */
61};
62
63#endif /* _ASM_X86_USER_H */
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 727acc152344..ddc04ccad03b 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -27,9 +27,11 @@
27extern unsigned int xstate_size; 27extern unsigned int xstate_size;
28extern u64 pcntxt_mask; 28extern u64 pcntxt_mask;
29extern struct xsave_struct *init_xstate_buf; 29extern struct xsave_struct *init_xstate_buf;
30extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
30 31
31extern void xsave_cntxt_init(void); 32extern void xsave_cntxt_init(void);
32extern void xsave_init(void); 33extern void xsave_init(void);
34extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
33extern int init_fpu(struct task_struct *child); 35extern int init_fpu(struct task_struct *child);
34extern int check_for_xstate(struct i387_fxsave_struct __user *buf, 36extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
35 void __user *fpstate, 37 void __user *fpstate,
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index f2f8540a7f3d..7a8a193b5144 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -164,6 +164,11 @@ int init_fpu(struct task_struct *tsk)
164 return 0; 164 return 0;
165} 165}
166 166
167/*
168 * The xstateregs_active() routine is the same as the fpregs_active() routine,
169 * as the "regset->n" for the xstate regset will be updated based on the feature
170 * capabilites supported by the xsave.
171 */
167int fpregs_active(struct task_struct *target, const struct user_regset *regset) 172int fpregs_active(struct task_struct *target, const struct user_regset *regset)
168{ 173{
169 return tsk_used_math(target) ? regset->n : 0; 174 return tsk_used_math(target) ? regset->n : 0;
@@ -224,6 +229,84 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
224 return ret; 229 return ret;
225} 230}
226 231
232int xstateregs_get(struct task_struct *target, const struct user_regset *regset,
233 unsigned int pos, unsigned int count,
234 void *kbuf, void __user *ubuf)
235{
236 int ret;
237
238 if (!cpu_has_xsave)
239 return -ENODEV;
240
241 ret = init_fpu(target);
242 if (ret)
243 return ret;
244
245 /*
246 * First copy the fxsave bytes 0..463.
247 */
248 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
249 &target->thread.xstate->xsave, 0,
250 offsetof(struct user_xstateregs,
251 i387.xstate_fx_sw));
252 if (ret)
253 return ret;
254
255 /*
256 * Copy the 48bytes defined by software.
257 */
258 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
259 xstate_fx_sw_bytes,
260 offsetof(struct user_xstateregs,
261 i387.xstate_fx_sw),
262 offsetof(struct user_xstateregs,
263 xsave_hdr));
264 if (ret)
265 return ret;
266
267 /*
268 * Copy the rest of xstate memory layout.
269 */
270 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
271 &target->thread.xstate->xsave.xsave_hdr,
272 offsetof(struct user_xstateregs,
273 xsave_hdr), -1);
274 return ret;
275}
276
277int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
278 unsigned int pos, unsigned int count,
279 const void *kbuf, const void __user *ubuf)
280{
281 int ret;
282 struct xsave_hdr_struct *xsave_hdr;
283
284 if (!cpu_has_xsave)
285 return -ENODEV;
286
287 ret = init_fpu(target);
288 if (ret)
289 return ret;
290
291 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
292 &target->thread.xstate->xsave, 0, -1);
293
294 /*
295 * mxcsr reserved bits must be masked to zero for security reasons.
296 */
297 target->thread.xstate->fxsave.mxcsr &= mxcsr_feature_mask;
298
299 xsave_hdr = &target->thread.xstate->xsave.xsave_hdr;
300
301 xsave_hdr->xstate_bv &= pcntxt_mask;
302 /*
303 * These bits must be zero.
304 */
305 xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
306
307 return ret;
308}
309
227#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 310#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
228 311
229/* 312/*
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 017d937639fe..16433a59b396 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -48,6 +48,7 @@ enum x86_regset {
48 REGSET_FP, 48 REGSET_FP,
49 REGSET_XFP, 49 REGSET_XFP,
50 REGSET_IOPERM64 = REGSET_XFP, 50 REGSET_IOPERM64 = REGSET_XFP,
51 REGSET_XSTATE,
51 REGSET_TLS, 52 REGSET_TLS,
52 REGSET_IOPERM32, 53 REGSET_IOPERM32,
53}; 54};
@@ -1584,7 +1585,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
1584 1585
1585#ifdef CONFIG_X86_64 1586#ifdef CONFIG_X86_64
1586 1587
1587static const struct user_regset x86_64_regsets[] = { 1588static struct user_regset x86_64_regsets[] __read_mostly = {
1588 [REGSET_GENERAL] = { 1589 [REGSET_GENERAL] = {
1589 .core_note_type = NT_PRSTATUS, 1590 .core_note_type = NT_PRSTATUS,
1590 .n = sizeof(struct user_regs_struct) / sizeof(long), 1591 .n = sizeof(struct user_regs_struct) / sizeof(long),
@@ -1597,6 +1598,12 @@ static const struct user_regset x86_64_regsets[] = {
1597 .size = sizeof(long), .align = sizeof(long), 1598 .size = sizeof(long), .align = sizeof(long),
1598 .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set 1599 .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
1599 }, 1600 },
1601 [REGSET_XSTATE] = {
1602 .core_note_type = NT_X86_XSTATE,
1603 .size = sizeof(u64), .align = sizeof(u64),
1604 .active = xstateregs_active, .get = xstateregs_get,
1605 .set = xstateregs_set
1606 },
1600 [REGSET_IOPERM64] = { 1607 [REGSET_IOPERM64] = {
1601 .core_note_type = NT_386_IOPERM, 1608 .core_note_type = NT_386_IOPERM,
1602 .n = IO_BITMAP_LONGS, 1609 .n = IO_BITMAP_LONGS,
@@ -1622,7 +1629,7 @@ static const struct user_regset_view user_x86_64_view = {
1622#endif /* CONFIG_X86_64 */ 1629#endif /* CONFIG_X86_64 */
1623 1630
1624#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 1631#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
1625static const struct user_regset x86_32_regsets[] = { 1632static struct user_regset x86_32_regsets[] __read_mostly = {
1626 [REGSET_GENERAL] = { 1633 [REGSET_GENERAL] = {
1627 .core_note_type = NT_PRSTATUS, 1634 .core_note_type = NT_PRSTATUS,
1628 .n = sizeof(struct user_regs_struct32) / sizeof(u32), 1635 .n = sizeof(struct user_regs_struct32) / sizeof(u32),
@@ -1641,6 +1648,12 @@ static const struct user_regset x86_32_regsets[] = {
1641 .size = sizeof(u32), .align = sizeof(u32), 1648 .size = sizeof(u32), .align = sizeof(u32),
1642 .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set 1649 .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
1643 }, 1650 },
1651 [REGSET_XSTATE] = {
1652 .core_note_type = NT_X86_XSTATE,
1653 .size = sizeof(u64), .align = sizeof(u64),
1654 .active = xstateregs_active, .get = xstateregs_get,
1655 .set = xstateregs_set
1656 },
1644 [REGSET_TLS] = { 1657 [REGSET_TLS] = {
1645 .core_note_type = NT_386_TLS, 1658 .core_note_type = NT_386_TLS,
1646 .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN, 1659 .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN,
@@ -1663,6 +1676,23 @@ static const struct user_regset_view user_x86_32_view = {
1663}; 1676};
1664#endif 1677#endif
1665 1678
1679/*
1680 * This represents bytes 464..511 in the memory layout exported through
1681 * the REGSET_XSTATE interface.
1682 */
1683u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
1684
1685void update_regset_xstate_info(unsigned int size, u64 xstate_mask)
1686{
1687#ifdef CONFIG_X86_64
1688 x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64);
1689#endif
1690#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
1691 x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64);
1692#endif
1693 xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask;
1694}
1695
1666const struct user_regset_view *task_user_regset_view(struct task_struct *task) 1696const struct user_regset_view *task_user_regset_view(struct task_struct *task)
1667{ 1697{
1668#ifdef CONFIG_IA32_EMULATION 1698#ifdef CONFIG_IA32_EMULATION
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index c5ee17e8c6d9..782c3a362ec6 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -337,6 +337,7 @@ void __ref xsave_cntxt_init(void)
337 cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx); 337 cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
338 xstate_size = ebx; 338 xstate_size = ebx;
339 339
340 update_regset_xstate_info(xstate_size, pcntxt_mask);
340 prepare_fx_sw_frame(); 341 prepare_fx_sw_frame();
341 342
342 setup_xstate_init(); 343 setup_xstate_init();
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 0cc4d55151b7..a8c4af073ce9 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -361,6 +361,7 @@ typedef struct elf64_shdr {
361#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ 361#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
362#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ 362#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
363#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ 363#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
364#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
364#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ 365#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
365 366
366 367