x86: xsave/xrstor support, ucontext_t extensions
RFC 1/1 x86: xsave/xrstor support, ucontext_t extensions
hi,
Appended patch adds the support for xsave/xrstor infrastructure for x86. xsave/xrstor manages the existing and future processor extended states in x86 architecutre.
More info on xsave/xrstor can be found in the Intel SDM's located at
http://www.intel.com/products/processor/manuals/index.htm
Please let me know your feedback and comments. Specifically, I am not sure if I break anything or make anyone's life harder with the ucontext_t extensions that are proposed in the patch.
Similar to fpstate, xsave state need to be saved/restored across signals. x86 sigcontext doesn't seem to have any unused space, while x86_64 has some unused space(reserved1[8]) in sigcontext.
To keep it consistent across 32bit and 64bit, ucontext is extended with the new state context. Please review and let me know if you foresee any compatibility or other issues with these extensions.
BTW, Traditionally glibc has this definition for struct ucontext.
/* Userlevel context. */
typedef struct ucontext
{
unsigned long int uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
__sigset_t uc_sigmask;
struct _libc_fpstate __fpregs_mem; } ucontext_t;
And application uses the same structure for get/setcontext() routines and to refer process context in signal handler routines.
Kernel which sets up the signal handling context has this definition:
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask;
};Though the kernel Vs user ucontext look somewhat similar, kernel's ucontext struct is different from glibc's ucontext struct because of sigset_t size differences between user Vs kernel. So fpstate in signal handlers must always be referred through the pointer in sigcontext, and not directly through __fpregs_mem in userlevels ucontext struct.
glibc perhaps need to use different context structures, one for get/setcontext() and another for signal handling? Signal handling context will be governed by the kernel and context info referred by get/setcontext() will be governed by glibc. This is specfically needed if glibc's get/setcontext() want to play with xsave info aswell.
This kernel patch is adding a pointer to ucontext for representing xsave context (size of this area will be determined by the processor and kernel capabilities). If at some point, this state need to be saved/restored by get/setcontext() glibc routines and if they want to support application usage like:
ucontext_t context;
void save()
{
getcontext(&context);
}void restore()
{
setcontext(&context);
}then, context information used by get/setcontext() need to evolve independently from the signal handler context information provided by the kernel.
Comments?
thanks,
suresh
---
[RFC] x86: xsave/xrstor support
The layout of the xsave/xrstor area extends from the 512-byte FXSAVE/FXRSTOR layout. xsave/xrstor area layout consists of:
- fxsave/fxrstor area (512 bytes)
- xsave header area (64 bytes)
- set of save areas, each corresponding to a processor extended state
The number of save areas, the offset and the size of each save area is enumerated by CPUID leaf function 0xd.
This patch includes the basic xsave/xrstor infrastructure, which includes:
- context switch support, extending traditional lazy restore mechanism
- signal handling support, extending ucontext_t
---
arch/x86/kernel/xsave.c new file +272 -0
@@ -0,0 +1,272 @@ +/* +* xsave/xrstor support. +* +* Suresh Siddha <[email protected]> +*/ +#include <linux/bootmem.h> +#include <linux/compat.h> +#include <asm/i387.h> + +#ifdef CONFIG_X86_64 +#include <asm/sigcontext32.h> +#endif + +unsigned int pcntxt_hmask, pcntxt_lmask; +struct xsave_struct *init_xstate_buf; + +#ifdef CONFIG_X86_64 +/* +* Signal frame handlers. +*/ +int save_i387_xstate (void __user *buf) +{ +struct task_struct *tsk = current; +int err =0 ; + +if ((unsigned long )buf %64 ) +printk ("save_i387_xstate: bad xstate %p\n" , buf); + +clear_used_math ();/* trigger finit */ +if (task_thread_info (tsk)->status &TS_USEDFPU ) { +if (cpu_has_xsave) + err =save_xstate_checking (buf); +else + err =save_i387_checking (buf); + +if (err) +return err; + +task_thread_info (tsk)->status &= ~TS_USEDFPU ; +stts (); + }else { +if (__copy_to_user (buf, &tsk->thread.xstate->fxsave, + xstate_size)) +return -1 ; + } + +return 0 ; +} + +/* +* This restores directly out of user space. Exceptions are handled. +*/ +int restore_i387_xstate (struct _fpstate __user *buf, +struct xstate_cntxt __user *buf1) +{ +int err =0 ; +int size =0 ; +unsigned int lmask =0 , hmask =0 ; +struct _xstate __user *xstate =0 ; + +if (cpu_has_xsave) { +__get_user (size, &buf1->size); +__get_user (lmask, &buf1->lmask); +__get_user (hmask, &buf1->hmask); +__get_user (xstate, &buf1->xstate); + } + +if (!buf && !xstate) + goto init_state; + +set_used_math (); +if (!(task_thread_info (current)->status &TS_USEDFPU )) { +clts (); +task_thread_info (current)->status |=TS_USEDFPU ; + } + +if (xstate) { + err =xrestore_checking ((struct xsave_struct *) xstate, size, + lmask, hmask); +if (err) + goto init_state; +/* +* initialize the other extended state that the kernel +* knows and not specifed in the user restore masks. +*/ +init_xstate (pcntxt_lmask & ~(XSTATE_FPSSE | lmask), + pcntxt_hmask & ~hmask); + }else +init_xstate (pcntxt_lmask & ~XSTATE_FPSSE , pcntxt_hmask); + +if (buf) { +if (!access_ok (VERIFY_READ , buf,sizeof (*buf))) { + err =-1 ; + goto init_state; + } + + err =restore_fpu_checking (buf); +if (err) + goto init_state; + }else +init_xstate (XSTATE_FPSSE ,0 ); + +if (!err) +return 0 ; + +init_state: +if (used_math ()) { +clear_fpu (current); +clear_used_math (); + } + +return err; +} +#endif + +#ifndef CONFIG_X86_64 +# define _fpstate_ia32 _fpstate +# define xstate_cntxt_ia32 xstate_cntxt +#endif + +/* +* FP and extended context restore during signal return. Extended state is +* restored directly from user space. Exceptions are handled. +*/ +int restore_user_xstate (struct _fpstate_ia32 __user *buf, +struct xstate_cntxt_ia32 __user *buf1) +{ +int err =0 ; +struct task_struct *tsk = current; +int size =0 , lmask =0 , hmask =0 ; +struct _xstate *xstate; + +if (!buf && !buf1) + goto init_state; + +set_used_math (); +if (!(task_thread_info (current)->status &TS_USEDFPU )) { +clts (); +task_thread_info (current)->status |=TS_USEDFPU ; + } + +__get_user (size, &buf1->size); +__get_user (lmask, &buf1->lmask); +__get_user (hmask, &buf1->hmask); + +#ifdef CONFIG_IA32_EMULATION + { +u32 tmp; +__get_user (tmp, &buf1->xstate); + xstate =compat_ptr (tmp); + } +#else +__get_user (xstate, &buf1->xstate); +#endif + +if (xstate) { +/* +* Restore directly from the user space and handle the possible +* exception. This way, we don't have to do manual error +* checking on the user buffer contents. +*/ + err =xrestore_checking ((__force struct xsave_struct *) xstate, + size, lmask, hmask); +if (err) +return err; +/* +* initialize the other extended state that the kernel +* knows and not specifed in the user restore masks. +*/ +init_xstate (pcntxt_lmask & ~(XSTATE_FPSSE | lmask), + pcntxt_hmask & ~hmask); + }else +init_xstate (pcntxt_lmask & ~XSTATE_FPSSE , pcntxt_hmask); + +/* +* FP and SSE state can't be restored directly from the userspace +* because of legacy reasons. Lets restore it to the fpstate +* in the task struct. +*/ +unlazy_fpu (tsk); + +if (buf) { +/* +* legacy FP and SSE restore. +*/ + err =restore_i387_fxsave (buf); +if (err) +return err; + }else +/* +* initialize tasks fpstate in the memory. +*/ +init_task_fpstate (tsk); + +return err; + +init_state: +if (used_math ()) { +clear_fpu (current); +clear_used_math (); + } + +return err; +} + +/* +* Enable the extended processor state save/restore feature +*/ +void __cpuinit xsave_init (void ) +{ +if (!cpu_has_xsave) +return ; + +set_in_cr4 (X86_CR4_OSXSAVE ); + +/* +* Enable all the features that the HW is capable of +* and the Linux kernel is aware of. +* +* xsetbv(); +*/ + asmvolatile (".byte 0x0f,0x01,0xd1" ::"c" (0 ), +"a" (pcntxt_lmask),"d" (pcntxt_hmask)); +} + +/* +* setup the xstate image representing the init state +*/ +void setup_xstate_init (void ) +{ + init_xstate_buf =alloc_bootmem (xstate_size); + init_xstate_buf->i387.mxcsr =MXCSR_DEFAULT ; +} + +/* +* Enable and initialize the xsave feature. +*/ +void __init xsave_cntxt_init (void ) +{ +unsigned int eax, ebx, ecx, edx; + +cpuid_count (0xd ,0 , &eax, &ebx, &ecx, &edx); + + pcntxt_lmask = eax; + pcntxt_hmask = edx; + +if ((pcntxt_lmask &XSTATE_FPSSE ) !=XSTATE_FPSSE ) { +printk ("FP/SSE not shown under xsave features %x\n" , + pcntxt_lmask); +BUG (); + } + +/* +* for now OS knows only about FP/SSE +*/ + pcntxt_lmask = pcntxt_lmask &XCNTXT_LMASK ; + pcntxt_hmask = pcntxt_hmask &XCNTXT_HMASK ; + +xsave_init (); + +/* +* Recompute the context size for enabled features +*/ +cpuid_count (0xd ,0 , &eax, &ebx, &ecx, &edx); + + xstate_size = ebx; + +setup_xstate_init (); + +printk ("xsave/xrstor: cntxt size %x, supported lmask %x, hmask %x\n" , + xstate_size, pcntxt_lmask, pcntxt_hmask); +}
include/asm-x86/xsave.h new file +120 -0
120 lines not on this page · raw message
include/asm-x86/processor-flags.h +1 -0
@@ -59,6 +59,7 @@#define X86_CR4_OSFXSR 0x00000200/* enable fast FPU save and restore */ #define X86_CR4_OSXMMEXCPT 0x00000400/* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x00002000/* enable VMX virtualization */ +#define X86_CR4_OSXSAVE 0x00040000/* enable xsave and xrestore */ /* * x86-64 Task Priority Register, CR8
arch/x86/kernel/traps_64.c +1 -5
@@ -1155,7 +1155,7 @@ }clts ();/* Allow maths ops (or we recurse) */ -restore_fpu_checking (&me->thread.xstate->fxsave); +restore_fpu_xstate (me);task_thread_info (me)->status |=TS_USEDFPU ; me->fpu_counter++; }
@@ -1191,10 +1191,6 @@#endif /* -* initialize the per thread extended state: -*/ -init_thread_xstate (); -/* * Should be a barrier for any external CPU state. */ cpu_init ();
arch/x86/kernel/signal_64.c +23 -21
95 lines not on this page · raw message
include/asm-x86/sigcontext.h +22 -0
@@ -202,4 +202,26 @@#endif /* !__i386__ */ +struct _xsave_hdr_struct { +u64 xstate_bv; +u64 reserved1[2 ]; +u64 reserved2[5 ]; +} __attribute__((packed)); + +struct _xstate { +/* +* Applications need to refer to fpstate through fpstate pointer +* in sigcontext. Not here directly. +*/ +struct _fpstate fpstate; +struct _xsave_hdr_struct xsave_hdr; +/* new processor state extensions will go here */ +} __attribute__ ((aligned (64 ))); + +struct xstate_cntxt { +struct _xstate __user *xstate; +u32 size; +u32 lmask; +u32 hmask; +};#endif
arch/x86/ia32/ia32_signal.c +65 -29
209 lines not on this page · raw message
arch/x86/kernel/Makefile +1 -1
@@ -31,7 +31,7 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-y += process.o -obj-y += i387.o +obj-y += i387.o xsave.o obj-y += ptrace.o obj-y += ds.o obj-$(CONFIG_X86_32) += tls.o
arch/x86/kernel/i387.c +79 -27
205 lines not on this page · raw message
arch/x86/kernel/signal_32.c +62 -29
187 lines not on this page · raw message
include/asm-x86/cpufeature.h +2 -0
@@ -90,6 +90,7 @@#define X86_FEATURE_CX16 (4*32+13)/* CMPXCHG16B */ #define X86_FEATURE_XTPR (4*32+14)/* Send Task Priority Messages */ #define X86_FEATURE_DCA (4*32+18)/* Direct Cache Access */ +#define X86_FEATURE_XSAVE (4*32+26)/* XSAVE */ /* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */ #define X86_FEATURE_XSTORE (5*32+ 2)/* on-CPU RNG present (xstore insn) */
@@ -187,6 +188,7 @@#define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES)#define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON)#define cpu_has_pat boot_cpu_has(X86_FEATURE_PAT) +#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)#if defined(CONFIG_X86_INVLPG ) || defined(CONFIG_X86_64 )# define cpu_has_invlpg 1
include/asm-x86/i387.h +84 -56
226 lines not on this page · raw message
include/asm-x86/processor.h +13 -0
@@ -351,10 +351,23 @@u32 entry_eip; }; +struct xsave_hdr_struct { +u64 xstate_bv; +u64 reserved1[2 ]; +u64 reserved2[5 ]; +} __attribute__((packed)); + +struct xsave_struct { +struct i387_fxsave_struct i387; +struct xsave_hdr_struct xsave_hdr; +/* new processor state extensions will go here */ +} __attribute__ ((packed,aligned (64 ))); +union thread_xstate {struct i387_fsave_struct fsave;struct i387_fxsave_struct fxsave;struct i387_soft_struct soft; +struct xsave_struct xsave; };#ifdef CONFIG_X86_64
arch/x86/kernel/cpu/feature_names.c +1 -1
@@ -46,7 +46,7 @@"pni" ,NULL ,NULL ,"monitor" ,"ds_cpl" ,"vmx" ,"smx" ,"est" ,"tm2" ,"ssse3" ,"cid" ,NULL ,NULL ,"cx16" ,"xtpr" ,NULL ,NULL ,NULL ,"dca" ,"sse4_1" ,"sse4_2" ,NULL ,NULL ,"popcnt" , -NULL ,NULL ,NULL ,NULL ,NULL ,NULL ,NULL ,NULL , +NULL ,NULL ,"xsave" ,NULL ,NULL ,NULL ,NULL ,NULL ,/* VIA/Cyrix/Centaur-defined */ NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
include/asm-x86/ucontext.h +4 -1
@@ -6,7 +6,10 @@struct ucontext *uc_link;stack_t uc_stack;struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ +sigset_t uc_sigmask; +/* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ +int __unused[32 - (sizeof (sigset_t) /sizeof (int ))]; + struct xstate_cntxt uc_xstate; };#endif /* _ASM_X86_UCONTEXT_H */
include/asm-x86/ia32.h +1 -0
@@ -41,6 +41,7 @@stack_ia32_t uc_stack;struct sigcontext_ia32 uc_mcontext;compat_sigset_t uc_sigmask;/* mask last for extensibility */ +struct xstate_cntxt_ia32 uc_xstate; };/* This matches struct stat64 in glibc2.2, hence the absolutely
include/asm-x86/sigcontext32.h +7 -0
@@ -43,6 +43,13 @@__u32 padding[56 ]; }; +struct xstate_cntxt_ia32 { +u32 xstate;/* really (struct _xstate *) */ +u32 size; +u32 lmask; +u32 hmask; +}; +struct sigcontext_ia32 {unsigned short gs, __gsh;unsigned short fs, __fsh;
arch/x86/kernel/sigframe.h +3 -2
@@ -3,9 +3,10 @@char __user *pretcode;int sig;struct sigcontext sc; -struct _fpstate fpstate; +struct xstate_cntxt xst_cnxt;unsigned long extramask[_NSIG_WORDS-1 ];char retcode[8 ]; +/* fp and rest of the extended context state follows here */ };struct rt_sigframe {
@@ -15,8 +16,8 @@void __user *puc;struct siginfo info;struct ucontext uc; -struct _fpstate fpstate;char retcode[8 ]; +/* fp and rest of the extended context state follows here */ };#else struct rt_sigframe {
arch/x86/kernel/traps_32.c +1 -2
@@ -1178,7 +1178,7 @@ }clts ();/* Allow maths ops (or we recurse) */ -restore_fpu (tsk); +restore_fpu_xstate (tsk); thread->status |=TS_USEDFPU ;/* So we fnsave on switch_to() */ tsk->fpu_counter++; }
@@ -1255,7 +1255,6 @@set_bit (SYSCALL_VECTOR , used_vectors); -init_thread_xstate ();/* * Should be a barrier for any external CPU state: */
arch/x86/kernel/cpu/common.c +4 -0
@@ -742,6 +742,10 @@current_thread_info ()->status =0 ;clear_used_math ();mxcsr_feature_mask_init (); + +if (!smp_processor_id ()) +init_thread_xstate (); +xsave_init (); }#ifdef CONFIG_HOTPLUG_CPU
Quoted 6 lines · Suresh Siddha
hi,
Appended patch adds the support for xsave/xrstor infrastructure for x86. xsave/xrstor manages the existing and future processor extended states in x86 architecutre.
Quoted 6 lines
More info on xsave/xrstor can be found in the Intel SDM's located at
http://www.intel.com/products/processor/manuals/index.htmPlease let me know your feedback and comments. Specifically, I am not sure if I break anything or make anyone's life harder with the
ucontext_textensions that are proposed in the patch.
This is a large patch, and somewhat difficult to review since it mixes kernel-private and user-visible changes. I'm going to focus on the user-visible changes.
Quoted 1 line
BTW, Traditionally glibc has this definition for struct ucontext.
glibc's definition is irrelevant, in part because glibc can and does lie about kernel types to applications, and in part because glibc is not the only user-space consumer of kernel types: there are other libcs, and there are user-space virtualisation tools (my interest in this matter) that care deeply about kernel types and sigframe layouts. In particular, user-space needs to be able to copy and assemble sigframes.
So however the xsave support ends up looking, user-space must have a sensible way of detecting and handling the layout changes.
Quoted 4 lines
include/asm-x86/ucontext.h +0
-0@@ -6,7 +6,10 @@struct ucontext *uc_link;
include/asm-x86/ucontext.h line 15
Quoted 10 lines
include/asm-x86/ucontext.h +4
-1stack_t uc_stack;struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ +sigset_t uc_sigmask; +/* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ +int __unused[32 - (sizeof (sigset_t) /sizeof (int ))]; + struct xstate_cntxt uc_xstate; };#endif /* _ASM_X86_UCONTEXT_H */
You're changing the layout of struct ucontext in two ways: uc_mcontext changes elsewhere, and you're adding __unused and uc_xstate.
How is user-space supposed to know whether it's looking at a current layout ucontext or an xsave-layout ucontext?
It seems that uc_flags is unused and always zero. Could you define a flag bit (e.g. 1) for uc_flags to indicate the xsave layout?
arch/x86/kernel/sigframe.h line 10
Quoted 12 lines
arch/x86/kernel/sigframe.h +2
-1@@ -3,9 +3,10 @@char __user *pretcode;int sig;struct sigcontext sc; -struct _fpstate fpstate; +struct xstate_cntxt xst_cnxt;unsigned long extramask[_NSIG_WORDS-1 ];char retcode[8 ]; +/* fp and rest of the extended context state follows here */ };
Offset to extramask[] and retcode changes, as well as the size of the structure.
Why contract xstate_cntxt to xst_cnxt? That just obscures things.
Quoted 19 lines
include/asm-x86/sigcontext.h +13
-0@@ -202,4 +202,26 @@#endif /* !__i386__ */ +struct _xsave_hdr_struct { +u64 xstate_bv; +u64 reserved1[2 ]; +u64 reserved2[5 ]; +} __attribute__((packed)); + +struct _xstate { +/* +* Applications need to refer to fpstate through fpstate pointer +* in sigcontext. Not here directly. +*/ +struct _fpstate fpstate; +struct _xsave_hdr_struct xsave_hdr;
include/asm-x86/sigcontext.h line 227
Quoted 10 lines
include/asm-x86/sigcontext.h +9
-0+/* new processor state extensions will go here */ +} __attribute__ ((aligned (64))); + +struct xstate_cntxt { +struct _xstate __user *xstate; +u32 size; +u32 lmask; +u32 hmask; +};#endif
What is the purpose of the xstate pointer in xstate_cntxt? As far as I can tell, it's redundant and can alway be derived from the ucontext's uc_mcontext.fpstate pointer.
On x86-64 we have:
Quoted 2 lines
arch/x86/kernel/signal_64.c +0
-0
...
arch/x86/kernel/signal_64.c line 248
Quoted 9 lines
arch/x86/kernel/signal_64.c +8
-0err |=__put_user (fp, &frame->uc.uc_mcontext.fpstate); + +if (cpu_has_xsave) { + err |=__put_user (fp, &frame->uc.uc_xstate.xstate); + err |=__put_user (xstate_size, &frame->uc.uc_xstate.size); + err |=__put_user (pcntxt_lmask, &frame->uc.uc_xstate.lmask); + err |=__put_user (pcntxt_hmask, &frame->uc.uc_xstate.hmask); + }else { + err |=__put_user (0 , &frame->uc.uc_xstate.xstate);
and on x86-32 we have:
Quoted 2 lines
arch/x86/kernel/signal_32.c +0
-0
...
Quoted 3 lines
arch/x86/kernel/signal_32.c +2
-1-get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, + struct _fpstate **fpstate, struct xsave_struct **xstate)
...
arch/x86/kernel/signal_32.c line 340
Quoted 13 lines
arch/x86/kernel/signal_32.c +12
-1- sp -= frame_size; +if (used_math ()) { + sp =round_down (sp - xstate_size,64 ); +if (cpu_has_xsave) + *xstate = (struct xsave_struct *) sp; + + sp = sp - (sizeof (struct _fpstate ) -FXSAVE_SIZE ); + + *fpstate = (struct _fpstate *) sp; + + sp -= frame_size; + }else + sp -= frame_size;
...(in setup_frame())
arch/x86/kernel/signal_32.c line 386
Quoted 12 lines
arch/x86/kernel/signal_32.c +9
-1- err =setup_sigcontext (&frame->sc, &frame->fpstate, regs, set->sig[0 ]); + err =setup_sigcontext (&frame->sc, regs, set->sig[0 ], + fpstate, xstate);if (err) goto give_sigsegv; +if (cpu_has_xsave) { + err |=__put_user (xstate, &frame->xst_cnxt.xstate); + err |=__put_user (xstate_size, &frame->xst_cnxt.size); + err |=__put_user (pcntxt_lmask, &frame->xst_cnxt.lmask); + err |=__put_user (pcntxt_hmask, &frame->xst_cnxt.hmask); + }else { + err |=__put_user (0 , &frame->xst_cnxt.xstate);
...(in setup_rt_frame())
arch/x86/kernel/signal_32.c line 485
Quoted 11 lines
arch/x86/kernel/signal_32.c +9
-2- err |=setup_sigcontext (&frame->uc.uc_mcontext, &frame->fpstate, - regs, set->sig[0 ]); + err |=setup_sigcontext (&frame->uc.uc_mcontext, regs, set->sig[0 ], + fpstate, xstate); +if (cpu_has_xsave) { + err |=__put_user (xstate, &frame->uc.uc_xstate.xstate); + err |=__put_user (xstate_size, &frame->uc.uc_xstate.size); + err |=__put_user (pcntxt_lmask, &frame->uc.uc_xstate.lmask); + err |=__put_user (pcntxt_hmask, &frame->uc.uc_xstate.hmask); + }else { + err |=__put_user (0 , &frame->uc.uc_xstate.xstate);
In all cases .xstate seems to be a function of fpstate and cpu_has_xsave.
And why does x86-64 make xstate == fpstate while on x86-32 they're at an offset from each other?
The fpstate pointer may be pointing into a struct _xstate. How is user-space supposed to know if this is the case?
struct _fpstate has a 'magic' field which distinguishes x87-only from x87+FXSR structs. Could that field also be used to indicate XSAVE?
How is user-space supposed to know how large the _xstate struct is? Is that the size field in the struct xstate_cntxt?
Quoted 2 lines
arch/x86/kernel/xsave.c new file +0
-0
...
arch/x86/kernel/xsave.c line 179
Quoted 5 lines
arch/x86/kernel/xsave.c new file +5
-0+/* +* FP and SSE state can't be restored directly from the userspace +* because of legacy reasons. Lets restore it to the fpstate +* in the task struct. +*/
Can you please explain what those 'legacy reasons' are?
arch/x86/kernel/signal_32.c
Quoted 2 lines
arch/x86/kernel/signal_32.c +0
-0
...(in setup_frame)
arch/x86/kernel/signal_32.c line 364
Quoted 4 lines
arch/x86/kernel/signal_32.c +1
-1-if (!access_ok (VERIFY_WRITE , frame,sizeof (*frame))) +if (!access_ok (VERIFY_WRITE , frame,sizeof (*frame))) goto give_sigsegv;
Gratuitous whitespace change.
I know xsave will be needed once AVX is released to the masses. Any idea on when that will happen?
/Mikael
Quoted 2 lines · Mikael Pettersson
This is a large patch, and somewhat difficult to review since it mixes kernel-private and user-visible changes.
Sorry. I wanted to give the complete picture. Will see if I can split it up while posting for upstream.
Quoted 10 lines
I'm going to focus on the user-visible changes.
Quoted 1 line
BTW, Traditionally glibc has this definition for struct ucontext.
glibc's definition is irrelevant, in part because glibc can and does lie about kernel types to applications, and in part because glibc is not the only user-space consumer of kernel types: there are other libcs, and there are user-space virtualisation tools (my interest in this matter) that care deeply about kernel types and sigframe layouts. In particular, user-space needs to be able to copy and assemble sigframes.
Ok. I hope user-space is doing this copy and assemble in a (sane) way that allows the kernel to modify the sigframe with out breaking old apps.
Do you know how the user-space is determining how much to copy today?
I have to probably use some magic values(or other flags), indicating the presence of extended state context information in the ucontext.
Quoted 2 lines
So however the xsave support ends up looking, user-space must have a sensible way of detecting and handling the layout changes.
cpuid information (cpuid.0x1.ecx.osxsave) indicates whether the OS supports xsave or not. This can be one way, that signal handlers can use to interpret the ucontext.
Given that it is more than signal handlers, I can add a flag also, representing ucontext extensions.
Quoted 13 lines
Quoted 13 lines
include/asm-x86/ucontext.h +4
-1@@ -6,7 +6,10 @@struct ucontext *uc_link;stack_t uc_stack;struct sigcontext uc_mcontext; -sigset_t uc_sigmask;/* mask last for extensibility */ +sigset_t uc_sigmask; +/* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ +int __unused[32 - (sizeof (sigset_t) /sizeof (int ))]; +struct xstate_cntxt uc_xstate; };
Quoted 4 lines
include/asm-x86/ucontext.h line 15
Quoted 1 line
include/asm-x86/ucontext.h +0
-0#endif /* _ASM_X86_UCONTEXT_H */ You're changing the layout of struct ucontext in two ways:
uc_mcontextchanges elsewhere, and you're adding__unusedanduc_xstate.
I am not changing the uc_mcontext (struct sigcontext). Just extending the ucontext.
Quoted 6 lines
How is user-space supposed to know whether it's looking at a current layout ucontext or an xsave-layout ucontext?
It seems that
uc_flagsis unused and always zero. Could you define a flag bit (e.g. 1) foruc_flagsto indicate the xsave layout?
Sure. I can even add a magic word to indicate the xsave presence, so that sigreturn can be double sure and not break older apps.
Quoted 6 lines
Quoted 6 lines
arch/x86/kernel/sigframe.h +0
-0@@ -3,9 +3,10 @@char __user *pretcode;int sig;struct sigcontext sc;
Quoted 8 lines
arch/x86/kernel/sigframe.h line 10
Quoted 6 lines
arch/x86/kernel/sigframe.h +2
-1-struct _fpstate fpstate; +struct xstate_cntxt xst_cnxt;unsigned long extramask[_NSIG_WORDS-1 ];char retcode[8 ]; +/* fp and rest of the extended context state follows here */ };Offset to extramask[] and retcode changes, as well as the size of the structure.
hm yes. this will break the restore of extramask[], for apps which set their own sig return frames.
I can leave _fpstate as it is(and unused) and move xstate context (which will contain fpstate + the extended state) after extramask[].
Quoted 1 line
Why contract
xstate_cntxttoxst_cnxt? That just obscures things.
ok.
Quoted 26 lines
Quoted 26 lines
include/asm-x86/sigcontext.h +19
-0@@ -202,4 +202,26 @@#endif /* !__i386__ */ +struct _xsave_hdr_struct { +u64 xstate_bv; +u64 reserved1[2 ]; +u64 reserved2[5 ]; +} __attribute__((packed)); + +struct _xstate { +/* +* Applications need to refer to fpstate through fpstate pointer +* in sigcontext. Not here directly. +*/ +struct _fpstate fpstate; +struct _xsave_hdr_struct xsave_hdr; +/* new processor state extensions will go here */ +} __attribute__ ((aligned (64 ))); + +struct xstate_cntxt { +struct _xstate __user *xstate; +u32 size;
Quoted 8 lines
include/asm-x86/sigcontext.h line 227
Quoted 4 lines
include/asm-x86/sigcontext.h +3
-0+u32 lmask; + u32 hmask; +};#endif What is the purpose of the xstate pointer in
xstate_cntxt? As far as I can tell, it's redundant and can alway be derived from the ucontext's uc_mcontext.fpstate pointer.
This is true in 64bit.
While doing sigreturn, there is no way, kernel can know if the uc_mcontext.fpstate is pointing to just the legacy fpstate(512 bytes) or the extended state pointer (unless we incorporate
some magic word at the end of fpstate image, see below)
during sigreturn, fpstate will be restored from the uc_mcontext.fpstate and extended state will be restored from xstate pointer.
Quoted 2 lines
And why does x86-64 make xstate == fpstate while on x86-32 they're at an offset from each other?
because sigcontext's 32bit fpstate is different from 64bit fpstate. 32bit fp state is fsave frame followed by fxsave frame. Whereas 64bit fp state is just fxsave frame. To maintain 32bit legacy compatibility, 32bit xstate is different from 32bit fpstate.
Quoted 2 lines
The fpstate pointer may be pointing into a struct
_xstate. How is user-space supposed to know if this is the case?
user-space doesn't have to know. user has to refer fpstate through fpstate pointer, and all the extended state through xstate pointer. during the sigreturn, kernel will restore fp state through fpstate pointer and the rest (exclusing FP/SSE) will be restored from xstate pointer.
Quoted 2 lines
struct
_fpstatehas a 'magic' field which distinguishes x87-only from x87+FXSR structs. Could that field also be used to indicate XSAVE?
I don't think we can use the existing 'magic' field. But we can use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.
Quoted 2 lines
How is user-space supposed to know how large the
_xstatestruct is? Is that the size field in the structxstate_cntxt?
yes. I will make the names more descriptive :)
Quoted 11 lines
Quoted 3 lines
arch/x86/kernel/xsave.c new file +0
-0...
arch/x86/kernel/xsave.c line 179
Quoted 5 lines
arch/x86/kernel/xsave.c new file +5
-0+/* +* FP and SSE state can't be restored directly from the userspace +* because of legacy reasons. Lets restore it to the fpstate +* in the task struct. +*/ Can you please explain what those 'legacy reasons' are?
As I mentioned earlier, fpstate contains both fsave frame followed by fxsave frame. So the kernel can't directly restore the information.
Quoted 2 lines
I know xsave will be needed once AVX is released to the masses. Any idea on when that will happen?
AVX is currently planned for Sandybridge time frame.
thanks,
suresh
Quoted 6 lines · Suresh Siddha
Quoted 2 lines · Mikael Pettersson
This is a large patch, and somewhat difficult to review since it mixes kernel-private and user-visible changes.
Sorry. I wanted to give the complete picture. Will see if I can split it up while posting for upstream.
Ok.
Quoted 9 lines
Quoted 8 lines
Quoted 1 line
BTW, Traditionally glibc has this definition for struct ucontext.
glibc's definition is irrelevant, in part because glibc can and does lie about kernel types to applications, and in part because glibc is not the only user-space consumer of kernel types: there are other libcs, and there are user-space virtualisation tools (my interest in this matter) that care deeply about kernel types and sigframe layouts. In particular, user-space needs to be able to copy and assemble sigframes.
Quoted 4 lines
Ok. I hope user-space is doing this copy and assemble in a (sane) way that allows the kernel to modify the sigframe with out breaking old apps.
Do you know how the user-space is determining how much to copy today?
The de-facto ABI for signal delivery and sigreturn is unfortunately based on fairly fixed-layout structs on the stack (sigframes). The only flexibility there that I've found is the sigcontext's fpstate pointer which allows the fpstate to be located elsewhere.
User-space pretty much has to know the kernel's sigframe layout, for instance, non-siginfo sigframes on x86-32 hide additional sigmask words above the fpstate.
User-space could in theory compare SP with the sigcontext's SP and the altstack (if any) and deduce the sigframe size from that, but that gives incomplete information; for instance, user-space must still be able to locate and adjust embedded pointers in the sigframe.
In my case we "know" the sigframe struct layout based on OS and CPU combination. I can't comment on how others deal with this.
It's pretty much guaranteed that any extension of these structs will break some applications. I think the best we can hope for is that
1) applications that only inspect sigframes without copying them don't break, and
2) applications get a mechanism for detecting the new layout of sigframes and ucontexts, allowing them to be updated to handle those changes.
Quoted 2 lines
I have to probably use some magic values(or other flags), indicating the presence of extended state context information in the ucontext.
I believe so too.
Quoted 6 lines
cpuid information (cpuid.0x1.ecx.osxsave) indicates whether the OS supports xsave or not. This can be one way, that signal handlers can use to interpret the ucontext.
Given that it is more than signal handlers, I can add a flag also, representing ucontext extensions.
My problem with the OSXAVE flag is that it's a very indirect way of communicating the layout of sigframes and sigcontexts. These structures should, if at all possible, be self-describing. A single flag bit in the sigcontext could handle both structures (since a sigframe always includes a sigcontext).
[But see my comment below about uc_flags.]
Quoted 5 lines
Quoted 2 lines
You're changing the layout of struct ucontext in two ways:
uc_mcontextchanges elsewhere, and you're adding__unusedanduc_xstate.I am not changing the
uc_mcontext(struct sigcontext). Just extending the ucontext.
Correct, my mistake.
Quoted 8 lines
Quoted 5 lines
How is user-space supposed to know whether it's looking at a current layout ucontext or an xsave-layout ucontext?
It seems that
uc_flagsis unused and always zero. Could you define a flag bit (e.g. 1) foruc_flagsto indicate the xsave layout?Sure. I can even add a magic word to indicate the xsave presence, so that sigreturn can be double sure and not break older apps.
The uc_flags field is not specified by SUSv3. Linux stores a zero in it on signal delivery but doesn't use it on signal return. Solaris describes it as implementation-dependent, and stores a bit vector in it describing which parts of the ucontext are valid and should be restored by setcontext (i.e. sigreturn in Linux). Thus uc_flags would be a perfect place to store an XSAVE flag or cookie.
Using uc_flags takes care of x86-64 and x86-32 with "rt" sigframes (SA_SIGINFO signal dispositions). The remaining problem is x86-32 with non-SA_SIGINFO sigframes, since they store plain sigcontexts on the stack not ucontexts, and so don't have a uc_flags field. To handle those we have to augment either sigcontexts or the plain non-rt sigframes with some kind of marker.
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
arch/x86/kernel/sigframe.h +2
-1@@ -3,9 +3,10 @@char __user *pretcode;int sig;struct sigcontext sc; -struct _fpstate fpstate; +struct xstate_cntxt xst_cnxt;unsigned long extramask[_NSIG_WORDS-1 ];char retcode[8 ]; +/* fp and rest of the extended context state follows here */ };
Quoted 4 lines
Quoted 1 line
Offset to extramask[] and retcode changes, as well as the size of the structure.
hm yes. this will break the restore of extramask[], for apps which set their own sig return frames.
Updating extramask[] is useful for combining sigprocmask(SIG_SETMASK,_,_) and sigreturn into an atomic operation. AFAIK, there's no way to reach extramask[] without knowing the sigframe layout.
Quoted 2 lines
I can leave
_fpstateas it is(and unused) and move xstate context (which will contain fpstate + the extended state) after extramask[].
I think that would be best.
Quoted 3 lines
Quoted 1 line
Why contract
xstate_cntxttoxst_cnxt? That just obscures things.ok.
Thanks.
Quoted 14 lines
Quoted 3 lines
What is the purpose of the xstate pointer in
xstate_cntxt? As far as I can tell, it's redundant and can alway be derived from the ucontext's uc_mcontext.fpstate pointer.This is true in 64bit.
While doing sigreturn, there is no way, kernel can know if the uc_mcontext.fpstate is pointing to just the legacy fpstate(512 bytes) or the extended state pointer (unless we incorporate
some magic word at the end of fpstate image, see below)during sigreturn, fpstate will be restored from the uc_mcontext.fpstate and extended state will be restored from xstate pointer.
Quoted 7 lines
Quoted 2 lines
And why does x86-64 make xstate == fpstate while on x86-32 they're at an offset from each other?
because sigcontext's 32bit fpstate is different from 64bit fpstate. 32bit fp state is fsave frame followed by fxsave frame. Whereas 64bit fp state is just fxsave frame. To maintain 32bit legacy compatibility, 32bit xstate is different from 32bit fpstate.
Ok, thanks for clarifying this.
Quoted 4 lines
Quoted 2 lines
struct
_fpstatehas a 'magic' field which distinguishes x87-only from x87+FXSR structs. Could that field also be used to indicate XSAVE?I don't think we can use the existing 'magic' field.
Hmm, right now it seems this field has a de-facto ABI of being either 0xffff (plain) or 0x0000 (fxsr). Using other values would confuse at least one application I know of. Sad.
Quoted 8 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.
If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
Another idea I have at the moment is that it seems that struct _fpstate reserves storage for x87 in both the legacy part and the fxsr part. Looking through arch/x86/kernel/i387.c it seems that the x87 space in the fxsr part isn't actually used (see convert_to_fxsr()). If so, it might be possible to reuse it for an XSAVE indicator.
Another idea is that marking non-siginfo sigframes could be done by adding a sys_xsave_sigreturn() and letting those sigframes have a return address pointing to a vsyscall that invokes this new syscall.
/Mikael
Quoted 5 lines
The de-facto ABI for signal delivery and sigreturn is unfortunately based on fairly fixed-layout structs on the stack (sigframes). The only flexibility there that I've found is the sigcontext's fpstate pointer which allows the fpstate to be located elsewhere.
One sure 100% compatible way would be to only change the signal layout once the application used anything that needs XSAVE/XRSTOR. But implementing that would be likely complicated and I'm not sure it's worth it.
I don't remember that much breakage when the FXSAVE support was introduced on i386. That already changed these data structures.
Quoted 4 lines
Another idea is that marking non-siginfo sigframes could be done by adding a
sys_xsave_sigreturn()and letting those sigframes have a return address pointing to a vsyscall that invokes this new syscall.
That sounds easy enough. x86-64 right now doesn't use signal vsyscalls but there is no principle reason it can't.
-Andi
H. Peter Anvin
reviewerQuoted 7 lines · Mikael Pettersson
My problem with the OSXAVE flag is that it's a very indirect way of communicating the layout of sigframes and sigcontexts. These structures should, if at all possible, be self-describing. A single flag bit in the sigcontext could handle both structures (since a sigframe always includes a sigcontext).
It's also wrong, since OSXSAVE indicates that the CPU can do it, not that the kernel can.
Quoted 9 lines
Quoted 4 lines
Quoted 3 lines
struct
_fpstatehas a 'magic' field which distinguishes x87-only from x87+FXSR structs. Could that field also be used to indicate XSAVE?I don't think we can use the existing 'magic' field.
Hmm, right now it seems this field has a de-facto ABI of being either
0xffff(plain) or0x0000(fxsr). Using other values would confuse at least one application I know of. Sad.
Well, arguably it is the right thing to use since we're talking about a new format. The difference is that the new format *does* extend backwards to match the old format.
Quoted 9 lines
Quoted 8 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.
Quoted 4 lines
If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
All we need is a single field -- a single byte -- reserved indefinitely for software use. Existing FXSAVE kernels will have set it to zero.
There might be fields the existing FXSAVE format which can be equally abused, even. I will do some looking.
-hpa
Quoted 11 lines · H. Peter Anvin
Quoted 7 lines · Mikael Pettersson
My problem with the OSXAVE flag is that it's a very indirect way of communicating the layout of sigframes and sigcontexts. These structures should, if at all possible, be self-describing. A single flag bit in the sigcontext could handle both structures (since a sigframe always includes a sigcontext).
It's also wrong, since OSXSAVE indicates that the CPU can do it, not that the kernel can.
OSXSAVE indicates the OS support and XSAVE indicates the cpu support.
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Quoted 2 lines
struct
_fpstatehas a 'magic' field which distinguishes x87-only from x87+FXSR structs. Could that field also be used to indicate XSAVE?I don't think we can use the existing 'magic' field.
Quoted 8 lines
Quoted 4 lines
Hmm, right now it seems this field has a de-facto ABI of being either
0xffff(plain) or0x0000(fxsr). Using other values would confuse at least one application I know of. Sad.Well, arguably it is the right thing to use since we're talking about a new format. The difference is that the new format *does* extend backwards to match the old format.
There might be some old applications, which just care about FP/SSE and just check for 0xffff (plain) or 0x0000 (fxsr). We should extend this in a backward compatible manner.
Quoted 15 lines
Quoted 10 lines
Quoted 9 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of
xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and see what they think.Quoted 4 lines
If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
Quoted 5 lines
All we need is a single field -- a single byte -- reserved indefinitely for software use. Existing FXSAVE kernels will have set it to zero.
There might be fields the existing FXSAVE format which can be equally abused, even. I will do some looking.
All the reserved fields at the end of fxsave format are zeroed and presented as such to the user. If HW makes some of these fields SW available, then we can use those (will check). If there is any scope with the existing format it self, that will be much better.
thanks,
suresh
H. Peter Anvin
reviewerQuoted 5 lines · Suresh Siddha
Quoted 2 lines
Quoted 1 line
It's also wrong, since OSXSAVE indicates that the CPU can do it, not that the kernel can.
OSXSAVE indicates the OS support and XSAVE indicates the cpu support.
Sorry, brainfart. Don't post so early in the morning.
Quoted 8 lines
Quoted 3 lines
All we need is a single field -- a single byte -- reserved indefinitely for software use. Existing FXSAVE kernels will have set it to zero.
There might be fields the existing FXSAVE format which can be equally abused, even. I will do some looking.
All the reserved fields at the end of fxsave format are zeroed and presented as such to the user. If HW makes some of these fields SW available, then we can use those (will check). If there is any scope with the existing format it self, that will be much better.
I was thinking about what we'd really like earlier, and given a clean slate I'd like to see a structure looking like:
struct state_ptrs {
size_t len;
struct state_foo *foo;
struct state_bar *bar;
...
};... where len is sizeof(struct state_ptrs). This is not merely extensible, but it's easy for userspace to massage it into whatever format -- longer or shorter -- that it happens to know about, and it gives a natural way for the kernel to communicate "none of this state" by feeding a NULL pointer. So pretty much we're looking for a way to backwards-compatible way to stash a pointer to this structure, I figure.
-hpa
Quoted 9 lines · Mikael Pettersson
Quoted 8 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.
Quoted 4 lines
If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
Ok. CPU folks are planning to make some of the bytes at the end of fxsave image, SW usable.
We can use some of these fields, to represent the extended state presence with a cookie, save area size, mask of the state stored. If needed, we can include the start address of the fpstate pointer (also as part of the cookie), so that we can detect the situation, where apps are just memcopying sizeof(struct _fpstate) from the fpstate pointer (but not aware of the extended state).
we don't need any ucontext_t extensions any more and just use the fpstate pointer to indicate the extended state aswell, right?
In addition, we need to make sure that for 32bit non-rt sigframes, we don't modify the extramask[] offset.
thanks,
suresh
Quoted 10 lines · Suresh Siddha
Quoted 9 lines · Mikael Pettersson
Quoted 8 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.
Quoted 7 lines
Quoted 4 lines
If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
Ok. CPU folks are planning to make some of the bytes at the end of fxsave image, SW usable.
Nice.
Quoted 6 lines
We can use some of these fields, to represent the extended state presence with a cookie, save area size, mask of the state stored. If needed, we can include the start address of the fpstate pointer (also as part of the cookie), so that we can detect the situation, where apps are just memcopying
sizeof(struct _fpstate)from the fpstate pointer (but not aware of the extended state).
I use a similar technique to detect user-space mangling of ucontexts on Solaris.
Quoted 2 lines
we don't need any
ucontext_textensions any more and just use the fpstate pointer to indicate the extended state aswell, right?
Yes, the old magic distinguishes x87-only from x87+fxsr, the new magic distinguishes fxsr from xsave.
Quoted 2 lines
In addition, we need to make sure that for 32bit non-rt sigframes, we don't modify the extramask[] offset.
Thanks,
/Mikael
Quoted 9 lines · Suresh Siddha
Quoted 8 lines · Mikael Pettersson
Quoted 8 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.
Quoted 7 lines
Quoted 4 lines
If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
Ok. CPU folks are planning to make some of the bytes at the end of fxsave image, SW usable.
Are they always zeroed in earlier CPUs though? If not that wouldn't work 100% reliably because whatever cookie you put in could have been there before by chance.
I don't see anything in the SDM guaranteeing zeroing.
-Andi
Quoted 15 lines · Andi Kleen
Quoted 14 lines · Suresh Siddha
Quoted 12 lines · Mikael Pettersson
Quoted 8 lines
But we can
use some what similar magic, if the fxsave/fxrstor give away
some of the fields at the end of fxsave image (today it is reserved and ignored during fxsave/fxrstor) for software use.
We can then use these fields at the end of fpstate, to indicate the presence of xstate. But this requires some architecture changes like giving away this space for SW use. We can take this to architects and
see what they think.If the HW doesn't store anything valuable there, we could store SW flags/cookies there on signal delivery, and clear them before fxrstor (unless the HW is known to ignore those fields). But it depends on how forgiving the HW is.
Quoted 6 lines
Quoted 2 lines
Ok. CPU folks are planning to make some of the bytes at the end of fxsave image, SW usable.
Are they always zeroed in earlier CPUs though? If not that wouldn't work 100% reliably because whatever cookie you put in could have been there before by chance.
I wrote a test program (fill an area with zeroes, fxsave, inspect reserved fields, then fill it with ones, fxsave, inspect again), and all processors appear to just not write anything to the reserved fields after the last xmm register. (Tested on an old Mobile Athlon64, Opteron 280, P4 Xeon, Pentium-D, and C2 Xeon E5345.)
So the question now is what if anything has the Linux kernel written to those reserved fields. (Looking..) Hmm, signal delivery on x86-64 seems to do fxsave directly to the fxsave area in the user's sigframe, which would imply that the reserved fields have unpredictable values.
/Mikael
H. Peter Anvin
reviewerQuoted 11 lines · Mikael Pettersson
Quoted 4 lines
Are they always zeroed in earlier CPUs though? If not that wouldn't work 100% reliably because whatever cookie you put in could have been there before by chance.
I wrote a test program (fill an area with zeroes, fxsave, inspect reserved fields, then fill it with ones, fxsave, inspect again), and all processors appear to just not write anything to the reserved fields after the last xmm register. (Tested on an old Mobile Athlon64, Opteron 280, P4 Xeon, Pentium-D, and C2 Xeon E5345.)
Quoted 5 lines
So the question now is what if anything has the Linux kernel written to those reserved fields. (Looking..) Hmm, signal delivery on x86-64 seems to do fxsave directly to the fxsave area in the user's sigframe, which would imply that the reserved fields have unpredictable values.
OK, so that's not a usable path unless we can find some area in the existing data set to put a flag. Groan.
-hpa
Quoted 12 lines · H. Peter Anvin
Quoted 11 lines · Mikael Pettersson
Quoted 4 lines
Are they always zeroed in earlier CPUs though? If not that wouldn't work 100% reliably because whatever cookie you put in could have been there before by chance.
I wrote a test program (fill an area with zeroes, fxsave, inspect reserved fields, then fill it with ones, fxsave, inspect again), and all processors appear to just not write anything to the reserved fields after the last xmm register. (Tested on an old Mobile Athlon64, Opteron 280, P4 Xeon, Pentium-D, and C2 Xeon E5345.)
Quoted 8 lines
Quoted 5 lines
So the question now is what if anything has the Linux kernel written to those reserved fields. (Looking..) Hmm, signal delivery on x86-64 seems to do fxsave directly to the fxsave area in the user's sigframe, which would imply that the reserved fields have unpredictable values.
OK, so that's not a usable path unless we can find some area in the existing data set to put a flag. Groan.
An ugly workaround could be to start clearing one of these fields, and say that the data there is only valid for kernels >= 2.6.26. (I said it was ugly...)
Or we go back to stashing a flag in uc_flags (which is kosher), and try to figure out how to mark non-rt sigframes.
/Mikael
Quoted 11 lines · Mikael Pettersson
Quoted 9 lines · H. Peter Anvin
Quoted 5 lines · Mikael Pettersson
So the question now is what if anything has the Linux kernel written to those reserved fields. (Looking..) Hmm, signal delivery on x86-64 seems to do fxsave directly to the fxsave area in the user's sigframe, which would imply that the reserved fields have unpredictable values.
OK, so that's not a usable path unless we can find some area in the existing data set to put a flag. Groan.
Quoted 6 lines
An ugly workaround could be to start clearing one of these fields, and say that the data there is only valid for kernels >= 2.6.26. (I said it was ugly...)
Or we go back to stashing a flag in
uc_flags(which is kosher), and try to figure out how to mark non-rt sigframes.
This issue of not-zeroing, is present in only 64bit kernels and for 64bit apps, right?
64bit app signal handling uses only rt_frame, so we can add an uc_flag for them and for 32bit apps, kernel was always zero'ing the reserved bits at the end of _fpstate.
In short, for non-rt frames, they can check the reserved bits at the end of fpstate frame and for rt-frames (perhaps even for 32bit rt frame handling) apps can check for uc_flag aswell, for extended state presence. Is this good enough?
thanks,
suresh
H. Peter Anvin
reviewerQuoted 4 lines · Suresh Siddha
This issue of not-zeroing, is present in only 64bit kernels and for 64bit apps, right?
Quoted 9 lines
64bit app signal handling uses only
rt_frame, so we can add anuc_flagfor them and for 32bit apps, kernel was always zero'ing the reserved bits at the end of_fpstate.In short, for non-rt frames, they can check the reserved bits at the end of fpstate frame and for rt-frames (perhaps even for 32bit rt frame handling) apps can check for
uc_flagaswell, for extended state presence. Is this good enough?
Are we sure about the "always" bit here (I suspect yes, but we may want to double-check at least back to 2.2 or 2.4.)
Anyway, seems reasonable enough to me.
-hpa
H. Peter Anvin
reviewerQuoted 11 lines · Suresh Siddha
Quoted 7 lines
An ugly workaround could be to start clearing one of these fields, and say that the data there is only valid for kernels >= 2.6.26. (I said it was ugly...)
Or we go back to stashing a flag in
uc_flags(which is kosher), and try to figure out how to mark non-rt sigframes.This issue of not-zeroing, is present in only 64bit kernels and for 64bit apps, right?
Quoted 9 lines
64bit app signal handling uses only
rt_frame, so we can add anuc_flagfor them and for 32bit apps, kernel was always zero'ing the reserved bits at the end of_fpstate.In short, for non-rt frames, they can check the reserved bits at the end of fpstate frame and for rt-frames (perhaps even for 32bit rt frame handling) apps can check for
uc_flagaswell, for extended state presence. Is this good enough?
Okay, trying to close on this :)
I would suggest using the uc_flag for the rt frames, and simply rely on the OSXSAVE flag for non-rt signal frames. It a rather sucky approach (as previously discussed), but since any sane user of these fields (as opposed to just relying on the kernel to save/restore) should use the SIGINFO frames, I don't see a problem *as long as it's possible to get the information* -- any solution which demands performance should just turn on SIGINFO and be happy.
The biggest potential problem with this that I see is that relying on CPUID can mess with certain virtualization solutions. Another option to accomplish the same thing would be to have a system call (preferrably a prctl, since it is at least in theory personality-dependent) to query what information is included in the fpstate data - since it will always be the same for any particular kernel.
Thoughts?
-hpa
Quoted 6 lines
The biggest potential problem with this that I see is that relying on CPUID can mess with certain virtualization solutions. Another option to accomplish the same thing would be to have a system call (preferrably a prctl, since it is at least in theory personality-dependent) to query what information is included in the fpstate data - since it will always be the same for any particular kernel.
It's easy and cheap to add an indicator to the vDSO for this.
Thanks,
Roland
H. Peter Anvin
reviewerQuoted 3 lines · Roland McGrath
Quoted 1 line
The biggest potential problem with this that I see is that relying on CPUID can mess with certain virtualization solutions. Another option to accomplish the same thing would be to have a system call (preferrably a prctl, since it is at least in theory personality-dependent) to query what information is included in the fpstate data - since it will always be the same for any particular kernel.
It's easy and cheap to add an indicator to the vDSO for this.
Yes, but I suspect for legacy apps running without vDSO might matter.
-hpa
Quoted 1 line
Yes, but I suspect for legacy apps running without vDSO might matter.
"Legacy" apps want to be changed to make a new kind of kernel query and care about new details of signal frame layout for new features they never used before, but don't want to handle the vDSO?
Thanks,
Roland
H. Peter Anvin
reviewerQuoted 5 lines · Roland McGrath
Quoted 1 line
Yes, but I suspect for legacy apps running without vDSO might matter.
"Legacy" apps want to be changed to make a new kind of kernel query and care about new details of signal frame layout for new features they never used before, but don't want to handle the vDSO?
I'm talking mostly about semi-embedded ISVs that have managed to get themselves funny ideas about what they don't want to change. The vDSO definitely involves more machinery to get to.
-hpa
Quoted 8 lines · Roland McGrath
Quoted 6 lines
The biggest potential problem with this that I see is that relying on CPUID can mess with certain virtualization solutions. Another option to accomplish the same thing would be to have a system call (preferrably a prctl, since it is at least in theory personality-dependent) to query what information is included in the fpstate data - since it will always be the same for any particular kernel.
It's easy and cheap to add an indicator to the vDSO for this.
For our user-space virtualisation code a plain system call, like prctl(), would be strongly preferable. Right now I can't say whether a vDSO solution would work at all for us, but a system call solution would be no problem at all.
/Mikael
Quoted 24 lines · H. Peter Anvin
Quoted 11 lines · Suresh Siddha
Quoted 7 lines
An ugly workaround could be to start clearing one of these fields, and say that the data there is only valid for kernels >= 2.6.26. (I said it was ugly...)
Or we go back to stashing a flag in
uc_flags(which is kosher), and try to figure out how to mark non-rt sigframes.This issue of not-zeroing, is present in only 64bit kernels and for 64bit apps, right?
Quoted 9 lines
64bit app signal handling uses only
rt_frame, so we can add anuc_flagfor them and for 32bit apps, kernel was always zero'ing the reserved bits at the end of_fpstate.In short, for non-rt frames, they can check the reserved bits at the end of fpstate frame and for rt-frames (perhaps even for 32bit rt frame handling) apps can check for
uc_flagaswell, for extended state presence. Is this good enough?Okay, trying to close on this :)
Quoted 7 lines
I would suggest using the
uc_flagfor the rt frames, and simply rely on the OSXSAVE flag for non-rt signal frames. It a rather sucky approach (as previously discussed), but since any sane user of these fields (as opposed to just relying on the kernel to save/restore) should use the SIGINFO frames, I don't see a problem *as long as it's possible to get the information* -- any solution which demands performance should just turn on SIGINFO and be happy.
I don't have the luxury to unconditionally change non-rt signal delivery to rt signal delivery, but using uc_flags plus OSXSAVE or prctl() to announce these layout changes would work for us. Of course, any existing sigframe mangling (as opposed to just reading it) code must be updated to avoid breakage, but that's unavoidable.
Quoted 8 lines
The biggest potential problem with this that I see is that relying on CPUID can mess with certain virtualization solutions. Another option to accomplish the same thing would be to have a system call (preferrably a prctl, since it is at least in theory personality-dependent) to query what information is included in the fpstate data - since it will always be the same for any particular kernel.
Thoughts?
Ok for me.
/Mikael
Quoted 18 lines · Mikael Pettersson
Quoted 9 lines · H. Peter Anvin
Quoted 5 lines · Suresh Siddha
In short, for non-rt frames, they can check the reserved bits at the end of fpstate frame and for rt-frames (perhaps even for 32bit rt frame handling) apps can check for
uc_flagaswell, for extended state presence. Is this good enough?Okay, trying to close on this :)
Quoted 7 lines
I would suggest using the
uc_flagfor the rt frames, and simply rely on the OSXSAVE flag for non-rt signal frames. It a rather sucky approach (as previously discussed), but since any sane user of these fields (as opposed to just relying on the kernel to save/restore) should use the SIGINFO frames, I don't see a problem *as long as it's possible to get the information* -- any solution which demands performance should just turn on SIGINFO and be happy.
Quoted 8 lines
I don't have the luxury to unconditionally change non-rt signal delivery to rt signal delivery, but using
uc_flagsplus OSXSAVE orprctl()to announce these layout changes would work for us. Of course, any existing sigframe mangling (as opposed to just reading it) code must be updated to avoid breakage, but that's unavoidable.Quoted 2 lines
The biggest potential problem with this that I see is that relying on CPUID can mess with certain virtualization solutions. Another option to
hpa, What is the virtualization problem? Are you referring to perf problem? As you noted, regular non-rt signal handlers won't need this cpuid check. It's needed only for those who manually look at non-rt signal frames and interpret it. And also, they can do this check only once and not everytime.
To me, prtcl() just seems to be an overkill.
While restoring from the user, kernel also need to find out what layout the user is passing. So it's bi-directional. I prefer the same mechanism (using cookies/magic numbers etc inaddition to uc_flags or cpuid checks) to interpret the fpstate for both user/kernel.
ARM also seem to be using similar things while extending their ucontext_t, with out other kernel interfaces to indicate the layout.
BTW, how come 32bit kernel doesn't have the X86_FXSR_MAGIC checks, while restoring the extended fxsave data from _fpstate?
thanks,
suresh
Quoted 10 lines
Quoted 6 lines
accomplish the same thing would be to have a system call (preferrably a prctl, since it is at least in theory personality-dependent) to query what information is included in the fpstate data - since it will always be the same for any particular kernel.
Thoughts?
Ok for me.
/Mikael
H. Peter Anvin
reviewerQuoted 6 lines · Suresh Siddha
hpa, What is the virtualization problem? Are you referring to perf problem? As you noted, regular non-rt signal handlers won't need this cpuid check. It's needed only for those who manually look at non-rt signal frames and interpret it. And also, they can do this check only once and not everytime.
No, relying on CPUID and vdso both have implications for virtualization.
Quoted 1 line
To me,
prtcl()just seems to be an overkill.
I don't think it is ... it's not overkill but rather "underkill"... it's a low-performance solution but it's guaranteed to be safe in the presence of virtualization of all its various ilk. Note that you don't need to be able to *set* the format via prctl(), just *query* (get) it.
Using prctl() allows us to make this personality-dependent if we ever need to.
Quoted 4 lines
While restoring from the user, kernel also need to find out what layout the user is passing. So it's bi-directional. I prefer the same mechanism (using cookies/magic numbers etc inaddition to
uc_flagsor cpuid checks) to interpret the fpstate for both user/kernel.
No, it really doesn't: the kernel only needs to be able to read the same format as it itself wrote.
Quoted 5 lines
ARM also seem to be using similar things while extending their
ucontext_t, with out other kernel interfaces to indicate the layout.BTW, how come 32bit kernel doesn't have the
X86_FXSR_MAGICchecks, while restoring the extended fxsave data from_fpstate?
Again, the kernel already knows the format, so it doesn't need to check.
-hpa
Quoted 11 lines · H. Peter Anvin
Quoted 8 lines · Suresh Siddha
hpa, What is the virtualization problem? Are you referring to perf problem? As you noted, regular non-rt signal handlers won't need this cpuid check. It's
needed only for those who manually look at non-rt signal frames and interpret it.
And also, they can do this check only once and not everytime.No, relying on CPUID and vdso both have implications for virtualization.
can you please elaborate? even in presence of virtualization, appropriate cpuid bits need to be set/visible for application, for xsave/xrstor to work properly.
Quoted 8 lines
I don't think it is ... it's not overkill but rather "underkill"... it's a low-performance solution but it's guaranteed to be safe in the presence of virtualization of all its various ilk. Note that you don't need to be able to *set* the format via
prctl(), just *query* (get) it.Using
prctl()allows us to make this personality-dependent if we ever need to.
Quoted 7 lines
Quoted 4 lines
While restoring from the user, kernel also need to find out what layout the user is passing. So it's bi-directional. I prefer the same mechanism (using cookies/magic numbers etc inaddition to
uc_flagsor cpuid checks) to interpret the fpstate for both user/kernel.No, it really doesn't: the kernel only needs to be able to read the same format as it itself wrote.
But user can potentially change the _fpstate pointer in sigcontext struct.
Quoted 9 lines
Quoted 7 lines
ARM also seem to be using similar things while extending their
ucontext_t, with out other kernel interfaces to indicate the layout.BTW, how come 32bit kernel doesn't have the
X86_FXSR_MAGICchecks, while restoring
the extended fxsave data from_fpstate?Again, the kernel already knows the format, so it doesn't need to check.
What happens with some old applications which change the _fpstate pointer. they may or may not be fxsave aware...
thanks,
suresh
H. Peter Anvin
reviewerQuoted 5 lines · Suresh Siddha
can you please elaborate? even in presence of virtualization, appropriate cpuid bits need to be set/visible for application, for xsave/xrstor to work properly.
For many paravirtualization solutions, CPUID "leak" from the hypervisor.
The fact that CPUID cannot be disabled (made ring 0 only) is a major
flaw in the architecture.
Therefore, relying on CPUID is too dangerous.
Quoted 11 lines
Quoted 9 lines
I don't think it is ... it's not overkill but rather "underkill"... it's a low-performance solution but it's guaranteed to be safe in the presence of virtualization of all its various ilk. Note that you don't need to be able to *set* the format via
prctl(), just *query* (get) it.Using
prctl()allows us to make this personality-dependent if we ever need to.Quoted 4 lines
While restoring from the user, kernel also need to find out what layout the user is passing. So it's bi-directional. I prefer the same mechanism (using cookies/magic numbers etc inaddition to
uc_flagsor cpuid checks) to interpret the fpstate for both user/kernel.No, it really doesn't: the kernel only needs to be able to read the same format as it itself wrote.
But user can potentially change the
_fpstatepointer in sigcontext struct.
If so, they get what they bargained for... I am not even sure the kernel will successfully clean up the stack frame if they do that. I don't think it has ever been supported doing that, and as you have correctly pointed out, we don't check the magic number, so if we had had offenders we ought to have smoked them out a long time ago.
Quoted 9 lines
Quoted 6 lines
Quoted 5 lines
ARM also seem to be using similar things while extending their
ucontext_t, with out other kernel interfaces to indicate the layout.BTW, how come 32bit kernel doesn't have the
X86_FXSR_MAGICchecks, while restoring the extended fxsave data from_fpstate?Again, the kernel already knows the format, so it doesn't need to check.
What happens with some old applications which change the
_fpstatepointer. they may or may not be fxsave aware...
That is not, and has never been, supported.
-hpa
Quoted 4 lines · H. Peter Anvin
Quoted 1 line
But user can potentially change the
_fpstatepointer in sigcontext struct.If so, they get what they bargained for... I am not even sure the kernel will successfully clean up the stack frame if they do that.
Why would that be a problem? The stack is defined by the user's SP, which is in the integer state part of the sigframe. We do a sigreturn(), reload SP/PC/etc, and off we go. Where fpstate pointed to doesn't matter, as long as it was NULL or a valid fpstate image.
Quoted 7 lines · H. Peter Anvin
Quoted 5 lines · Suresh Siddha
can you please elaborate? even in presence of virtualization, appropriate cpuid bits need to be set/visible for application, for xsave/xrstor to work properly.
Quoted 5 lines
For many paravirtualization solutions, CPUID "leak" from the hypervisor.
The fact that CPUID cannot be disabled (made ring 0 only) is a major
flaw in the architecture.Therefore, relying on CPUID is too dangerous.
hmm.. so the kernel needs to export all the cpuid info (that the kernel enables and supports) to the user through some mechanism then?
atleast in the xsave case, hypervisor can completely control the OSXSAVE flag. I am still not convinced whether I need to add prctl() to indicate the layout. If I have to add, then it should not just
be about whether xsave information is included in _fpstate or not, it should also be about the whole cpuid information provided by the xsave architecture. Because the user potentially needs all that information, to make sense out of the data layout included in the extended state area.
thanks,
suresh
Quoted 2 lines
hmm.. so the kernel needs to export all the cpuid info (that the kernel enables and supports) to the user through some mechanism then?
For a cheap interface, we use AT_HWCAP for this. Unfortunately that only covers the first 32 bits of CPUID info. (For another cheap interface, giving all the CPUID bits in the vDSO would be easy.)
For a clunky interface that already exists and is "simple" to use, there is /dev/cpu/0/cpuid now. I wonder if having a device node and opening it too much for applications that consider the vDSO too complex.
Thanks,
Roland
H. Peter Anvin
reviewerQuoted 10 lines · Roland McGrath
Quoted 2 lines
hmm.. so the kernel needs to export all the cpuid info (that the kernel enables and supports) to the user through some mechanism then?
For a cheap interface, we use
AT_HWCAPfor this. Unfortunately that only covers the first 32 bits of CPUID info. (For another cheap interface, giving all the CPUID bits in the vDSO would be easy.)For a clunky interface that already exists and is "simple" to use, there is
/dev/cpu/0/cpuidnow. I wonder if having a device node and opening it too much for applications that consider the vDSO too complex.
I doubt it.
-hpa
Quoted 8 lines · H. Peter Anvin
Quoted 7 lines · Roland McGrath
Quoted 2 lines
hmm.. so the kernel needs to export all the cpuid info (that the kernel enables and supports) to the user through some mechanism then?
For a cheap interface, we use
AT_HWCAPfor this. Unfortunately that only covers the first 32 bits of CPUID info. (For another cheap interface, giving all the CPUID bits in the vDSO would be easy.)
Quoted 5 lines
Quoted 3 lines
For a clunky interface that already exists and is "simple" to use, there is
/dev/cpu/0/cpuidnow. I wonder if having a device node and opening it too much for applications that consider the vDSO too complex.I doubt it.
Ok. If really needed, they can use this interface aswell. But I don't see a need for a new system call / other mechanism, just for xsave purpose. They can rely on cpuid or any other equivalent infrastructure the kernel provides.
thanks,
suresh
H. Peter Anvin
reviewerx86: xsave/xrstor support; ucontext_t extensions
Sorry for not getting back on this for so long.
I have looked at the XSAVE architecture, and it is pretty darn hideous, mostly because it doesn't describe itself in the absence of CPUID information. Given that, it would have been much better if there had been separate invocations of XSAVE for each substate region. On the other hand, normalizing to the current CPU format is probably desirable anyway.
I would like to make this proposal for the signal frames (again, flagged with a uc_flags bit for RT frames):
- The SW-reserved areas at the bottom of the FXSAVE region will be used as follows:
- A magic number (M1)
- A length pointer (L1), giving the length of the entire XSAVE region.
- At the end of the XSAVE region, i.e. at the offset given by the length pointer, we create a secondary structure looking something like this:
- Magic number (M2)
- Descriptor count (DC)
- DC * <EBX, EAX> from CPUID leaf 0Dh
- Possibly a checksum or CRC of this structure
Note that this tail structure will always be the same on a given kernel, so it can be pre-canned at boot time. This tail structure serves two purposes:
- It can be used to verify against truncation of the state. (I.e. if an XSAVE-unaware application tries to copy and save away a state and later restore it, but only copies the first 512 bytes and later just puts a pointer to it.)
- It can be used to verify against an alien state (saved and restored from another CPU, or even just another kernel version with different support.)
If there is a mismatch, we can then take appropriate action:
- No M1 or M2 signature, or L1 or DC are insane:
-> Reinitialize any non-FXSAVE state.
- M1, M2, L1, and DC make sense, but mismatch on DC or descriptor offsets:
-> Do a region-by-region copy in of the state; reinitialize any
regions not provided.
- Mismatch on descriptor sizes:
-> Consider that region corrupt and reinitialize?
The region-by-region copy could of course be used even in the same-CPU case, if there turns out to be a negible performance difference over whole-block copy.
Thoughts?
-hpa
Re: x86: xsave/xrstor support; ucontext_t extensions
Quoted 1 line · H. Peter Anvin
Sorry for not getting back on this for so long.
I thought we had a closure on the previous thread. But no problem. It's better late than never.
Quoted 3 lines
I have looked at the XSAVE architecture, and it is pretty darn hideous, mostly because it doesn't describe itself in the absence of CPUID information.
xsave,xrstor are performance senstive instructions as they are used in process context switches. It doesn't have to describe itself and at any time, one can get all the xsave relevant layout information using cpuid. And when needed, SW can always pass extra information with the xsave image.
Quoted 2 lines
Given that, it would have been much better if there had been separate invocations of XSAVE for each substate region.
It's primarily designed for context switch handling, with fxsave's interoperability in mind. Even though the substates are laidout one after another, xsave/xrstor can operate on individual states based on the edx:eax mask.
Each substate will probably also have different instructions to save/restore/init their substate.
Quoted 3 lines
On the
other hand, normalizing to the current CPU format is probably desirable anyway.
yes.
Quoted 7 lines
I would like to make this proposal for the signal frames (again, flagged with a
uc_flagsbit for RT frames):- The SW-reserved areas at the bottom of the FXSAVE region will be used as follows:
- A magic number (M1)
- A length pointer (L1), giving the length of the entire XSAVE region.
As previously agreed.
Quoted 4 lines
- At the end of the XSAVE region, i.e. at the offset given by the length pointer, we create a secondary structure looking something like this:
- Magic number (M2)
As I mentioned earlier, we can avoid this magic number, by including a pointer (which points to start of the fp and xstate on stack) along with M1.
This will catch any one copying the FP state of the frame but not aware of Xstate.
Quoted 2 lines
- Descriptor count (DC)
- DC * <EBX, EAX> from CPUID leaf 0Dh
As you mentioned, this doesn't change after a kernel boot. So do we really need to save this static information on every signal? (also please see below about the compaction).
Quoted 10 lines
- Possibly a checksum or CRC of this structure
Note that this tail structure will always be the same on a given kernel, so it can be pre-canned at boot time. This tail structure serves two purposes:
- It can be used to verify against truncation of the state. (I.e. if an XSAVE-unaware application tries to copy and save away a state and later restore it, but only copies the first 512 bytes and later just puts a pointer to it.)
As I mentioned above, pointer along with M1 should be enough to catch this?
Quoted 3 lines
- It can be used to verify against an alien state (saved and restored from another CPU, or even just another kernel version with different support.)
Though the xsave layout is extendable, save area is not compacted if some features are not supported by processor and/or system software. This is documented in Vol 2b under "xsave" instruction.
In my RFC, we had the bit mask also saved in the SW-reserved area, which represents the extended state saved in the signal frame. This is in addition to the bit mask represeted by the xstate_bv in the header. xstate_bv indicates the current status (init/non-init) of the sub-states for the bit mask saved in the SW-reserved area.
While restoring, kernel can also use the same bit mask in SW area to restore the state and init the other state not referred by the bit mask.
Quoted 9 lines
If there is a mismatch, we can then take appropriate action:
- No M1 or M2 signature, or L1 or DC are insane:
-> Reinitialize any non-FXSAVE state.- M1, M2, L1, and DC make sense, but mismatch on DC or descriptor offsets:
-> Do a region-by-region copy in of the state; reinitialize any
regions not provided.
Given that the descriptor offsets don't change, we can achieve the same thing with a bit mask representing the state in the xsave layout. xrstor with the approriate bit masks will automatically restore/init the state.
Quoted 6 lines
- Mismatch on descriptor sizes:
-> Consider that region corrupt and reinitialize?The region-by-region copy could of course be used even in the same-CPU case, if there turns out to be a negible performance difference over whole-block copy.
Today in 64bit, we directly do fxsave/fxrstor in and out of user-space for signal handlers. I would like to retain this behavior as much as possible with xsave/xrstor aswell (and at the same time, provide as much information as possible for the user to interpret the signal frame). Bit mask representing the state saved in the xsave image, M1, length and some cookie (pointer along with M1) to detect the image truncation can achieve this. Isn't it?
thanks,
suresh
H. Peter Anvin
reviewerRe: x86: xsave/xrstor support; ucontext_t extensions
Quoted 2 lines · Suresh Siddha
I thought we had a closure on the previous thread. But no problem. It's better late than never.
I apologize. The last two months have been exceptionally tough.
Quoted 5 lines
xsave,xrstor are performance senstive instructions as they are used in process context switches. It doesn't have to describe itself and at any time, one can get all the xsave relevant layout information using cpuid. And when needed, SW can always pass extra information with the xsave image.
Yes, the big problem with it is its monolithic nature (with no realistic alternate instruction.)
Quoted 4 lines
Quoted 1 line
- Magic number (M2)
As I mentioned earlier, we can avoid this magic number, by including a pointer (which points to start of the fp and xstate on stack) along with M1.
As I mentioned before, this introduces a very different constraint, which is a really bad precedent; data shouldn't be dependent on its own location.
Quoted 9 lines
This will catch any one copying the FP state of the frame but not aware of Xstate.
Quoted 2 lines
- Descriptor count (DC)
- DC * <EBX, EAX> from CPUID leaf 0DhAs you mentioned, this doesn't change after a kernel boot. So do we really need to save this static information on every signal? (also please see below about the compaction).
I think given the compaction constraint we're okay with the bitmap plus length of the area.
Quoted 10 lines
Quoted 8 lines
- Possibly a checksum or CRC of this structure
Note that this tail structure will always be the same on a given kernel, so it can be pre-canned at boot time. This tail structure serves two purposes:
- It can be used to verify against truncation of the state. (I.e. if an XSAVE-unaware application tries to copy and save away a state and later restore it, but only copies the first 512 bytes and later just puts a pointer to it.)
As I mentioned above, pointer along with M1 should be enough to catch this?
I think the pointer is a really really bad idea. Even if we don't need the structure I think having a tail magic is the better alternative, and it's also really cheap to do since you have to have the length pointer anyway.
Quoted 8 lines
Quoted 3 lines
- It can be used to verify against an alien state (saved and restored from another CPU, or even just another kernel version with different support.)
Though the xsave layout is extendable, save area is not compacted if some features are not supported by processor and/or system software. This is documented in Vol 2b under "xsave" instruction.
Ah, you're right, my bad. That does make the problem substantially simpler (I somehow read only the second half of the and/or clause, but it's all there.) So, OK, no need for descriptors (he says, as he waits for the architectural shoe to drop, especially in a multivendor environment.)
Quoted 4 lines
Given that the descriptor offsets don't change, we can achieve the same thing with a bit mask representing the state in the xsave layout. xrstor with the approriate bit masks will automatically restore/init the state.
Agreed.
Quoted 11 lines
Quoted 4 lines
- Mismatch on descriptor sizes:
-> Consider that region corrupt and reinitialize?The region-by-region copy could of course be used even in the same-CPU case, if there turns out to be a negible performance difference over whole-block copy.
Today in 64bit, we directly do fxsave/fxrstor in and out of user-space for signal handlers. I would like to retain this behavior as much as possible with xsave/xrstor aswell (and at the same time, provide as much information as possible for the user to interpret the signal frame). Bit mask representing the state saved in the xsave image, M1, length and some cookie (pointer along with M1) to detect the image truncation can achieve this. Isn't it?
If the state is complete, which it of course will be something like 99.9999% of the time, then doing XRSTOR from user space should work just fine. The case of having to stitch up state is clearly an exceptional case, which is not at all performance critical in any way.
-hpa
H. Peter Anvin
reviewerQuoted 6 lines · Suresh Siddha
Quoted 5 lines · H. Peter Anvin
Quoted 4 lines · Suresh Siddha
can you please elaborate? even in presence of virtualization, appropriate cpuid bits need to be set/visible for application, for xsave/xrstor to work properly.
Quoted 8 lines
Quoted 5 lines
For many paravirtualization solutions, CPUID "leak" from the hypervisor.
The fact that CPUID cannot be disabled (made ring 0 only) is a major
flaw in the architecture.Therefore, relying on CPUID is too dangerous.
hmm.. so the kernel needs to export all the cpuid info (that the kernel enables and supports) to the user through some mechanism then?
Not really. Most of the CPUID information doesn't have a OS-dependent portion, but the parts that do cause problems (there are other issues, like the hypervisor wanting to limit the feature set available to the client, but there is no real solution to that, and certainly it would be out of scope for this discussion.)
Quoted 7 lines
atleast in the xsave case, hypervisor can completely control the OSXSAVE flag. I am still not convinced whether I need to add
prctl()to indicate the layout. If I have to add, then it should not just
be about whether xsave information is included in_fpstateor not, it should also be about the whole cpuid information provided by the xsave architecture. Because the user potentially needs all that information, to make sense out of the data layout included in the extended state area.
Agreed that this information is needed, although it probably would be better to leave it in the frame itself; that way at least the rt frames would stand on their own. I'm worried about using the reserved fields since they could be messed up by ptrace, but you could also argue that if you have the ability to trace the process you can do anything else to it; that way we could use a reserved field to signal the presence of the XSAVE information in the frame; I would hope that that XSAVE information would be self-describing (perhaps a linked list of blocks or a separate chain of descriptors.)
In other words, we know of a place to stash the presence flag for rt signal frames, the uc_flags field; we effectively need to find a place to stash the uc_flags field for the non-rt frame.
Quoted 3 lines · you
Hmm, right now it seems this field has a de-facto ABI of being either
0xffff(plain) or0x0000(fxsr). Using other values would confuse at least one application I know of. Sad.
... could you share what application that is? This otherwise would be ideal.
-hpa
Quoted 8 lines · H. Peter Anvin
Quoted 3 lines · you
Hmm, right now it seems this field has a de-facto ABI of being either
0xffff(plain) or0x0000(fxsr). Using other values would confuse at least one application I know of. Sad.... could you share what application that is? This otherwise would be ideal.
It's the virtual machine for the Erlang/OTP concurrent functional language. It's open-source and used extensively for telecom and internet server applications.
The language doesn't allow non-finite FP values, so FP ops must be checked. As an optimisation, the virtual machine groups FP ops into blocks, enables FP exceptions, and has a SIGFPE handler that just records that an FP exception has occurred in a per-thread flag. After each FP block there's a single check for this flag, which if set triggers a language-level "badarith" exception.
In order to resume from an SSE2 exception the SIGFPE handler must update some parts of the sigcontext. But first the handler must detect if the exception came from x87 or SSE2, which requires looking at the mxcsr field, which requires looking at the magic field to detect the fpstate's layout.
The magic field is described as follows in sigcontext.h:
Quoted 7 lines
struct _fpstate { ... unsigned short magic; /* 0xffff = regular FPU data only */ ... };#define
X86_FXSR_MAGIC0x0000
While this in theory allows for other values than -1 and 0 in magic, any such value would be != FXSR_MAGIC and therefore would not trigger the application's "inspect the fxsr layout" logic.
/Mikael
Quoted 7 lines · Mikael Pettersson
Quoted 6 lines · H. Peter Anvin
Quoted 3 lines · you
Hmm, right now it seems this field has a de-facto ABI of being either
0xffff(plain) or0x0000(fxsr). Using other values would confuse at least one application I know of. Sad.
Quoted 6 lines
Quoted 2 lines
... could you share what application that is? This otherwise would be ideal.
It's the virtual machine for the Erlang/OTP concurrent functional language. It's open-source and used extensively for telecom and internet server applications.
I had a few reports over the years of other applications ddoing very weird specific things with the sigframe. So I agree it's fairly important to be as compatible here as possible.
-Andi
Quoted 9 lines · * H. Peter Anvin ([email protected]) wrote:
Quoted 6 lines · Suresh Siddha
hpa, What is the virtualization problem? Are you referring to perf problem? As you noted, regular non-rt signal handlers won't need this cpuid check. It's needed only for those who manually look at non-rt signal frames and interpret it. And also, they can do this check only once and not everytime.
No, relying on CPUID and vdso both have implications for virtualization.
hmm, what implications? cpuid is dealt with already.
Quoted 9 lines · Chris Wright
Quoted 8 lines · * H. Peter Anvin ([email protected]) wrote:
Quoted 6 lines · Suresh Siddha
hpa, What is the virtualization problem? Are you referring to perf problem? As you noted, regular non-rt signal handlers won't need this cpuid check. It's needed only for those who manually look at non-rt signal frames and interpret it. And also, they can do this check only once and not everytime.
Quoted 3 lines
Quoted 1 line
No, relying on CPUID and vdso both have implications for virtualization.
hmm, what implications? cpuid is dealt with already.
By whom?
Case in point: only a few weeks ago, we (as in LKML hackers) tried to debug a user's bug report. Something very strange seemed to be going on. It turned out the user was actually using a virtualisation engine (qemu, not the latest) which presented highly inconsistent cpuid data to the kernel, causing major confusion.
So I agree with hpa. The kernel has decided to use a particular sigframe layout. It should communicate this to user-space in a robust manner that is independent of how the kernel arrived at this decision.
Quoted 4 lines · * Mikael Pettersson ([email protected]) wrote:
Quoted 1 line · Chris Wright
hmm, what implications? cpuid is dealt with already.
By whom?
I was thinking specifically vmx non-root.
thanks,
-chris
H. Peter Anvin
reviewerQuoted 6 lines · Chris Wright
Quoted 3 lines · * Mikael Pettersson ([email protected]) wrote:
Quoted 1 line · Chris Wright
hmm, what implications? cpuid is dealt with already.
By whom?
I was thinking specifically vmx non-root.
You're assuming the presence *and use* of VMX.
-hpa
Quoted 1 line · * H. Peter Anvin ([email protected]) wrote:
You're assuming the presence *and use* of VMX.
Yes, and I see what you're referring to w/out.
Quoted 8 lines · H. Peter Anvin
Quoted 6 lines · Suresh Siddha
hpa, What is the virtualization problem? Are you referring to perf problem? As you noted, regular non-rt signal handlers won't need this cpuid check. It's needed only for those who manually look at non-rt signal frames and interpret it. And also, they can do this check only once and not everytime.
Quoted 8 lines
No, relying on CPUID and vdso both have implications for virtualization.
Quoted 1 line
To me,
prtcl()just seems to be an overkill.I don't think it is ... it's not overkill but rather "underkill"... it's a low-performance solution but it's guaranteed to be safe in the presence of virtualization of all its various ilk. Note that you don't need to be able to *set* the format via
prctl(), just *query* (get) it.
I agree. It works, user-space only needs to query it once, so it's not a big deal that it's a syscall. Admittedly a sigcontext flag would have been better, but that doesn't seem to be viable.
Quoted 7 lines
Quoted 4 lines
While restoring from the user, kernel also need to find out what layout the user is passing. So it's bi-directional. I prefer the same mechanism (using cookies/magic numbers etc inaddition to
uc_flagsor cpuid checks) to interpret the fpstate for both user/kernel.No, it really doesn't: the kernel only needs to be able to read the same format as it itself wrote.
The kernel needs to accept one(*) of the formats it can produce, which is not necessarily what it last produced. It's not inconceivable that user-space will construct sigframes on the fly (to emulate setcontext), or that it will mangle sigframes (e.g. to map non-rt to rt before sigreturn).
(*) The format is determined by which version of sys_sigreturn the user invokes.
/Mikael
H. Peter Anvin
reviewerQuoted 9 lines · Mikael Pettersson
Quoted 8 lines
Quoted 5 lines
While restoring from the user, kernel also need to find out what layout the user is passing. So it's bi-directional. I prefer the same mechanism (using cookies/magic numbers etc inaddition to
uc_flagsor cpuid checks) to interpret the fpstate for both user/kernel.No, it really doesn't: the kernel only needs to be able to read the same format as it itself wrote.
Quoted 8 lines
The kernel needs to accept
one(*)of the formats it can produce, which is not necessarily what it last produced. It's not inconceivable that user-space will construct sigframes on the fly (to emulate setcontext), or that it will mangle sigframes (e.g. to map non-rt to rt before sigreturn).(*) The format is determined by which version of
sys_sigreturnthe user invokes.
No. You CANNOT restore from a frame that doesn't have the full state - you don't have enough information to do so!
-hpa
Quoted 19 lines · H. Peter Anvin
Quoted 18 lines · Mikael Pettersson
Quoted 2 lines
Quoted 2 lines
While restoring from the user, kernel also need to find out what
layout
Quoted 1 line
Quoted 1 line
the user is passing. So it's bi-directional. I prefer the same
mechanism
Quoted 1 line
Quoted 1 line
(using cookies/magic numbers etc inaddition to
uc_flagsor cpuidchecks) to
Quoted 3 lines
Quoted 1 line
interpret the fpstate for both user/kernel.
No, it really doesn't: the kernel only needs to be able to read the
same > format as it itself wrote.
The kernel needs to accept
one(*)of the formats it can produce, which is not necessarily what it last produced. It's not inconceivable that user-space will construct sigframes on the fly (to emulate setcontext), or that it will mangle sigframes (e.g. to map non-rt to rt before sigreturn).
Quoted 6 lines
Quoted 3 lines
(*) The format is determined by which version of
sys_sigreturnthe user invokes.No. You CANNOT restore from a frame that doesn't have the full state - you don't have enough information to do so!
What I was doing in the RFC is: restore the state what ever that was present and init the state that was not present in the stack frame.
Quoted 2 lines
What I was doing in the RFC is: restore the state what ever that was present and init the state that was not present in the stack frame.
That is consistent in spirit with the existing treatment of FPU data. That is, if the sigcontext.fpstate pointer is NULL, the thread's FPU state is reset to default. (And despite what hpa said about being "supported", the facts in the code are that sigreturn just follows the sigcontext.fpstate pointer, whatever it is. On 32-bit, the pointer is NULL in the context saved when the thread had not used the FPU, so modifying the sigcontext to include FP state when it didn't before requires putting in some user-chosen pointer. There in fact may well be existing code that does user-level coroutine switching using sigreturn and relies on this, for all we know.)
Thanks,
Roland
H. Peter Anvin
reviewerQuoted 14 lines · Roland McGrath
Quoted 2 lines
What I was doing in the RFC is: restore the state what ever that was present and init the state that was not present in the stack frame.
That is consistent in spirit with the existing treatment of FPU data. That is, if the sigcontext.fpstate pointer is NULL, the thread's FPU state is reset to default. (And despite what hpa said about being "supported", the facts in the code are that sigreturn just follows the sigcontext.fpstate pointer, whatever it is. On 32-bit, the pointer is NULL in the context saved when the thread had not used the FPU, so modifying the sigcontext to include FP state when it didn't before requires putting in some user-chosen pointer. There in fact may well be existing code that does user-level coroutine switching using sigreturn and relies on this, for all we know.)
Okay. Pretty much what it comes down to is that there is no ideal solution. Thus, we're trying to explore the potential tradeoffs. The scenario you describe above will crash horribly for a non-FXSAVE aware application running on an FXSAVE kernel.
Either way, there has been a long time since, and new bad applications have obviously emerged, partially "assisted" by our propensity to not document, and the deep gulf between our kernel and userspace developers.
Let's try another strawman on for size:
- It is clear it is desirable not just for the frame itself but for the fpstate to be self-describing.
- Thus, let's put a magic cookie in one of the reserved fields at the end of the FXSAVE region, and make sure it is long enough to be unlikely to pop up randomly; as well as another magic cookie outside the FXSAVE region.
- The signal delivery code will write the cookie (or zero, for !XSAVE) regardless of any crap ptrace might have written into it.
- We will ALSO set bit 0 in uc_flags for RT sigframes as an additional assurance.
- We will introduce at least a 32-bit field for future use, to be written unconditionally zero for now. We don't want to have to go through this particular torture yet again.
- The XSAVE state beyond the FXSAVE region needs to be self-describing.
This may mean adding information not provided by the hardware.
Furthermore, it must be possible for userspace to know the length of the frame, even if it doesn't understand its detailed contents.
None of this is foolproof on older kernels -- there simply *IS* no option for older kernels that is 100% guaranteed, thanks to various assumptions made and design decisions taken over the years. There are a couple of failure scenarious here:
- XSAVE-aware application running on pre-XSAVE kernel:
Such an application will be aware that the XSAVE information may not exist, but needs to know (with high probability) that it isn't present. We have CPUID.OSXSAVE, the uc_flags bit, and the magic cookie to help here. ptrace can introduce the magic cookie falsely into the state, but ptrace can introduce all kinds of failures; either way they would (probablistically) not see the *second* cookie.
The fact that 64-bit kernels don't clear the unused fields is of less concern, since 64-bit kernels get the uc_flags field.
- Pre-XSAVE application running on XSAVE kernel with XSAVE enabled:
Here we have the potential for all kinds of corrupt state, including userspace trying to save away the state and load it later, not knowing the proper size of it. Worse, some sick person might try to save and restore state from different hosts, with potential for all kinds of mayhem.
The saved state, if copied from the original, would contain the first cookie but not the second cookie.
Again, the use of two cookies here adds some amount of assurance; but that again amounts to probabilistic failure detection. However, I personally don't see any way to avoid that scenario at all.
-hpa
Quoted 16 lines · H. Peter Anvin
Quoted 14 lines · Roland McGrath
Quoted 2 lines
What I was doing in the RFC is: restore the state what ever that was present and init the state that was not present in the stack frame.
That is consistent in spirit with the existing treatment of FPU data. That is, if the sigcontext.fpstate pointer is NULL, the thread's FPU state is reset to default. (And despite what hpa said about being "supported", the facts in the code are that sigreturn just follows the sigcontext.fpstate pointer, whatever it is. On 32-bit, the pointer is NULL in the context saved when the thread had not used the FPU, so modifying the sigcontext to include FP state when it didn't before requires putting in some user-chosen pointer. There in fact may well be existing code that does user-level coroutine switching using sigreturn and relies on this, for all we know.)
Quoted 4 lines
Okay. Pretty much what it comes down to is that there is no ideal solution. Thus, we're trying to explore the potential tradeoffs. The scenario you describe above will crash horribly for a non-FXSAVE aware application running on an FXSAVE kernel.
yes, who ever added fxsave extensions missed this and we def want to handle these kind of scenarios in xsave context.
Quoted 8 lines
Either way, there has been a long time since, and new bad applications have obviously emerged, partially "assisted" by our propensity to not document, and the deep gulf between our kernel and userspace developers.
Let's try another strawman on for size:
- It is clear it is desirable not just for the frame itself but for the fpstate to be self-describing.
Yes.
Quoted 9 lines
- Thus, let's put a magic cookie in one of the reserved fields at the end of the FXSAVE region, and make sure it is long enough to be unlikely to pop up randomly; as well as another magic cookie outside the FXSAVE region.
- The signal delivery code will write the cookie (or zero, for !XSAVE) regardless of any crap ptrace might have written into it.
Quoted 6 lines
- We will ALSO set bit 0 in
uc_flagsfor RT sigframes as an additional assurance.- We will introduce at least a 32-bit field for future use, to be written unconditionally zero for now. We don't want to have to go through this particular torture yet again.
This is exactly what I have been trying to say. CPU folks are going to document that bytes[464..511] of fxsave frame are going to be SW usable. We can use some of these to represent the cookie, size of the xsave frame, state that is saved in the frame etc. And the remaining unused bytes can be cleared to zero for future use.
you say:
Quoted 1 line
as well as another magic cookie outside the FXSAVE region.
Is this to avoid issues with memcpy, who end up copying only fxsave info but not the extended state? We don't need another magic cookie outside the fxsave region, we can include the address of the _fpstate pointer along side of the first cookie in the SW usable portion of the fxsave state.
Quoted 2 lines
- The XSAVE state beyond the FXSAVE region needs to be self-describing. This may mean adding information not provided by the hardware.
In my RFC, I have added size of the xsave, state mask saved in xsave frame. I will move this to the sw usable portion of fxsave. We can add any thing more if desired.
Quoted 2 lines
Furthermore, it must be possible for userspace to know the length of the frame, even if it doesn't understand its detailed contents.
With the above, we are just changing the _fpstate layout (which includes the length). But if we need frame size in the
sigframe layout, we can add it (and it can be done outside the scope of xsave patches).
Quoted 7 lines
None of this is foolproof on older kernels -- there simply *IS* no option for older kernels that is 100% guaranteed, thanks to various assumptions made and design decisions taken over the years. There are a couple of failure scenarious here:
- XSAVE-aware application running on pre-XSAVE kernel:
Quoted 7 lines
Such an application will be aware that the XSAVE information may not exist, but needs to know (with high probability) that it isn't present. We have CPUID.OSXSAVE, the
uc_flagsbit, and the magic cookie to help here. ptrace can introduce the magic cookie falsely into the state, but ptrace can introduce all kinds of failures; either way they would (probablistically) not see the *second* cookie.
Application can use cpuid.OSXSAVE (even in paravirtualization, hypervisors will prevent the leak of cpuid.osxsave for kernels which don't use it) reliably. And also, we have uc_flags (for rt-frame) and other cookies in the SW usable portion of fxsave frame.
In all the cases, kernel should be as graceful as it can be. xsave aware kernel should try to find and restore xsave state and if there is any failure, try to restore just the fpstate and init the rest.
Quoted 11 lines
The fact that 64-bit kernels don't clear the unused fields is of less concern, since 64-bit kernels get the
uc_flagsfield.- Pre-XSAVE application running on XSAVE kernel with XSAVE enabled:
Here we have the potential for all kinds of corrupt state, including userspace trying to save away the state and load it later, not knowing the proper size of it. Worse, some sick person might try to save and restore state from different hosts, with potential for all kinds of mayhem.
Quoted 4 lines
The saved state, if copied from the original, would contain the first cookie but not the second cookie.
Again, the use of two cookies here adds some amount of assurance;
I think the pointer along with the first cookie is enough right? There is no SW usable portion in the xsave layout outside the fxsave area. And for compatibility reasons, its best to keep the xsave layout similar to what the cpu uses.
Quoted 2 lines
but that again amounts to probabilistic failure detection. However, I personally don't see any way to avoid that scenario at all.
In this case, kernel will atleast not corrupt the fxsave state, which the application cares about.
thanks,
suresh
H. Peter Anvin
reviewerQuoted 6 lines · Suresh Siddha
Quoted 6 lines
Quoted 6 lines
The kernel needs to accept
one(*)of the formats it can produce, which is not necessarily what it last produced. It's not inconceivable that user-space will construct sigframes on the fly (to emulate setcontext), or that it will mangle sigframes (e.g. to map non-rt to rt before sigreturn).
Quoted 7 lines
Quoted 4 lines
Quoted 3 lines
(*) The format is determined by which version of
sys_sigreturnthe user invokes.No. You CANNOT restore from a frame that doesn't have the full state - you don't have enough information to do so!
What I was doing in the RFC is: restore the state what ever that was present and init the state that was not present in the stack frame.
Either way, I find it somewhat surprising that the user would invoke a different sys_sigreturn especially if using a restorer function (which gcc always does.)
I really think I need to understand your application better, *especially* in the light of the fact you wouldn't at the moment know how even get the size of the frame.
-hpa
H. Peter Anvin
reviewerQuoted 8 lines · Mikael Pettersson
An ugly workaround could be to start clearing one of these fields, and say that the data there is only valid for kernels >= 2.6.26. (I said it was ugly...)
Or we go back to stashing a flag in
uc_flags(which is kosher), and try to figure out how to mark non-rt sigframes.
Or use the OSXSAVE hack. Let me think about this for some time.
There is also the option of simply using a field guarded by a 64- or 128-bit magic number. It's a bit ugly, but it works.
-hpa
H. Peter Anvin
reviewerQuoted 9 lines · Andi Kleen
Quoted 2 lines
Ok. CPU folks are planning to make some of the bytes at the end of fxsave image, SW usable.
Are they always zeroed in earlier CPUs though? If not that wouldn't work 100% reliably because whatever cookie you put in could have been there before by chance.
I don't see anything in the SDM guaranteeing zeroing.
I'm pretty sure they weren't zeroed by the CPUs. If they weren't zeroed *by the kernel*, there might have been an information leak.
-hpa
Quoted 9 lines · H. Peter Anvin
Quoted 8 lines · Andi Kleen
Quoted 3 lines
Ok. CPU folks are planning to make some of the bytes at the end of fxsave
image, SW usable.Are they always zeroed in earlier CPUs though? If not that wouldn't work 100% reliably because whatever cookie you put in could have been there before by chance.
Quoted 5 lines
Quoted 2 lines
I don't see anything in the SDM guaranteeing zeroing.
I'm pretty sure they weren't zeroed by the CPUs. If they weren't zeroed *by the kernel*, there might have been an information leak.
I don't think there is one. We never copy fxsave completely out of the kernel. x86-64 does FXSAVE directly in/out user space, but the only leak is what there was before.
-Andi
Quoted 3 lines
I don't think there is one. We never copy fxsave completely out of the kernel. x86-64 does FXSAVE directly in/out user space, but the only leak is what there was before.
ptrace/user_regset copies out and in the whole fxsave block from the ptrace caller. (Only the mxcsr word is constrained after copy-in.)
Thanks,
Roland
H. Peter Anvin
reviewerQuoted 6 lines · Roland McGrath
Quoted 3 lines
I don't think there is one. We never copy fxsave completely out of the kernel. x86-64 does FXSAVE directly in/out user space, but the only leak is what there was before.
ptrace/user_regset copies out and in the whole fxsave block from the ptrace caller. (Only the mxcsr word is constrained after copy-in.)
I see two problems with that:
1. potential information leak out of the kernel if the memory area isn't zeroed before the first FXSAVE - I haven't verified if so is the case. This would be a (potentially very serious) security hole.
2. Hidden state in the kernel - this means user space can set nonarchitectural state in the kernel. There are a few risks with that:
a. Malware might use it to hide state.
b. The possibility of using the stability or lack thereof of this
state to extract information about kernel internals and/or provide a covert channel in the presence of hardware changes.
c. It is not certain that future architectures will not have
off-limit fields here, like the equivalent of MXCSR. This is somewhat of a tricky judgement, of course, but it seems safer to me if we would explicitly list the modifiable fields.
Thoughts?
-hpa
Quoted 3 lines
1. potential information leak out of the kernel if the memory area isn't zeroed before the first FXSAVE - I haven't verified if so is the case. This would be a (potentially very serious) security hole.
Not a problem (see init_fpu).
Quoted 4 lines
2. Hidden state in the kernel - this means user space can set nonarchitectural state in the kernel. There are a few risks with that:
a. Malware might use it to hide state.
Meh. You can already use FP reg space when abusing non-FP-using programs (via ptrace or signal frame clobbering). Via ptrace, you can use %db[0-3] without setting %db7 to make them affect hardware. etc, etc.
Quoted 7 lines
b. The possibility of using the stability or lack thereof of this
state to extract information about kernel internals and/or provide a covert channel in the presence of hardware changes.
c. It is not certain that future architectures will not have
off-limit fields here, like the equivalent of MXCSR. This is somewhat of a tricky judgement, of course, but it seems safer to me if we would explicitly list the modifiable fields.
Meh. The status quo is that (aside from initialization) it gets whatever the hardware does. FXRSTOR is an unprivileged instruction. AFAIK the only reason we control the MXCSR value is because we don't want to handle a #GP in context switch. That would happen if reserved bits were set in MXCSR. We already have code to do fxrstor and handle it, which sigreturn uses. We could just use that if it weren't so trivial to keep MXCSR safe--but since it is, why not keep one fewer entry in the exception fixup table?
The hardware people know that it is unprivileged and is used in this way where privileged code uses a data block received from unprivileged code. If they add things that can make the data lead to new kinds of exceptions, they will make it require the OS enable something, just like we already have to set OSFXSR for the MXCSR reserved bits #GP case to be possible.
Any piece of software state we start using in this buffer just has to meet these same expectations. (i.e. if any value could cause lossage to anything but the user's own memory and user-mode CPU state, then we have to police it at sigreturn/user_regset.set time.)
Thanks,
Roland
Quoted 2 lines
AFAIK the only reason we control the MXCSR value is because we don't want to handle a #GP in context switch.
x86-64 actually handles it in context switch, just i386 doesn't.
-Andi