Skip to contentSkip to conversation

x86: xsave/xrstor support, ucontext_t extensions

RFC In review Suresh Siddha 6 participants 57 messages May 13, 2008 – Jun 6, 2008 x86

lore
Share & tools
lore
#0 lore raw

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
Index: linux-2.6-x86/arch/x86/kernel/xsave.c
===================================================================
@@ -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();
+	 */
+	asm volatile(".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
Index: linux-2.6-x86/include/asm-x86/processor-flags.h
===================================================================
@@ -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
Index: linux-2.6-x86/arch/x86/kernel/traps_64.c
===================================================================
@@ -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
Index: linux-2.6-x86/include/asm-x86/sigcontext.h
===================================================================
@@ -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
Index: linux-2.6-x86/arch/x86/kernel/Makefile
===================================================================
@@ -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
Index: linux-2.6-x86/include/asm-x86/cpufeature.h
===================================================================
@@ -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
Index: linux-2.6-x86/include/asm-x86/processor.h
===================================================================
@@ -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
Index: linux-2.6-x86/arch/x86/kernel/cpu/feature_names.c
===================================================================
@@ -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
Index: linux-2.6-x86/include/asm-x86/ucontext.h
===================================================================
@@ -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
Index: linux-2.6-x86/include/asm-x86/ia32.h
===================================================================
@@ -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
Index: linux-2.6-x86/include/asm-x86/sigcontext32.h
===================================================================
@@ -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
Index: linux-2.6-x86/arch/x86/kernel/sigframe.h
===================================================================
@@ -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
Index: linux-2.6-x86/arch/x86/kernel/traps_32.c
===================================================================
@@ -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
Index: linux-2.6-x86/arch/x86/kernel/cpu/common.c
===================================================================
@@ -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
#1 lore raw
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.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.

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 -1
 	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 */

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 -0
 	err |= __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

#2 lore raw
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_mcontext changes elsewhere, and you're adding __unused and uc_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_flags is unused and always zero. Could you define a flag bit (e.g. 1) for uc_flags to 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_cntxt to xst_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 _fpstate has 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 _xstate struct is? Is that the size field in the struct xstate_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

#3 lore raw
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_mcontext changes elsewhere, and you're adding __unused and uc_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_flags is unused and always zero. Could you define a flag bit (e.g. 1) for uc_flags to 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 _fpstate as 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_cntxt to xst_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 _fpstate has 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

#4 lore raw
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

#5 lore raw
In reply to Mikael Pettersson
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.

Quoted 9 lines
Quoted 4 lines
Quoted 3 lines

struct _fpstate has 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.

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

#6 lore raw
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 _fpstate has 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) or 0x0000 (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

#7 lore raw
Quoted 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

#8 lore raw
In reply to Mikael Pettersson
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

#9 lore raw
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_t extensions 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

#10 lore raw
In reply to Suresh Siddha
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

#11 lore raw
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

#12 lore raw
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 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

#13 lore raw
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

#14 lore raw
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

#15 lore raw
Quoted 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 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?

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

#16 lore raw
In reply to Suresh Siddha
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 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?

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

#17 lore raw
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

#18 lore raw
Quoted 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

#19 lore raw
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

#20 lore raw
Quoted 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

#21 lore raw
In reply to Roland McGrath
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

#22 lore raw
In reply to H. Peter Anvin
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 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?

Okay, trying to close on this :)

Quoted 7 lines

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.

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

#23 lore raw
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_flag aswell, for extended state presence. Is this good enough?

Okay, trying to close on this :)

Quoted 7 lines

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.

Quoted 8 lines

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 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

#24 lore raw
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.

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_flags or 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_MAGIC checks, while restoring the extended fxsave data from _fpstate?

Again, the kernel already knows the format, so it doesn't need to check.

-hpa

#25 lore raw
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_flags or 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_MAGIC checks, 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

#26 lore raw
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.

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_flags or 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.

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_MAGIC checks, 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...

That is not, and has never been, supported.

-hpa

#27 lore raw
Quoted 4 lines · H. Peter Anvin
Quoted 1 line

But user can potentially change the _fpstate pointer 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.

#28 lore raw
In reply to H. Peter Anvin
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

#29 lore raw
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

#30 lore raw
Quoted 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_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.

I doubt it.

-hpa

#31 lore raw
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_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.)

Quoted 5 lines
Quoted 3 lines

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.

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

#32 lore raw

x86: 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

#33 lore raw

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_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.

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

#34 lore raw

Re: 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 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).

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

#35 lore raw
In reply to Suresh Siddha
Quoted 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 _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.

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) or 0x0000 (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

#36 lore raw
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) or 0x0000 (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_MAGIC 0x0000

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

#37 lore raw
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) or 0x0000 (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

#38 lore raw
In reply to H. Peter Anvin
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.

#39 lore raw
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.

#40 lore raw
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

#41 lore raw
Quoted 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

#42 lore raw
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.

#43 lore raw
In reply to H. Peter Anvin
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_flags or 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

#44 lore raw
Quoted 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_flags or 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_sigreturn the 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

#45 lore raw
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_flags or cpuid

checks) 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_sigreturn the 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.

#46 lore raw
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

#47 lore raw
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.)

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

#48 lore raw
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_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.

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_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.

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_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.

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

#49 lore raw
In reply to Suresh Siddha
Quoted 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_sigreturn the 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

#50 lore raw
In reply to Mikael Pettersson
Quoted 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

#51 lore raw
In reply to Andi Kleen
Quoted 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

#52 lore raw
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

#53 lore raw
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

#54 lore raw
Quoted 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

#55 lore raw
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

#56 lore raw
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