aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2010-02-11 14:50:59 -0500
committerH. Peter Anvin <hpa@zytor.com>2010-02-11 18:08:17 -0500
commit5b3efd500854d45d305b53c54c97db5970959980 (patch)
tree731629e22791d14b9661cada9c0c69eb38776c3b /arch/x86/kernel
parent676ad585531e965416fd958747894541dabcec96 (diff)
x86, ptrace: regset extensions to support xstate
Add the xstate regset support which helps extend the kernel ptrace and the core-dump interfaces to support AVX state etc. This regset interface is designed to support all the future state that gets supported using xsave/xrstor infrastructure. Looking at the memory layout saved by "xsave", one can't say which state is represented in the memory layout. This is because if a particular state is in init state, in the xsave hdr it can be represented by bit '0'. And hence we can't really say by the xsave header wether a state is in init state or the state is not saved in the memory layout. And hence the xsave memory layout available through this regset interface uses SW usable bytes [464..511] to convey what state is represented in the memory layout. First 8 bytes of the sw_usable_bytes[464..467] will be set to OS enabled xstate mask(which is same as the 64bit mask returned by the xgetbv's xCR0). The note NT_X86_XSTATE represents the extended state information in the core file, using the above mentioned memory layout. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> LKML-Reference: <20100211195614.802495327@sbs-t61.sc.intel.com> Signed-off-by: Hongjiu Lu <hjl.tools@gmail.com> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/i387.c83
-rw-r--r--arch/x86/kernel/ptrace.c34
-rw-r--r--arch/x86/kernel/xsave.c1
3 files changed, 116 insertions, 2 deletions
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();