[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Wed Feb 1 10:56:51 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/09f923a839c9
changeset: 319:09f923a839c9
user:      ray at terran.dlink.ua
date:      Wed Feb 01 11:53:18 2012 +0200
description:
Update sys/amd64

diffstat:

 head/sys/amd64/acpica/acpi_switch.S     |   25 ++-
 head/sys/amd64/acpica/acpi_wakecode.S   |    8 +-
 head/sys/amd64/acpica/acpi_wakeup.c     |   16 +-
 head/sys/amd64/amd64/cpu_switch.S       |   32 ++-
 head/sys/amd64/amd64/fpu.c              |  315 ++++++++++++++++++++++++++++---
 head/sys/amd64/amd64/genassym.c         |    4 +-
 head/sys/amd64/amd64/initcpu.c          |    3 +-
 head/sys/amd64/amd64/machdep.c          |  142 +++++++++++--
 head/sys/amd64/amd64/minidump_machdep.c |    6 +-
 head/sys/amd64/amd64/mp_machdep.c       |    6 +-
 head/sys/amd64/amd64/ptrace_machdep.c   |  141 ++++++++++++++
 head/sys/amd64/amd64/sys_machdep.c      |   28 ++-
 head/sys/amd64/amd64/trap.c             |    4 +-
 head/sys/amd64/amd64/uma_machdep.c      |    5 +-
 head/sys/amd64/amd64/vm_machdep.c       |   72 ++++++-
 head/sys/amd64/conf/GENERIC             |    3 +-
 head/sys/amd64/conf/NOTES               |    7 +-
 head/sys/amd64/ia32/ia32_reg.c          |    8 +-
 head/sys/amd64/ia32/ia32_signal.c       |  119 +++++++++--
 head/sys/amd64/include/cpufunc.h        |    2 +-
 head/sys/amd64/include/float.h          |   18 +-
 head/sys/amd64/include/fpu.h            |   77 +++++--
 head/sys/amd64/include/frame.h          |    5 +-
 head/sys/amd64/include/md_var.h         |   12 +-
 head/sys/amd64/include/pcb.h            |    6 +-
 head/sys/amd64/include/pcpu.h           |    4 +-
 head/sys/amd64/include/ptrace.h         |    7 +-
 head/sys/amd64/include/signal.h         |    7 +-
 head/sys/amd64/include/specialreg.h     |   15 +-
 head/sys/amd64/include/sysarch.h        |   14 +-
 head/sys/amd64/include/ucontext.h       |   10 +-
 31 files changed, 958 insertions(+), 163 deletions(-)

diffs (2297 lines):

diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/acpica/acpi_switch.S
--- a/head/sys/amd64/acpica/acpi_switch.S	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/acpica/acpi_switch.S	Wed Feb 01 11:53:18 2012 +0200
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2001 Takanori Watanabe <takawata at jp.freebsd.org>
  * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki at jp.freebsd.org>
- * Copyright (c) 2008-2010 Jung-uk Kim <jkim at FreeBSD.org>
+ * Copyright (c) 2008-2012 Jung-uk Kim <jkim at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/acpica/acpi_switch.S 230830 2012-01-31 17:51:30Z jkim $
  */
 
 #include <machine/asmacros.h>
@@ -95,7 +95,6 @@
 
 	/* Restore CR0 except for FPU mode. */
 	movq	PCB_CR0(%rdi), %rax
-	movq	%rax, %rcx
 	andq	$~(CR0_EM | CR0_TS), %rax
 	movq	%rax, %cr0
 
@@ -146,10 +145,26 @@
 
 	/* Restore FPU state. */
 	fninit
-	fxrstor	PCB_USERFPU(%rdi)
+	movq	WAKEUP_CTX(xsmask), %rax
+	testq	%rax, %rax
+	jz	1f
+	movq	%rax, %rdx
+	shrq	$32, %rdx
+	movl	$XCR0, %ecx
+/*	xsetbv	*/
+	.byte	0x0f, 0x01, 0xd1
+	movq	WAKEUP_CTX(fpusave), %rcx
+/*	xrstor	(%rcx) */
+	.byte	0x0f, 0xae, 0x29
+	jmp	2f
+1:
+	movq	WAKEUP_CTX(fpusave), %rcx
+	fxrstor	(%rcx)
+2:
 
 	/* Reload CR0. */
-	movq	%rcx, %cr0
+	movq	PCB_CR0(%rdi), %rax
+	movq	%rax, %cr0
 
 	/* Restore return address. */
 	movq	PCB_RIP(%rdi), %rax
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/acpica/acpi_wakecode.S
--- a/head/sys/amd64/acpica/acpi_wakecode.S	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/acpica/acpi_wakecode.S	Wed Feb 01 11:53:18 2012 +0200
@@ -2,7 +2,7 @@
  * Copyright (c) 2001 Takanori Watanabe <takawata at jp.freebsd.org>
  * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki at jp.freebsd.org>
  * Copyright (c) 2003 Peter Wemm
- * Copyright (c) 2008-2010 Jung-uk Kim <jkim at FreeBSD.org>
+ * Copyright (c) 2008-2012 Jung-uk Kim <jkim at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/acpica/acpi_wakecode.S 230830 2012-01-31 17:51:30Z jkim $
  */
 
 #include <machine/asmacros.h>
@@ -267,6 +267,8 @@
 	.quad	0
 wakeup_pcb:
 	.quad	0
+wakeup_fpusave:
+	.quad	0
 wakeup_gdt:
 	.word	0
 	.quad	0
@@ -282,6 +284,8 @@
 	.quad	0
 wakeup_sfmask:
 	.quad	0
+wakeup_xsmask:
+	.quad	0
 wakeup_cpu:
 	.long	0
 dummy:
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/acpica/acpi_wakeup.c
--- a/head/sys/amd64/acpica/acpi_wakeup.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/acpica/acpi_wakeup.c	Wed Feb 01 11:53:18 2012 +0200
@@ -2,7 +2,7 @@
  * Copyright (c) 2001 Takanori Watanabe <takawata at jp.freebsd.org>
  * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki at jp.freebsd.org>
  * Copyright (c) 2003 Peter Wemm
- * Copyright (c) 2008-2010 Jung-uk Kim <jkim at FreeBSD.org>
+ * Copyright (c) 2008-2012 Jung-uk Kim <jkim at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/acpica/acpi_wakeup.c 223758 2011-07-04 12:04:52Z attilio $");
+__FBSDID("$FreeBSD: head/sys/amd64/acpica/acpi_wakeup.c 230830 2012-01-31 17:51:30Z jkim $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -45,6 +45,7 @@
 #include <machine/pcb.h>
 #include <machine/pmap.h>
 #include <machine/specialreg.h>
+#include <machine/md_var.h>
 
 #ifdef SMP
 #include <x86/apicreg.h>
@@ -67,8 +68,10 @@
 
 #ifdef SMP
 extern struct pcb	**susppcbs;
+extern void		**suspfpusave;
 #else
 static struct pcb	**susppcbs;
+static void		**suspfpusave;
 #endif
 
 int			acpi_restorecpu(vm_offset_t, struct pcb *);
@@ -105,6 +108,7 @@
 	int		ms;
 
 	WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[cpu]);
+	WAKECODE_FIXUP(wakeup_fpusave, void *, suspfpusave[cpu]);
 	WAKECODE_FIXUP(wakeup_gdt, uint16_t, susppcbs[cpu]->pcb_gdt.rd_limit);
 	WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t,
 	    susppcbs[cpu]->pcb_gdt.rd_base);
@@ -244,6 +248,7 @@
 	load_cr3(KPML4phys);
 
 	if (savectx(susppcbs[0])) {
+		ctx_fpusave(suspfpusave[0]);
 #ifdef SMP
 		if (!CPU_EMPTY(&wakeup_cpus) &&
 		    suspend_cpus(wakeup_cpus) == 0) {
@@ -256,6 +261,7 @@
 		WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
 
 		WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[0]);
+		WAKECODE_FIXUP(wakeup_fpusave, void *, suspfpusave[0]);
 		WAKECODE_FIXUP(wakeup_gdt, uint16_t,
 		    susppcbs[0]->pcb_gdt.rd_limit);
 		WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t,
@@ -333,8 +339,11 @@
 		return (NULL);
 	}
 	susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK);
-	for (i = 0; i < mp_ncpus; i++)
+	suspfpusave = malloc(mp_ncpus * sizeof(void *), M_DEVBUF, M_WAITOK);
+	for (i = 0; i < mp_ncpus; i++) {
 		susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
+		suspfpusave[i] = alloc_fpusave(M_WAITOK);
+	}
 
 	return (wakeaddr);
 }
@@ -377,6 +386,7 @@
 	WAKECODE_FIXUP(wakeup_lstar, uint64_t, rdmsr(MSR_LSTAR));
 	WAKECODE_FIXUP(wakeup_cstar, uint64_t, rdmsr(MSR_CSTAR));
 	WAKECODE_FIXUP(wakeup_sfmask, uint64_t, rdmsr(MSR_SF_MASK));
+	WAKECODE_FIXUP(wakeup_xsmask, uint64_t, xsave_mask);
 
 	/* Build temporary page tables below realmode code. */
 	pt4 = wakeaddr;
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/cpu_switch.S
--- a/head/sys/amd64/amd64/cpu_switch.S	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/cpu_switch.S	Wed Feb 01 11:53:18 2012 +0200
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/amd64/cpu_switch.S 230426 2012-01-21 17:45:27Z kib $
  */
 
 #include <machine/asmacros.h>
@@ -112,16 +112,25 @@
 
 	/* have we used fp, and need a save? */
 	cmpq	%rdi,PCPU(FPCURTHREAD)
-	jne	1f
+	jne	3f
 	movq	PCB_SAVEFPU(%r8),%r8
 	clts
+	cmpl	$0,use_xsave
+	jne	1f
 	fxsave	(%r8)
-	smsw	%ax
+	jmp	2f
+1:	movq	%rdx,%rcx
+	movl	xsave_mask,%eax
+	movl	xsave_mask+4,%edx
+/*	xsave	(%r8) */
+	.byte	0x41,0x0f,0xae,0x20
+	movq	%rcx,%rdx
+2:	smsw	%ax
 	orb	$CR0_TS,%al
 	lmsw	%ax
 	xorl	%eax,%eax
 	movq	%rax,PCPU(FPCURTHREAD)
-1:
+3:
 
 	/* Save is done.  Now fire up new thread. Leave old vmspace. */
 	movq	TD_PCB(%rsi),%r8
@@ -354,10 +363,19 @@
 	sldt	PCB_LDT(%rdi)
 	str	PCB_TR(%rdi)
 
-	clts
-	fxsave	PCB_USERFPU(%rdi)
-	movq	%rsi,%cr0	/* The previous %cr0 is saved in %rsi. */
+2:	movq	%rsi,%cr0	/* The previous %cr0 is saved in %rsi. */
 
 	movl	$1,%eax
 	ret
 END(savectx)
+
+/*
+ * Wrapper around fpusave to care about TS0_CR.
+ */
+ENTRY(ctx_fpusave)
+	movq	%cr0,%rsi
+	clts
+	call	fpusave
+	movq	%rsi,%cr0
+	ret
+END(ctx_fpusave)
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/fpu.c
--- a/head/sys/amd64/amd64/fpu.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/fpu.c	Wed Feb 01 11:53:18 2012 +0200
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/fpu.c 230766 2012-01-30 07:53:33Z kib $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -78,6 +78,41 @@
 				    : : "n" (CR0_TS) : "ax")
 #define	stop_emulating()	__asm __volatile("clts")
 
+static __inline void
+xrstor(char *addr, uint64_t mask)
+{
+	uint32_t low, hi;
+
+	low = mask;
+	hi = mask >> 32;
+	/* xrstor (%rdi) */
+	__asm __volatile(".byte	0x0f,0xae,0x2f" : :
+	    "a" (low), "d" (hi), "D" (addr));
+}
+
+static __inline void
+xsave(char *addr, uint64_t mask)
+{
+	uint32_t low, hi;
+
+	low = mask;
+	hi = mask >> 32;
+	/* xsave (%rdi) */
+	__asm __volatile(".byte	0x0f,0xae,0x27" : :
+	    "a" (low), "d" (hi), "D" (addr) : "memory");
+}
+
+static __inline void
+xsetbv(uint32_t reg, uint64_t val)
+{
+	uint32_t low, hi;
+
+	low = val;
+	hi = val >> 32;
+	__asm __volatile(".byte 0x0f,0x01,0xd1" : :
+	    "c" (reg), "a" (low), "d" (hi));
+}
+
 #else	/* !(__GNUCLIKE_ASM && !lint) */
 
 void	fldcw(u_short cw);
@@ -90,25 +125,106 @@
 void	ldmxcsr(u_int csr);
 void	start_emulating(void);
 void	stop_emulating(void);
+void	xrstor(char *addr, uint64_t mask);
+void	xsave(char *addr, uint64_t mask);
+void	xsetbv(uint32_t reg, uint64_t val);
 
 #endif	/* __GNUCLIKE_ASM && !lint */
 
 #define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_cw)
 #define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_sw)
 
-typedef u_char bool_t;
+CTASSERT(sizeof(struct savefpu) == 512);
+CTASSERT(sizeof(struct xstate_hdr) == 64);
+CTASSERT(sizeof(struct savefpu_ymm) == 832);
+
+/*
+ * This requirement is to make it easier for asm code to calculate
+ * offset of the fpu save area from the pcb address. FPU save area
+ * must by 64-bytes aligned.
+ */
+CTASSERT(sizeof(struct pcb) % XSAVE_AREA_ALIGN == 0);
 
 static	void	fpu_clean_state(void);
 
 SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
     NULL, 1, "Floating point instructions executed in hardware");
 
-static	struct savefpu		fpu_initialstate;
+int use_xsave;			/* non-static for cpu_switch.S */
+uint64_t xsave_mask;		/* the same */
+static	struct savefpu *fpu_initialstate;
+
+void
+fpusave(void *addr)
+{
+
+	if (use_xsave)
+		xsave((char *)addr, xsave_mask);
+	else
+		fxsave((char *)addr);
+}
+
+static void
+fpurestore(void *addr)
+{
+
+	if (use_xsave)
+		xrstor((char *)addr, xsave_mask);
+	else
+		fxrstor((char *)addr);
+}
 
 /*
- * Initialize the floating point unit.  On the boot CPU we generate a
- * clean state that is used to initialize the floating point unit when
- * it is first used by a process.
+ * Enable XSAVE if supported and allowed by user.
+ * Calculate the xsave_mask.
+ */
+static void
+fpuinit_bsp1(void)
+{
+	u_int cp[4];
+	uint64_t xsave_mask_user;
+
+	if ((cpu_feature2 & CPUID2_XSAVE) != 0) {
+		use_xsave = 1;
+		TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
+	}
+	if (!use_xsave)
+		return;
+
+	cpuid_count(0xd, 0x0, cp);
+	xsave_mask = XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
+	if ((cp[0] & xsave_mask) != xsave_mask)
+		panic("CPU0 does not support X87 or SSE: %x", cp[0]);
+	xsave_mask = ((uint64_t)cp[3] << 32) | cp[0];
+	xsave_mask_user = xsave_mask;
+	TUNABLE_ULONG_FETCH("hw.xsave_mask", &xsave_mask_user);
+	xsave_mask_user |= XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE;
+	xsave_mask &= xsave_mask_user;
+}
+
+/*
+ * Calculate the fpu save area size.
+ */
+static void
+fpuinit_bsp2(void)
+{
+	u_int cp[4];
+
+	if (use_xsave) {
+		cpuid_count(0xd, 0x0, cp);
+		cpu_max_ext_state_size = cp[1];
+
+		/*
+		 * Reload the cpu_feature2, since we enabled OSXSAVE.
+		 */
+		do_cpuid(1, cp);
+		cpu_feature2 = cp[2];
+	} else
+		cpu_max_ext_state_size = sizeof(struct savefpu);
+}
+
+/*
+ * Initialize the floating point unit.
  */
 void
 fpuinit(void)
@@ -117,6 +233,20 @@
 	u_int mxcsr;
 	u_short control;
 
+	if (IS_BSP())
+		fpuinit_bsp1();
+
+	if (use_xsave) {
+		load_cr4(rcr4() | CR4_XSAVE);
+		xsetbv(XCR0, xsave_mask);
+	}
+
+	/*
+	 * XCR0 shall be set up before CPU can report the save area size.
+	 */
+	if (IS_BSP())
+		fpuinit_bsp2();
+
 	/*
 	 * It is too early for critical_enter() to work on AP.
 	 */
@@ -127,20 +257,46 @@
 	fldcw(control);
 	mxcsr = __INITIAL_MXCSR__;
 	ldmxcsr(mxcsr);
-	if (PCPU_GET(cpuid) == 0) {
-		fxsave(&fpu_initialstate);
-		if (fpu_initialstate.sv_env.en_mxcsr_mask)
-			cpu_mxcsr_mask = fpu_initialstate.sv_env.en_mxcsr_mask;
-		else
-			cpu_mxcsr_mask = 0xFFBF;
-		bzero(fpu_initialstate.sv_fp, sizeof(fpu_initialstate.sv_fp));
-		bzero(fpu_initialstate.sv_xmm, sizeof(fpu_initialstate.sv_xmm));
-	}
 	start_emulating();
 	intr_restore(saveintr);
 }
 
 /*
+ * On the boot CPU we generate a clean state that is used to
+ * initialize the floating point unit when it is first used by a
+ * process.
+ */
+static void
+fpuinitstate(void *arg __unused)
+{
+	register_t saveintr;
+
+	fpu_initialstate = malloc(cpu_max_ext_state_size, M_DEVBUF,
+	    M_WAITOK | M_ZERO);
+	saveintr = intr_disable();
+	stop_emulating();
+
+	fpusave(fpu_initialstate);
+	if (fpu_initialstate->sv_env.en_mxcsr_mask)
+		cpu_mxcsr_mask = fpu_initialstate->sv_env.en_mxcsr_mask;
+	else
+		cpu_mxcsr_mask = 0xFFBF;
+
+	/*
+	 * The fninit instruction does not modify XMM registers.  The
+	 * fpusave call dumped the garbage contained in the registers
+	 * after reset to the initial state saved.  Clear XMM
+	 * registers file image to make the startup program state and
+	 * signal handler XMM register content predictable.
+	 */
+	bzero(&fpu_initialstate->sv_xmm[0], sizeof(struct xmmacc));
+
+	start_emulating();
+	intr_restore(saveintr);
+}
+SYSINIT(fpuinitstate, SI_SUB_DRIVERS, SI_ORDER_ANY, fpuinitstate, NULL);
+
+/*
  * Free coprocessor (if we have it).
  */
 void
@@ -150,7 +306,7 @@
 	critical_enter();
 	if (curthread == PCPU_GET(fpcurthread)) {
 		stop_emulating();
-		fxsave(PCPU_GET(curpcb)->pcb_save);
+		fpusave(PCPU_GET(curpcb)->pcb_save);
 		start_emulating();
 		PCPU_SET(fpcurthread, 0);
 	}
@@ -423,7 +579,7 @@
 		 * the PCB doesn't contain a clean FPU state.  Explicitly
 		 * load an initial state.
 		 */
-		fxrstor(&fpu_initialstate);
+		fpurestore(fpu_initialstate);
 		if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
 			fldcw(pcb->pcb_initial_fpucw);
 		if (PCB_USER_FPU(pcb))
@@ -432,7 +588,7 @@
 		else
 			set_pcb_flags(pcb, PCB_FPUINITDONE);
 	} else
-		fxrstor(pcb->pcb_save);
+		fpurestore(pcb->pcb_save);
 	critical_exit();
 }
 
@@ -461,15 +617,16 @@
 
 	pcb = td->td_pcb;
 	if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) {
-		bcopy(&fpu_initialstate, &pcb->pcb_user_save,
-		    sizeof(fpu_initialstate));
-		pcb->pcb_user_save.sv_env.en_cw = pcb->pcb_initial_fpucw;
+		bcopy(fpu_initialstate, get_pcb_user_save_pcb(pcb),
+		    cpu_max_ext_state_size);
+		get_pcb_user_save_pcb(pcb)->sv_env.en_cw =
+		    pcb->pcb_initial_fpucw;
 		fpuuserinited(td);
 		return (_MC_FPOWNED_PCB);
 	}
 	critical_enter();
 	if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
-		fxsave(&pcb->pcb_user_save);
+		fpusave(get_pcb_user_save_pcb(pcb));
 		critical_exit();
 		return (_MC_FPOWNED_FPU);
 	} else {
@@ -491,25 +648,78 @@
 		set_pcb_flags(pcb, PCB_FPUINITDONE);
 }
 
+int
+fpusetxstate(struct thread *td, char *xfpustate, size_t xfpustate_size)
+{
+	struct xstate_hdr *hdr, *ehdr;
+	size_t len, max_len;
+	uint64_t bv;
+
+	/* XXXKIB should we clear all extended state in xstate_bv instead ? */
+	if (xfpustate == NULL)
+		return (0);
+	if (!use_xsave)
+		return (EOPNOTSUPP);
+
+	len = xfpustate_size;
+	if (len < sizeof(struct xstate_hdr))
+		return (EINVAL);
+	max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+	if (len > max_len)
+		return (EINVAL);
+
+	ehdr = (struct xstate_hdr *)xfpustate;
+	bv = ehdr->xstate_bv;
+
+	/*
+	 * Avoid #gp.
+	 */
+	if (bv & ~xsave_mask)
+		return (EINVAL);
+	if ((bv & (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE)) !=
+	    (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE))
+		return (EINVAL);
+
+	hdr = (struct xstate_hdr *)(get_pcb_user_save_td(td) + 1);
+
+	hdr->xstate_bv = bv;
+	bcopy(xfpustate + sizeof(struct xstate_hdr),
+	    (char *)(hdr + 1), len - sizeof(struct xstate_hdr));
+
+	return (0);
+}
+
 /*
  * Set the state of the FPU.
  */
-void
-fpusetregs(struct thread *td, struct savefpu *addr)
+int
+fpusetregs(struct thread *td, struct savefpu *addr, char *xfpustate,
+    size_t xfpustate_size)
 {
 	struct pcb *pcb;
+	int error;
 
 	pcb = td->td_pcb;
 	critical_enter();
 	if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
-		fxrstor(addr);
+		error = fpusetxstate(td, xfpustate, xfpustate_size);
+		if (error != 0) {
+			critical_exit();
+			return (error);
+		}
+		bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+		fpurestore(get_pcb_user_save_td(td));
 		critical_exit();
 		set_pcb_flags(pcb, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
 	} else {
 		critical_exit();
-		bcopy(addr, &td->td_pcb->pcb_user_save, sizeof(*addr));
+		error = fpusetxstate(td, xfpustate, xfpustate_size);
+		if (error != 0)
+			return (error);
+		bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
 		fpuuserinited(td);
 	}
+	return (0);
 }
 
 /*
@@ -599,20 +809,62 @@
 DRIVER_MODULE(fpupnp, acpi, fpupnp_driver, fpupnp_devclass, 0, 0);
 #endif	/* DEV_ISA */
 
+static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx",
+    "Kernel contexts for FPU state");
+
+#define	FPU_KERN_CTX_FPUINITDONE 0x01
+
+struct fpu_kern_ctx {
+	struct savefpu *prev;
+	uint32_t flags;
+	char hwstate1[];
+};
+
+struct fpu_kern_ctx *
+fpu_kern_alloc_ctx(u_int flags)
+{
+	struct fpu_kern_ctx *res;
+	size_t sz;
+
+	sz = sizeof(struct fpu_kern_ctx) + XSAVE_AREA_ALIGN +
+	    cpu_max_ext_state_size;
+	res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ?
+	    M_NOWAIT : M_WAITOK) | M_ZERO);
+	return (res);
+}
+
+void
+fpu_kern_free_ctx(struct fpu_kern_ctx *ctx)
+{
+
+	/* XXXKIB clear the memory ? */
+	free(ctx, M_FPUKERN_CTX);
+}
+
+static struct savefpu *
+fpu_kern_ctx_savefpu(struct fpu_kern_ctx *ctx)
+{
+	vm_offset_t p;
+
+	p = (vm_offset_t)&ctx->hwstate1;
+	p = roundup2(p, XSAVE_AREA_ALIGN);
+	return ((struct savefpu *)p);
+}
+
 int
 fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
 {
 	struct pcb *pcb;
 
 	pcb = td->td_pcb;
-	KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save == &pcb->pcb_user_save,
-	    ("mangled pcb_save"));
+	KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
+	    get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
 	ctx->flags = 0;
 	if ((pcb->pcb_flags & PCB_FPUINITDONE) != 0)
 		ctx->flags |= FPU_KERN_CTX_FPUINITDONE;
 	fpuexit(td);
 	ctx->prev = pcb->pcb_save;
-	pcb->pcb_save = &ctx->hwstate;
+	pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
 	set_pcb_flags(pcb, PCB_KERNFPU);
 	clear_pcb_flags(pcb, PCB_FPUINITDONE);
 	return (0);
@@ -629,7 +881,7 @@
 		fpudrop();
 	critical_exit();
 	pcb->pcb_save = ctx->prev;
-	if (pcb->pcb_save == &pcb->pcb_user_save) {
+	if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
 		if ((pcb->pcb_flags & PCB_USERFPUINITDONE) != 0) {
 			set_pcb_flags(pcb, PCB_FPUINITDONE);
 			clear_pcb_flags(pcb, PCB_KERNFPU);
@@ -653,7 +905,8 @@
 	pcb = PCPU_GET(curpcb);
 	KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0,
 	    ("Only kthread may use fpu_kern_thread"));
-	KASSERT(pcb->pcb_save == &pcb->pcb_user_save, ("mangled pcb_save"));
+	KASSERT(pcb->pcb_save == get_pcb_user_save_pcb(pcb),
+	    ("mangled pcb_save"));
 	KASSERT(PCB_USER_FPU(pcb), ("recursive call"));
 
 	set_pcb_flags(pcb, PCB_KERNFPU);
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/genassym.c
--- a/head/sys/amd64/amd64/genassym.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/genassym.c	Wed Feb 01 11:53:18 2012 +0200
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/genassym.c 225475 2011-09-11 16:08:10Z kib $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/genassym.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_compat.h"
 #include "opt_hwpmc_hooks.h"
@@ -156,7 +156,7 @@
 ASSYM(PCB_TSSP, offsetof(struct pcb, pcb_tssp));
 ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save));
 ASSYM(PCB_SAVEFPU_SIZE, sizeof(struct savefpu));
-ASSYM(PCB_USERFPU, offsetof(struct pcb, pcb_user_save));
+ASSYM(PCB_USERFPU, sizeof(struct pcb));
 ASSYM(PCB_SIZE, sizeof(struct pcb));
 ASSYM(PCB_FULL_IRET, PCB_FULL_IRET);
 ASSYM(PCB_DBREGS, PCB_DBREGS);
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/initcpu.c
--- a/head/sys/amd64/amd64/initcpu.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/initcpu.c	Wed Feb 01 11:53:18 2012 +0200
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/initcpu.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_cpu.h"
 
@@ -72,6 +72,7 @@
 u_int	cpu_fxsr;		/* SSE enabled */
 u_int	cpu_mxcsr_mask;		/* Valid bits in mxcsr */
 u_int	cpu_clflush_line_size = 32;
+u_int	cpu_max_ext_state_size;
 
 SYSCTL_UINT(_hw, OID_AUTO, via_feature_rng, CTLFLAG_RD,
 	&via_feature_rng, 0, "VIA RNG feature available in CPU");
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/machdep.c
--- a/head/sys/amd64/amd64/machdep.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/machdep.c 229085 2011-12-31 13:24:53Z gavin $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/machdep.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_atalk.h"
 #include "opt_atpic.h"
@@ -154,8 +154,10 @@
 #define	EFL_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
 
 static void cpu_startup(void *);
-static void get_fpcontext(struct thread *td, mcontext_t *mcp);
-static int  set_fpcontext(struct thread *td, const mcontext_t *mcp);
+static void get_fpcontext(struct thread *td, mcontext_t *mcp,
+    char *xfpusave, size_t xfpusave_len);
+static int  set_fpcontext(struct thread *td, const mcontext_t *mcp,
+    char *xfpustate, size_t xfpustate_len);
 SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
 
 /*
@@ -315,6 +317,8 @@
 	struct sigacts *psp;
 	char *sp;
 	struct trapframe *regs;
+	char *xfpusave;
+	size_t xfpusave_len;
 	int sig;
 	int oonstack;
 
@@ -328,6 +332,14 @@
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_rsp);
 
+	if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) {
+		xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+		xfpusave = __builtin_alloca(xfpusave_len);
+	} else {
+		xfpusave_len = 0;
+		xfpusave = NULL;
+	}
+
 	/* Save user context. */
 	bzero(&sf, sizeof(sf));
 	sf.sf_uc.uc_sigmask = *mask;
@@ -337,7 +349,7 @@
 	sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
 	bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(*regs));
 	sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
-	get_fpcontext(td, &sf.sf_uc.uc_mcontext);
+	get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
 	fpstate_drop(td);
 	sf.sf_uc.uc_mcontext.mc_fsbase = pcb->pcb_fsbase;
 	sf.sf_uc.uc_mcontext.mc_gsbase = pcb->pcb_gsbase;
@@ -348,13 +360,18 @@
 	/* Allocate space for the signal handler context. */
 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
 	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
-		sp = td->td_sigstk.ss_sp +
-		    td->td_sigstk.ss_size - sizeof(struct sigframe);
+		sp = td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
 #if defined(COMPAT_43)
 		td->td_sigstk.ss_flags |= SS_ONSTACK;
 #endif
 	} else
-		sp = (char *)regs->tf_rsp - sizeof(struct sigframe) - 128;
+		sp = (char *)regs->tf_rsp - 128;
+	if (xfpusave != NULL) {
+		sp -= xfpusave_len;
+		sp = (char *)((unsigned long)sp & ~0x3Ful);
+		sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
+	}
+	sp -= sizeof(struct sigframe);
 	/* Align to 16 bytes. */
 	sfp = (struct sigframe *)((unsigned long)sp & ~0xFul);
 
@@ -387,7 +404,10 @@
 	/*
 	 * Copy the sigframe out to the user's stack.
 	 */
-	if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+	if (copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
+	    (xfpusave != NULL && copyout(xfpusave,
+	    (void *)sf.sf_uc.uc_mcontext.mc_xfpustate, xfpusave_len)
+	    != 0)) {
 #ifdef DEBUG
 		printf("process %ld has trashed its stack\n", (long)p->p_pid);
 #endif
@@ -432,6 +452,8 @@
 	struct proc *p;
 	struct trapframe *regs;
 	ucontext_t *ucp;
+	char *xfpustate;
+	size_t xfpustate_len;
 	long rflags;
 	int cs, error, ret;
 	ksiginfo_t ksi;
@@ -490,7 +512,28 @@
 		return (EINVAL);
 	}
 
-	ret = set_fpcontext(td, &ucp->uc_mcontext);
+	if ((uc.uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
+		xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
+		if (xfpustate_len > cpu_max_ext_state_size -
+		    sizeof(struct savefpu)) {
+			uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
+			    p->p_pid, td->td_name, xfpustate_len);
+			return (EINVAL);
+		}
+		xfpustate = __builtin_alloca(xfpustate_len);
+		error = copyin((const void *)uc.uc_mcontext.mc_xfpustate,
+		    xfpustate, xfpustate_len);
+		if (error != 0) {
+			uprintf(
+	"pid %d (%s): sigreturn copying xfpustate failed\n",
+			    p->p_pid, td->td_name);
+			return (error);
+		}
+	} else {
+		xfpustate = NULL;
+		xfpustate_len = 0;
+	}
+	ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate, xfpustate_len);
 	if (ret != 0) {
 		uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n",
 		    p->p_pid, td->td_name, ret);
@@ -1592,6 +1635,7 @@
 	int gsel_tss, x;
 	struct pcpu *pc;
 	struct nmi_pcpu *np;
+	struct xstate_hdr *xhdr;
 	u_int64_t msr;
 	char *env;
 	size_t kstack0_sz;
@@ -1601,7 +1645,6 @@
 	kstack0_sz = thread0.td_kstack_pages * PAGE_SIZE;
 	bzero((void *)thread0.td_kstack, kstack0_sz);
 	physfree += kstack0_sz;
-	thread0.td_pcb = (struct pcb *)(thread0.td_kstack + kstack0_sz) - 1;
 
 	/*
  	 * This may be done better later if it gets more high level
@@ -1650,7 +1693,6 @@
 	physfree += DPCPU_SIZE;
 	PCPU_SET(prvspace, pc);
 	PCPU_SET(curthread, &thread0);
-	PCPU_SET(curpcb, thread0.td_pcb);
 	PCPU_SET(tssp, &common_tss[0]);
 	PCPU_SET(commontssp, &common_tss[0]);
 	PCPU_SET(tss, (struct system_segment_descriptor *)&gdt[GPROC0_SEL]);
@@ -1742,13 +1784,6 @@
 	initializecpu();	/* Initialize CPU registers */
 	initializecpucache();
 
-	/* make an initial tss so cpu can get interrupt stack on syscall! */
-	common_tss[0].tss_rsp0 = thread0.td_kstack +
-	    kstack0_sz - sizeof(struct pcb);
-	/* Ensure the stack is aligned to 16 bytes */
-	common_tss[0].tss_rsp0 &= ~0xFul;
-	PCPU_SET(rsp0, common_tss[0].tss_rsp0);
-
 	/* doublefault stack space, runs on ist1 */
 	common_tss[0].tss_ist1 = (long)&dblfault_stack[sizeof(dblfault_stack)];
 
@@ -1785,6 +1820,25 @@
 	msgbufinit(msgbufp, msgbufsize);
 	fpuinit();
 
+	/*
+	 * Set up thread0 pcb after fpuinit calculated pcb + fpu save
+	 * area size.  Zero out the extended state header in fpu save
+	 * area.
+	 */
+	thread0.td_pcb = get_pcb_td(&thread0);
+	bzero(get_pcb_user_save_td(&thread0), cpu_max_ext_state_size);
+	if (use_xsave) {
+		xhdr = (struct xstate_hdr *)(get_pcb_user_save_td(&thread0) +
+		    1);
+		xhdr->xstate_bv = xsave_mask;
+	}
+	/* make an initial tss so cpu can get interrupt stack on syscall! */
+	common_tss[0].tss_rsp0 = (vm_offset_t)thread0.td_pcb;
+	/* Ensure the stack is aligned to 16 bytes */
+	common_tss[0].tss_rsp0 &= ~0xFul;
+	PCPU_SET(rsp0, common_tss[0].tss_rsp0);
+	PCPU_SET(curpcb, thread0.td_pcb);
+
 	/* transfer to user mode */
 
 	_ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
@@ -2054,7 +2108,7 @@
 	    P_SHOULDSTOP(td->td_proc),
 	    ("not suspended thread %p", td));
 	fpugetregs(td);
-	fill_fpregs_xmm(&td->td_pcb->pcb_user_save, fpregs);
+	fill_fpregs_xmm(get_pcb_user_save_td(td), fpregs);
 	return (0);
 }
 
@@ -2063,7 +2117,7 @@
 set_fpregs(struct thread *td, struct fpreg *fpregs)
 {
 
-	set_fpregs_xmm(fpregs, &td->td_pcb->pcb_user_save);
+	set_fpregs_xmm(fpregs, get_pcb_user_save_td(td));
 	fpuuserinited(td);
 	return (0);
 }
@@ -2114,9 +2168,11 @@
 	mcp->mc_gs = tp->tf_gs;
 	mcp->mc_flags = tp->tf_flags;
 	mcp->mc_len = sizeof(*mcp);
-	get_fpcontext(td, mcp);
+	get_fpcontext(td, mcp, NULL, 0);
 	mcp->mc_fsbase = pcb->pcb_fsbase;
 	mcp->mc_gsbase = pcb->pcb_gsbase;
+	mcp->mc_xfpustate = 0;
+	mcp->mc_xfpustate_len = 0;
 	bzero(mcp->mc_spare, sizeof(mcp->mc_spare));
 	return (0);
 }
@@ -2132,6 +2188,7 @@
 {
 	struct pcb *pcb;
 	struct trapframe *tp;
+	char *xfpustate;
 	long rflags;
 	int ret;
 
@@ -2142,7 +2199,18 @@
 		return (EINVAL);
 	rflags = (mcp->mc_rflags & PSL_USERCHANGE) |
 	    (tp->tf_rflags & ~PSL_USERCHANGE);
-	ret = set_fpcontext(td, mcp);
+	if (mcp->mc_flags & _MC_HASFPXSTATE) {
+		if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
+		    sizeof(struct savefpu))
+			return (EINVAL);
+		xfpustate = __builtin_alloca(mcp->mc_xfpustate_len);
+		ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
+		    mcp->mc_xfpustate_len);
+		if (ret != 0)
+			return (ret);
+	} else
+		xfpustate = NULL;
+	ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
 	if (ret != 0)
 		return (ret);
 	tp->tf_r15 = mcp->mc_r15;
@@ -2180,35 +2248,51 @@
 }
 
 static void
-get_fpcontext(struct thread *td, mcontext_t *mcp)
+get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
+    size_t xfpusave_len)
 {
+	size_t max_len, len;
 
 	mcp->mc_ownedfp = fpugetregs(td);
-	bcopy(&td->td_pcb->pcb_user_save, &mcp->mc_fpstate,
+	bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate,
 	    sizeof(mcp->mc_fpstate));
 	mcp->mc_fpformat = fpuformat();
+	if (!use_xsave || xfpusave_len == 0)
+		return;
+	max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+	len = xfpusave_len;
+	if (len > max_len) {
+		len = max_len;
+		bzero(xfpusave + max_len, len - max_len);
+	}
+	mcp->mc_flags |= _MC_HASFPXSTATE;
+	mcp->mc_xfpustate_len = len;
+	bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
 }
 
 static int
-set_fpcontext(struct thread *td, const mcontext_t *mcp)
+set_fpcontext(struct thread *td, const mcontext_t *mcp, char *xfpustate,
+    size_t xfpustate_len)
 {
 	struct savefpu *fpstate;
+	int error;
 
 	if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
 		return (0);
 	else if (mcp->mc_fpformat != _MC_FPFMT_XMM)
 		return (EINVAL);
-	else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
+	else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) {
 		/* We don't care what state is left in the FPU or PCB. */
 		fpstate_drop(td);
-	else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
+		error = 0;
+	} else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
 	    mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
 		fpstate = (struct savefpu *)&mcp->mc_fpstate;
 		fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
-		fpusetregs(td, fpstate);
+		error = fpusetregs(td, fpstate, xfpustate, xfpustate_len);
 	} else
 		return (EINVAL);
-	return (0);
+	return (error);
 }
 
 void
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/minidump_machdep.c
--- a/head/sys/amd64/amd64/minidump_machdep.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/minidump_machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/minidump_machdep.c 225194 2011-08-26 17:08:22Z jhb $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/minidump_machdep.c 230623 2012-01-27 20:18:31Z kmacy $");
 
 #include "opt_pmap.h"
 #include "opt_watchdog.h"
@@ -41,6 +41,7 @@
 #include <sys/watchdog.h>
 #endif
 #include <vm/vm.h>
+#include <vm/vm_page.h>
 #include <vm/pmap.h>
 #include <machine/atomic.h>
 #include <machine/elf.h>
@@ -75,8 +76,11 @@
 static int
 is_dumpable(vm_paddr_t pa)
 {
+	vm_page_t m;
 	int i;
 
+	if ((m = vm_phys_paddr_to_vm_page(pa)) != NULL)
+		return ((m->flags & PG_NODUMP) == 0);
 	for (i = 0; dump_avail[i] != 0 || dump_avail[i + 1] != 0; i += 2) {
 		if (pa >= dump_avail[i] && pa < dump_avail[i + 1])
 			return (1);
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/mp_machdep.c
--- a/head/sys/amd64/amd64/mp_machdep.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/mp_machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/mp_machdep.c 227309 2011-11-07 15:43:11Z ed $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/mp_machdep.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_cpu.h"
 #include "opt_kstack_pages.h"
@@ -99,7 +99,8 @@
 void *dpcpu;
 
 struct pcb stoppcbs[MAXCPU];
-struct pcb **susppcbs = NULL;
+struct pcb **susppcbs;
+void **suspfpusave;
 
 /* Variables needed for SMP tlb shootdown. */
 vm_offset_t smp_tlb_addr1;
@@ -1422,6 +1423,7 @@
 	cr3 = rcr3();
 
 	if (savectx(susppcbs[cpu])) {
+		ctx_fpusave(suspfpusave[cpu]);
 		wbinvd();
 		CPU_SET_ATOMIC(cpu, &stopped_cpus);
 	} else {
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/ptrace_machdep.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/amd64/amd64/ptrace_machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2011 Konstantin Belousov <kib at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/ptrace_machdep.c 230426 2012-01-21 17:45:27Z kib $");
+
+#include "opt_compat.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/sysent.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+
+static int
+cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data)
+{
+	char *savefpu;
+	int error;
+
+	if (!use_xsave)
+		return (EOPNOTSUPP);
+
+	switch (req) {
+	case PT_GETXSTATE:
+		savefpu = (char *)(get_pcb_user_save_td(td) + 1);
+		error = copyout(savefpu, addr,
+		    cpu_max_ext_state_size - sizeof(struct savefpu));
+		break;
+
+	case PT_SETXSTATE:
+		if (data > cpu_max_ext_state_size - sizeof(struct savefpu)) {
+			error = EINVAL;
+			break;
+		}
+		savefpu = malloc(data, M_TEMP, M_WAITOK);
+		error = copyin(addr, savefpu, data);
+		if (error == 0)
+			error = fpusetxstate(td, savefpu, data);
+		free(savefpu, M_TEMP);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	return (error);
+}
+
+#ifdef COMPAT_FREEBSD32
+#define PT_I386_GETXMMREGS	(PT_FIRSTMACH + 0)
+#define PT_I386_SETXMMREGS	(PT_FIRSTMACH + 1)
+#define PT_I386_GETXSTATE	(PT_FIRSTMACH + 2)
+#define PT_I386_SETXSTATE	(PT_FIRSTMACH + 3)
+
+static int
+cpu32_ptrace(struct thread *td, int req, void *addr, int data)
+{
+	struct savefpu *fpstate;
+	int error;
+
+	switch (req) {
+	case PT_I386_GETXMMREGS:
+		error = copyout(get_pcb_user_save_td(td), addr,
+		    sizeof(*fpstate));
+		break;
+
+	case PT_I386_SETXMMREGS:
+		fpstate = get_pcb_user_save_td(td);
+		error = copyin(addr, fpstate, sizeof(*fpstate));
+		fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask;
+		break;
+
+	case PT_I386_GETXSTATE:
+		error = cpu_ptrace_xstate(td, PT_GETXSTATE, addr, data);
+		break;
+
+	case PT_I386_SETXSTATE:
+		error = cpu_ptrace_xstate(td, PT_SETXSTATE, addr, data);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	return (error);
+}
+#endif
+
+int
+cpu_ptrace(struct thread *td, int req, void *addr, int data)
+{
+	int error;
+
+#ifdef COMPAT_FREEBSD32
+	if (SV_CURPROC_FLAG(SV_ILP32))
+		return (cpu32_ptrace(td, req, addr, data));
+#endif
+
+	switch (req) {
+	case PT_GETXSTATE:
+	case PT_SETXSTATE:
+		error = cpu_ptrace_xstate(td, req, addr, data);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	return (error);
+}
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/sys_machdep.c
--- a/head/sys/amd64/amd64/sys_machdep.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/sys_machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/sys_machdep.c 226498 2011-10-18 07:39:27Z des $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/sys_machdep.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_capsicum.h"
 
@@ -179,6 +179,8 @@
 	uint32_t i386base;
 	uint64_t a64base;
 	struct i386_ioperm_args iargs;
+	struct i386_get_xfpustate i386xfpu;
+	struct amd64_get_xfpustate a64xfpu;
 
 #ifdef CAPABILITY_MODE
 	/*
@@ -195,10 +197,12 @@
 		case I386_SET_FSBASE:
 		case I386_GET_GSBASE:
 		case I386_SET_GSBASE:
+		case I386_GET_XFPUSTATE:
 		case AMD64_GET_FSBASE:
 		case AMD64_SET_FSBASE:
 		case AMD64_GET_GSBASE:
 		case AMD64_SET_GSBASE:
+		case AMD64_GET_XFPUSTATE:
 			break;
 
 		case I386_SET_IOPERM:
@@ -226,6 +230,18 @@
 		    sizeof(struct i386_ioperm_args))) != 0)
 			return (error);
 		break;
+	case I386_GET_XFPUSTATE:
+		if ((error = copyin(uap->parms, &i386xfpu,
+		    sizeof(struct i386_get_xfpustate))) != 0)
+			return (error);
+		a64xfpu.addr = (void *)(uintptr_t)i386xfpu.addr;
+		a64xfpu.len = i386xfpu.len;
+		break;
+	case AMD64_GET_XFPUSTATE:
+		if ((error = copyin(uap->parms, &a64xfpu,
+		    sizeof(struct amd64_get_xfpustate))) != 0)
+			return (error);
+		break;
 	default:
 		break;
 	}
@@ -296,6 +312,16 @@
 		}
 		break;
 
+	case I386_GET_XFPUSTATE:
+	case AMD64_GET_XFPUSTATE:
+		if (a64xfpu.len > cpu_max_ext_state_size -
+		    sizeof(struct savefpu))
+			return (EINVAL);
+		fpugetregs(td);
+		error = copyout((char *)(get_pcb_user_save_td(td) + 1),
+		    a64xfpu.addr, a64xfpu.len);
+		return (error);
+
 	default:
 		error = EINVAL;
 		break;
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/trap.c
--- a/head/sys/amd64/amd64/trap.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/trap.c	Wed Feb 01 11:53:18 2012 +0200
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/trap.c 227399 2011-11-09 18:25:50Z kib $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/trap.c 230426 2012-01-21 17:45:27Z kib $");
 
 /*
  * AMD64 Trap and System call handling
@@ -934,7 +934,7 @@
 	KASSERT(PCB_USER_FPU(td->td_pcb),
 	    ("System call %s returing with kernel FPU ctx leaked",
 	     syscallname(td->td_proc, sa.code)));
-	KASSERT(td->td_pcb->pcb_save == &td->td_pcb->pcb_user_save,
+	KASSERT(td->td_pcb->pcb_save == get_pcb_user_save_td(td),
 	    ("System call %s returning with mangled pcb_save",
 	     syscallname(td->td_proc, sa.code)));
 
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/uma_machdep.c
--- a/head/sys/amd64/amd64/uma_machdep.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/uma_machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/uma_machdep.c 226843 2011-10-27 16:39:17Z alc $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/uma_machdep.c 230623 2012-01-27 20:18:31Z kmacy $");
 
 #include <sys/param.h>
 #include <sys/lock.h>
@@ -65,7 +65,8 @@
 			break;
 	}
 	pa = m->phys_addr;
-	dump_add_page(pa);
+	if ((wait & M_NODUMP) == 0)
+		dump_add_page(pa);
 	va = (void *)PHYS_TO_DMAP(pa);
 	if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0)
 		pagezero(va);
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/amd64/vm_machdep.c
--- a/head/sys/amd64/amd64/vm_machdep.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/amd64/vm_machdep.c	Wed Feb 01 11:53:18 2012 +0200
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/amd64/vm_machdep.c 223758 2011-07-04 12:04:52Z attilio $");
+__FBSDID("$FreeBSD: head/sys/amd64/amd64/vm_machdep.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_isa.h"
 #include "opt_cpu.h"
@@ -90,6 +90,51 @@
 static volatile u_int	cpu_reset_proxy_active;
 #endif
 
+struct savefpu *
+get_pcb_user_save_td(struct thread *td)
+{
+	vm_offset_t p;
+
+	p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
+	    cpu_max_ext_state_size;
+	KASSERT((p % 64) == 0, ("Unaligned pcb_user_save area"));
+	return ((struct savefpu *)p);
+}
+
+struct savefpu *
+get_pcb_user_save_pcb(struct pcb *pcb)
+{
+	vm_offset_t p;
+
+	p = (vm_offset_t)(pcb + 1);
+	return ((struct savefpu *)p);
+}
+
+struct pcb *
+get_pcb_td(struct thread *td)
+{
+	vm_offset_t p;
+
+	p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
+	    cpu_max_ext_state_size - sizeof(struct pcb);
+	return ((struct pcb *)p);
+}
+
+void *
+alloc_fpusave(int flags)
+{
+	struct pcb *res;
+	struct savefpu_ymm *sf;
+
+	res = malloc(cpu_max_ext_state_size, M_DEVBUF, flags);
+	if (use_xsave) {
+		sf = (struct savefpu_ymm *)res;
+		bzero(&sf->sv_xstate.sx_hd, sizeof(sf->sv_xstate.sx_hd));
+		sf->sv_xstate.sx_hd.xstate_bv = xsave_mask;
+	}
+	return (res);
+}
+
 /*
  * Finish a fork operation, with process p2 nearly set up.
  * Copy and update the pcb, set up the stack so that the child
@@ -127,15 +172,16 @@
 	fpuexit(td1);
 
 	/* Point the pcb to the top of the stack */
-	pcb2 = (struct pcb *)(td2->td_kstack +
-	    td2->td_kstack_pages * PAGE_SIZE) - 1;
+	pcb2 = get_pcb_td(td2);
 	td2->td_pcb = pcb2;
 
 	/* Copy td1's pcb */
 	bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
 
 	/* Properly initialize pcb_save */
-	pcb2->pcb_save = &pcb2->pcb_user_save;
+	pcb2->pcb_save = get_pcb_user_save_pcb(pcb2);
+	bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2),
+	    cpu_max_ext_state_size);
 
 	/* Point mdproc and then copy over td1's contents */
 	mdp2 = &p2->p_md;
@@ -310,11 +356,17 @@
 void
 cpu_thread_alloc(struct thread *td)
 {
+	struct pcb *pcb;
+	struct xstate_hdr *xhdr;
 
-	td->td_pcb = (struct pcb *)(td->td_kstack +
-	    td->td_kstack_pages * PAGE_SIZE) - 1;
-	td->td_frame = (struct trapframe *)td->td_pcb - 1;
-	td->td_pcb->pcb_save = &td->td_pcb->pcb_user_save;
+	td->td_pcb = pcb = get_pcb_td(td);
+	td->td_frame = (struct trapframe *)pcb - 1;
+	pcb->pcb_save = get_pcb_user_save_pcb(pcb);
+	if (use_xsave) {
+		xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1);
+		bzero(xhdr, sizeof(*xhdr));
+		xhdr->xstate_bv = xsave_mask;
+	}
 }
 
 void
@@ -387,7 +439,9 @@
 	 */
 	bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
 	clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
-	pcb2->pcb_save = &pcb2->pcb_user_save;
+	pcb2->pcb_save = get_pcb_user_save_pcb(pcb2);
+	bcopy(get_pcb_user_save_td(td0), pcb2->pcb_save,
+	    cpu_max_ext_state_size);
 	set_pcb_flags(pcb2, PCB_FULL_IRET);
 
 	/*
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/conf/GENERIC
--- a/head/sys/amd64/conf/GENERIC	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/conf/GENERIC	Wed Feb 01 11:53:18 2012 +0200
@@ -16,7 +16,7 @@
 # If you are in doubt as to the purpose or necessity of a line, check first
 # in NOTES.
 #
-# $FreeBSD: head/sys/amd64/conf/GENERIC 229997 2012-01-12 00:34:33Z ken $
+# $FreeBSD: head/sys/amd64/conf/GENERIC 230843 2012-01-31 19:38:18Z jimharris $
 
 cpu		HAMMER
 ident		GENERIC
@@ -123,6 +123,7 @@
 device		adw		# Advansys wide SCSI adapters
 device		aic		# Adaptec 15[012]x SCSI adapters, AIC-6[23]60.
 device		bt		# Buslogic/Mylex MultiMaster SCSI adapters
+device		isci		# Intel C600 SAS controller
 
 # ATA/SCSI peripherals
 device		scbus		# SCSI bus (required for ATA/SCSI)
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/conf/NOTES
--- a/head/sys/amd64/conf/NOTES	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/conf/NOTES	Wed Feb 01 11:53:18 2012 +0200
@@ -4,7 +4,7 @@
 # This file contains machine dependent kernel configuration notes.  For
 # machine independent notes, look in /sys/conf/NOTES.
 #
-# $FreeBSD: head/sys/amd64/conf/NOTES 228940 2011-12-28 23:26:58Z delphij $
+# $FreeBSD: head/sys/amd64/conf/NOTES 230843 2012-01-31 19:38:18Z jimharris $
 #
 
 #
@@ -409,6 +409,11 @@
 device		ips
 
 #
+# Intel C600 (Patsburg) integrated SAS controller
+device		isci
+options		ISCI_LOGGING	# enable debugging in isci HAL
+
+#
 # SafeNet crypto driver: can be moved to the MI NOTES as soon as
 # it's tested on a big-endian machine
 #
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/ia32/ia32_reg.c
--- a/head/sys/amd64/ia32/ia32_reg.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/ia32/ia32_reg.c	Wed Feb 01 11:53:18 2012 +0200
@@ -23,11 +23,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/ia32/ia32_reg.c 230426 2012-01-21 17:45:27Z kib $
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/amd64/ia32/ia32_reg.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_compat.h"
 
@@ -155,7 +155,7 @@
 	sv_87 = (struct save87 *)regs;
 	penv_87 = &sv_87->sv_env;
 	fpugetregs(td);
-	sv_fpu = &td->td_pcb->pcb_user_save;
+	sv_fpu = get_pcb_user_save_td(td);
 	penv_xmm = &sv_fpu->sv_env;
 	
 	/* FPU control/status */
@@ -187,7 +187,7 @@
 {
 	struct save87 *sv_87 = (struct save87 *)regs;
 	struct env87 *penv_87 = &sv_87->sv_env;
-	struct savefpu *sv_fpu = &td->td_pcb->pcb_user_save;
+	struct savefpu *sv_fpu = get_pcb_user_save_td(td);
 	struct envxmm *penv_xmm = &sv_fpu->sv_env;
 	int i;
 
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/ia32/ia32_signal.c
--- a/head/sys/amd64/ia32/ia32_signal.c	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/ia32/ia32_signal.c	Wed Feb 01 11:53:18 2012 +0200
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/amd64/ia32/ia32_signal.c 220238 2011-04-01 11:16:29Z kib $");
+__FBSDID("$FreeBSD: head/sys/amd64/ia32/ia32_signal.c 230426 2012-01-21 17:45:27Z kib $");
 
 #include "opt_compat.h"
 
@@ -71,6 +71,7 @@
 #include <compat/freebsd32/freebsd32_signal.h>
 #include <compat/freebsd32/freebsd32_util.h>
 #include <compat/freebsd32/freebsd32_proto.h>
+#include <compat/freebsd32/freebsd32.h>
 #include <compat/ia32/ia32_signal.h>
 #include <machine/psl.h>
 #include <machine/segments.h>
@@ -83,15 +84,15 @@
 #ifdef COMPAT_FREEBSD4
 static void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *);
 #endif
-static void ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp);
-static int ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp);
 
 #define	CS_SECURE(cs)		(ISPL(cs) == SEL_UPL)
 #define	EFL_SECURE(ef, oef)	((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
 
 static void
-ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp)
+ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp,
+    char *xfpusave, size_t xfpusave_len)
 {
+	size_t max_len, len;
 
 	/*
 	 * XXX Format of 64bit and 32bit FXSAVE areas differs. FXSAVE
@@ -100,28 +101,43 @@
 	 * for now, it should be irrelevant for most applications.
 	 */
 	mcp->mc_ownedfp = fpugetregs(td);
-	bcopy(&td->td_pcb->pcb_user_save, &mcp->mc_fpstate,
+	bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate,
 	    sizeof(mcp->mc_fpstate));
 	mcp->mc_fpformat = fpuformat();
+	if (!use_xsave || xfpusave_len == 0)
+		return;
+	max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+	len = xfpusave_len;
+	if (len > max_len) {
+		len = max_len;
+		bzero(xfpusave + max_len, len - max_len);
+	}
+	mcp->mc_flags |= _MC_HASFPXSTATE;
+	mcp->mc_xfpustate_len = len;
+	bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
 }
 
 static int
-ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp)
+ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp,
+    char *xfpustate, size_t xfpustate_len)
 {
+	int error;
 
 	if (mcp->mc_fpformat == _MC_FPFMT_NODEV)
 		return (0);
 	else if (mcp->mc_fpformat != _MC_FPFMT_XMM)
 		return (EINVAL);
-	else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE)
+	else if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) {
 		/* We don't care what state is left in the FPU or PCB. */
 		fpstate_drop(td);
-	else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
+		error = 0;
+	} else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
 	    mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
-		fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate);
+		error = fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate,
+		    xfpustate, xfpustate_len);
 	} else
 		return (EINVAL);
-	return (0);
+	return (error);
 }
 
 /*
@@ -164,10 +180,12 @@
 	mcp->mc_esp = tp->tf_rsp;
 	mcp->mc_ss = tp->tf_ss;
 	mcp->mc_len = sizeof(*mcp);
-	ia32_get_fpcontext(td, mcp);
+	mcp->mc_flags = tp->tf_flags;
+	ia32_get_fpcontext(td, mcp, NULL, 0);
 	mcp->mc_fsbase = pcb->pcb_fsbase;
 	mcp->mc_gsbase = pcb->pcb_gsbase;
-	bzero(mcp->mc_spare1, sizeof(mcp->mc_spare1));
+	mcp->mc_xfpustate = 0;
+	mcp->mc_xfpustate_len = 0;
 	bzero(mcp->mc_spare2, sizeof(mcp->mc_spare2));
 	set_pcb_flags(pcb, PCB_FULL_IRET);
 	return (0);
@@ -183,6 +201,7 @@
 ia32_set_mcontext(struct thread *td, const struct ia32_mcontext *mcp)
 {
 	struct trapframe *tp;
+	char *xfpustate;
 	long rflags;
 	int ret;
 
@@ -191,7 +210,18 @@
 		return (EINVAL);
 	rflags = (mcp->mc_eflags & PSL_USERCHANGE) |
 	    (tp->tf_rflags & ~PSL_USERCHANGE);
-	ret = ia32_set_fpcontext(td, mcp);
+	if (mcp->mc_flags & _MC_IA32_HASFPXSTATE) {
+		if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
+		    sizeof(struct savefpu))
+			return (EINVAL);
+		xfpustate = __builtin_alloca(mcp->mc_xfpustate_len);
+		ret = copyin(PTRIN(mcp->mc_xfpustate), xfpustate,
+		    mcp->mc_xfpustate_len);
+		if (ret != 0)
+			return (ret);
+	} else
+		xfpustate = NULL;
+	ret = ia32_set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
 	if (ret != 0)
 		return (ret);
 	tp->tf_gs = mcp->mc_gs;
@@ -529,6 +559,8 @@
 	struct sigacts *psp;
 	char *sp;
 	struct trapframe *regs;
+	char *xfpusave;
+	size_t xfpusave_len;
 	int oonstack;
 	int sig;
 
@@ -554,6 +586,14 @@
 	regs = td->td_frame;
 	oonstack = sigonstack(regs->tf_rsp);
 
+	if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) {
+		xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu);
+		xfpusave = __builtin_alloca(xfpusave_len);
+	} else {
+		xfpusave_len = 0;
+		xfpusave = NULL;
+	}
+
 	/* Save user context. */
 	bzero(&sf, sizeof(sf));
 	sf.sf_uc.uc_sigmask = *mask;
@@ -582,7 +622,7 @@
 	sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs;
 	sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs;
 	sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
-	ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext);
+	ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
 	fpstate_drop(td);
 	sf.sf_uc.uc_mcontext.mc_fsbase = td->td_pcb->pcb_fsbase;
 	sf.sf_uc.uc_mcontext.mc_gsbase = td->td_pcb->pcb_gsbase;
@@ -590,11 +630,16 @@
 
 	/* Allocate space for the signal handler context. */
 	if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack &&
-	    SIGISMEMBER(psp->ps_sigonstack, sig)) {
-		sp = td->td_sigstk.ss_sp +
-		    td->td_sigstk.ss_size - sizeof(sf);
-	} else
-		sp = (char *)regs->tf_rsp - sizeof(sf);
+	    SIGISMEMBER(psp->ps_sigonstack, sig))
+		sp = td->td_sigstk.ss_sp + td->td_sigstk.ss_size;
+	else
+		sp = (char *)regs->tf_rsp;
+	if (xfpusave != NULL) {
+		sp -= xfpusave_len;
+		sp = (char *)((unsigned long)sp & ~0x3Ful);
+		sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp;
+	}
+	sp -= sizeof(sf);
 	/* Align to 16 bytes. */
 	sfp = (struct ia32_sigframe *)((uintptr_t)sp & ~0xF);
 	PROC_UNLOCK(p);
@@ -626,7 +671,10 @@
 	/*
 	 * Copy the sigframe out to the user's stack.
 	 */
-	if (copyout(&sf, sfp, sizeof(*sfp)) != 0) {
+	if (copyout(&sf, sfp, sizeof(*sfp)) != 0 ||
+	    (xfpusave != NULL && copyout(xfpusave,
+	    PTRIN(sf.sf_uc.uc_mcontext.mc_xfpustate), xfpusave_len)
+	    != 0)) {
 #ifdef DEBUG
 		printf("process %ld has trashed its stack\n", (long)p->p_pid);
 #endif
@@ -812,6 +860,8 @@
 	struct ia32_ucontext uc;
 	struct trapframe *regs;
 	struct ia32_ucontext *ucp;
+	char *xfpustate;
+	size_t xfpustate_len;
 	int cs, eflags, error, ret;
 	ksiginfo_t ksi;
 
@@ -858,9 +908,34 @@
 		return (EINVAL);
 	}
 
-	ret = ia32_set_fpcontext(td, &ucp->uc_mcontext);
-	if (ret != 0)
+	if ((ucp->uc_mcontext.mc_flags & _MC_HASFPXSTATE) != 0) {
+		xfpustate_len = uc.uc_mcontext.mc_xfpustate_len;
+		if (xfpustate_len > cpu_max_ext_state_size -
+		    sizeof(struct savefpu)) {
+			uprintf("pid %d (%s): sigreturn xfpusave_len = 0x%zx\n",
+			    td->td_proc->p_pid, td->td_name, xfpustate_len);
+			return (EINVAL);
+		}
+		xfpustate = __builtin_alloca(xfpustate_len);
+		error = copyin(PTRIN(ucp->uc_mcontext.mc_xfpustate),
+		    xfpustate, xfpustate_len);
+		if (error != 0) {
+			uprintf(
+	"pid %d (%s): sigreturn copying xfpustate failed\n",
+			    td->td_proc->p_pid, td->td_name);
+			return (error);
+		}
+	} else {
+		xfpustate = NULL;
+		xfpustate_len = 0;
+	}
+	ret = ia32_set_fpcontext(td, &ucp->uc_mcontext, xfpustate,
+	    xfpustate_len);
+	if (ret != 0) {
+		uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n",
+		    td->td_proc->p_pid, td->td_name, ret);
 		return (ret);
+	}
 
 	regs->tf_rdi = ucp->uc_mcontext.mc_edi;
 	regs->tf_rsi = ucp->uc_mcontext.mc_esi;
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/cpufunc.h
--- a/head/sys/amd64/include/cpufunc.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/cpufunc.h	Wed Feb 01 11:53:18 2012 +0200
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/amd64/include/cpufunc.h 223796 2011-07-05 18:42:10Z jkim $
+ * $FreeBSD: head/sys/amd64/include/cpufunc.h 230766 2012-01-30 07:53:33Z kib $
  */
 
 /*
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/float.h
--- a/head/sys/amd64/include/float.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/float.h	Wed Feb 01 11:53:18 2012 +0200
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)float.h	7.1 (Berkeley) 5/8/90
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/float.h 230475 2012-01-23 06:36:41Z das $
  */
 
 #ifndef _MACHINE_FLOAT_H_
@@ -55,6 +55,11 @@
 #define FLT_MAX_EXP	128		/* emax */
 #define FLT_MAX		3.40282347E+38F	/* (1-b**(-p))*b**emax */
 #define FLT_MAX_10_EXP	38		/* floor(log10((1-b**(-p))*b**emax)) */
+#if __ISO_C_VISIBLE >= 2011
+#define	FLT_TRUE_MIN	1.40129846E-45F	/* b**(emin-p) */
+#define	FLT_DECIMAL_DIG	9		/* ceil(1+p*log10(b)) */
+#define	FLT_HAS_SUBNORM	1
+#endif /* __ISO_C_VISIBLE >= 2011 */
 
 #define DBL_MANT_DIG	53
 #define DBL_EPSILON	2.2204460492503131E-16
@@ -65,6 +70,11 @@
 #define DBL_MAX_EXP	1024
 #define DBL_MAX		1.7976931348623157E+308
 #define DBL_MAX_10_EXP	308
+#if __ISO_C_VISIBLE >= 2011
+#define	DBL_TRUE_MIN	4.9406564584124654E-324
+#define	DBL_DECIMAL_DIG	17
+#define	DBL_HAS_SUBNORM	1
+#endif /* __ISO_C_VISIBLE >= 2011 */
 
 #define LDBL_MANT_DIG	64
 #define LDBL_EPSILON	1.0842021724855044340E-19L
@@ -75,4 +85,10 @@
 #define LDBL_MAX_EXP	16384
 #define LDBL_MAX	1.1897314953572317650E+4932L
 #define LDBL_MAX_10_EXP	4932
+#if __ISO_C_VISIBLE >= 2011
+#define	LDBL_TRUE_MIN	3.6451995318824746025E-4951L
+#define	LDBL_DECIMAL_DIG 21
+#define	LDBL_HAS_SUBNORM 1
+#endif /* __ISO_C_VISIBLE >= 2011 */
+
 #endif /* _MACHINE_FLOAT_H_ */
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/fpu.h
--- a/head/sys/amd64/include/fpu.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/fpu.h	Wed Feb 01 11:53:18 2012 +0200
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)npx.h	5.3 (Berkeley) 1/18/91
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/fpu.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 /*
@@ -43,45 +43,71 @@
 
 /* Contents of each x87 floating point accumulator */
 struct fpacc87 {
-	u_char	fp_bytes[10];
+	uint8_t	fp_bytes[10];
 };
 
 /* Contents of each SSE extended accumulator */
 struct  xmmacc {
-	u_char	xmm_bytes[16];
+	uint8_t	xmm_bytes[16];
+};
+
+/* Contents of the upper 16 bytes of each AVX extended accumulator */
+struct  ymmacc {
+	uint8_t  ymm_bytes[16];
 };
 
 struct  envxmm {
-	u_int16_t	en_cw;		/* control word (16bits) */
-	u_int16_t	en_sw;		/* status word (16bits) */
-	u_int8_t	en_tw;		/* tag word (8bits) */
-	u_int8_t	en_zero;
-	u_int16_t	en_opcode;	/* opcode last executed (11 bits ) */
-	u_int64_t	en_rip;		/* floating point instruction pointer */
-	u_int64_t	en_rdp;		/* floating operand pointer */
-	u_int32_t	en_mxcsr;	/* SSE sontorol/status register */
-	u_int32_t	en_mxcsr_mask;	/* valid bits in mxcsr */
+	uint16_t	en_cw;		/* control word (16bits) */
+	uint16_t	en_sw;		/* status word (16bits) */
+	uint8_t		en_tw;		/* tag word (8bits) */
+	uint8_t		en_zero;
+	uint16_t	en_opcode;	/* opcode last executed (11 bits ) */
+	uint64_t	en_rip;		/* floating point instruction pointer */
+	uint64_t	en_rdp;		/* floating operand pointer */
+	uint32_t	en_mxcsr;	/* SSE sontorol/status register */
+	uint32_t	en_mxcsr_mask;	/* valid bits in mxcsr */
 };
 
 struct  savefpu {
 	struct	envxmm	sv_env;
 	struct {
 		struct fpacc87	fp_acc;
-		u_char		fp_pad[6];      /* padding */
+		uint8_t		fp_pad[6];      /* padding */
 	} sv_fp[8];
 	struct xmmacc	sv_xmm[16];
-	u_char sv_pad[96];
+	uint8_t sv_pad[96];
 } __aligned(16);
 
+struct xstate_hdr {
+	uint64_t xstate_bv;
+	uint8_t xstate_rsrv0[16];
+	uint8_t	xstate_rsrv[40];
+};
+
+struct savefpu_xstate {
+	struct xstate_hdr sx_hd;
+	struct ymmacc	sx_ymm[16];
+};
+
+struct savefpu_ymm {
+	struct	envxmm	sv_env;
+	struct {
+		struct fpacc87	fp_acc;
+		int8_t		fp_pad[6];      /* padding */
+	} sv_fp[8];
+	struct xmmacc	sv_xmm[16];
+	uint8_t sv_pad[96];
+	struct savefpu_xstate sv_xstate;
+} __aligned(64);
+
 #ifdef _KERNEL
-struct fpu_kern_ctx {
-	struct savefpu hwstate;
-	struct savefpu *prev;
-	uint32_t flags;
-};
-#define	FPU_KERN_CTX_FPUINITDONE 0x01
+
+struct fpu_kern_ctx;
 
 #define	PCB_USER_FPU(pcb) (((pcb)->pcb_flags & PCB_KERNFPU) == 0)
+
+#define	XSAVE_AREA_ALIGN	64
+
 #endif
 
 /*
@@ -114,9 +140,15 @@
 int	fpuformat(void);
 int	fpugetregs(struct thread *td);
 void	fpuinit(void);
-void	fpusetregs(struct thread *td, struct savefpu *addr);
+void	fpusave(void *addr);
+int	fpusetregs(struct thread *td, struct savefpu *addr,
+	    char *xfpustate, size_t xfpustate_size);
+int	fpusetxstate(struct thread *td, char *xfpustate,
+	    size_t xfpustate_size);
 int	fputrap(void);
 void	fpuuserinited(struct thread *td);
+struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int flags);
+void	fpu_kern_free_ctx(struct fpu_kern_ctx *ctx);
 int	fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx,
 	    u_int flags);
 int	fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx);
@@ -124,9 +156,10 @@
 int	is_fpu_kern_thread(u_int flags);
 
 /*
- * Flags for fpu_kern_enter() and fpu_kern_thread().
+ * Flags for fpu_kern_alloc_ctx(), fpu_kern_enter() and fpu_kern_thread().
  */
 #define	FPU_KERN_NORMAL	0x0000
+#define	FPU_KERN_NOWAIT	0x0001
 
 #endif
 
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/frame.h
--- a/head/sys/amd64/include/frame.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/frame.h	Wed Feb 01 11:53:18 2012 +0200
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)frame.h	5.2 (Berkeley) 1/18/91
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/frame.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 #ifndef _MACHINE_FRAME_H_
@@ -81,6 +81,7 @@
 };
 
 #define	TF_HASSEGS	0x1
-/* #define	_MC_HASBASES	0x2 */
+#define	TF_HASBASES	0x2
+#define	TF_HASFPXSTATE	0x4
 
 #endif /* _MACHINE_FRAME_H_ */
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/md_var.h
--- a/head/sys/amd64/include/md_var.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/md_var.h	Wed Feb 01 11:53:18 2012 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/amd64/include/md_var.h 225576 2011-09-15 09:54:07Z kib $
+ * $FreeBSD: head/sys/amd64/include/md_var.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 #ifndef _MACHINE_MD_VAR_H_
@@ -51,6 +51,7 @@
 extern	u_int	cpu_fxsr;
 extern	u_int	cpu_high;
 extern	u_int	cpu_id;
+extern	u_int	cpu_max_ext_state_size;
 extern	u_int	cpu_mxcsr_mask;
 extern	u_int	cpu_procinfo;
 extern	u_int	cpu_procinfo2;
@@ -67,17 +68,23 @@
 extern	int	_ucode32sel;
 extern	int	_ufssel;
 extern	int	_ugssel;
+extern	int	use_xsave;
+extern	uint64_t xsave_mask;
 
 typedef void alias_for_inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
+struct	pcb;
+struct	savefpu;
 struct	thread;
 struct	reg;
 struct	fpreg;
 struct  dbreg;
 struct	dumperinfo;
 
+void	*alloc_fpusave(int flags);
 void	amd64_syscall(struct thread *td, int traced);
 void	busdma_swi(void);
 void	cpu_setregs(void);
+void	ctx_fpusave(void *);
 void	doreti_iret(void) __asm(__STRING(doreti_iret));
 void	doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault));
 void	ld_ds(void) __asm(__STRING(ld_ds));
@@ -105,5 +112,8 @@
 void	setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int ist);
 int	user_dbreg_trap(void);
 void	minidumpsys(struct dumperinfo *);
+struct savefpu *get_pcb_user_save_td(struct thread *td);
+struct savefpu *get_pcb_user_save_pcb(struct pcb *pcb);
+struct pcb *get_pcb_td(struct thread *td);
 
 #endif /* !_MACHINE_MD_VAR_H_ */
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/pcb.h
--- a/head/sys/amd64/include/pcb.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/pcb.h	Wed Feb 01 11:53:18 2012 +0200
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)pcb.h	5.10 (Berkeley) 5/12/91
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/pcb.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 #ifndef _AMD64_PCB_H_
@@ -92,7 +92,8 @@
 	struct amd64tss *pcb_tssp;
 
 	struct savefpu	*pcb_save;
-	struct savefpu	pcb_user_save;
+
+	uint64_t	pcb_pad[2];
 };
 
 #ifdef _KERNEL
@@ -130,6 +131,7 @@
 
 void	makectx(struct trapframe *, struct pcb *);
 int	savectx(struct pcb *);
+
 #endif
 
 #endif /* _AMD64_PCB_H_ */
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/pcpu.h
--- a/head/sys/amd64/include/pcpu.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/pcpu.h	Wed Feb 01 11:53:18 2012 +0200
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/pcpu.h 230260 2012-01-17 07:21:23Z kib $
  */
 
 #ifndef _MACHINE_PCPU_H_
@@ -226,6 +226,8 @@
 }
 #define	curthread		(__curthread())
 
+#define	IS_BSP()	(PCPU_GET(cpuid) == 0)
+
 #else /* !lint || defined(__GNUCLIKE_ASM) && defined(__GNUCLIKE___TYPEOF) */
 
 #error "this file needs to be ported to your compiler"
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/ptrace.h
--- a/head/sys/amd64/include/ptrace.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/ptrace.h	Wed Feb 01 11:53:18 2012 +0200
@@ -27,10 +27,15 @@
  * SUCH DAMAGE.
  *
  *	@(#)ptrace.h	8.1 (Berkeley) 6/11/93
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/ptrace.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 #ifndef _MACHINE_PTRACE_H_
 #define _MACHINE_PTRACE_H_
 
+#define	__HAVE_PTRACE_MACHDEP
+
+#define PT_GETXSTATE	(PT_FIRSTMACH + 0)
+#define PT_SETXSTATE	(PT_FIRSTMACH + 1)
+
 #endif
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/signal.h
--- a/head/sys/amd64/include/signal.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/signal.h	Wed Feb 01 11:53:18 2012 +0200
@@ -28,7 +28,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)signal.h	8.1 (Berkeley) 6/11/93
- * $FreeBSD: head/sys/amd64/include/signal.h 227399 2011-11-09 18:25:50Z kib $
+ * $FreeBSD: head/sys/amd64/include/signal.h 230765 2012-01-30 07:51:52Z kib $
  */
 
 #ifndef _MACHINE_SIGNAL_H_
@@ -99,7 +99,10 @@
 	long	sc_fsbase;
 	long	sc_gsbase;
 
-	long	sc_spare[6];
+	long	sc_xfpustate;
+	long	sc_xfpustate_len;
+
+	long	sc_spare[4];
 };
 #endif /* __BSD_VISIBLE */
 
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/specialreg.h
--- a/head/sys/amd64/include/specialreg.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/specialreg.h	Wed Feb 01 11:53:18 2012 +0200
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)specialreg.h	7.1 (Berkeley) 5/9/91
- * $FreeBSD: head/sys/amd64/include/specialreg.h 222043 2011-05-17 22:36:16Z jkim $
+ * $FreeBSD: head/sys/amd64/include/specialreg.h 230261 2012-01-17 07:23:43Z kib $
  */
 
 #ifndef _MACHINE_SPECIALREG_H_
@@ -66,6 +66,7 @@
 #define	CR4_PCE	0x00000100	/* Performance monitoring counter enable */
 #define	CR4_FXSR 0x00000200	/* Fast FPU save/restore used by OS */
 #define	CR4_XMM	0x00000400	/* enable SIMD/MMX2 to use except 16 */
+#define	CR4_XSAVE 0x00040000	/* XSETBV/XGETBV */
 
 /*
  * Bits in AMD64 special registers.  EFER is 64 bits wide.
@@ -76,6 +77,18 @@
 #define	EFER_NXE 0x000000800	/* PTE No-Execute bit enable (R/W) */
 
 /*
+ * Intel Extended Features registers
+ */
+#define	XCR0	0		/* XFEATURE_ENABLED_MASK register */
+
+#define	XFEATURE_ENABLED_X87	0x00000001
+#define	XFEATURE_ENABLED_SSE	0x00000002
+#define	XFEATURE_ENABLED_AVX	0x00000004
+
+#define	XFEATURE_AVX					\
+    (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE | XFEATURE_ENABLED_AVX)
+
+/*
  * CPUID instruction features register
  */
 #define	CPUID_FPU	0x00000001
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/sysarch.h
--- a/head/sys/amd64/include/sysarch.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/sysarch.h	Wed Feb 01 11:53:18 2012 +0200
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/amd64/include/sysarch.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 /*
@@ -50,12 +50,14 @@
 #define	I386_SET_FSBASE		8
 #define	I386_GET_GSBASE		9
 #define	I386_SET_GSBASE		10
+#define	I386_GET_XFPUSTATE	11
 
 /* Leave space for 0-127 for to avoid translating syscalls */
 #define	AMD64_GET_FSBASE	128
 #define	AMD64_SET_FSBASE	129
 #define	AMD64_GET_GSBASE	130
 #define	AMD64_SET_GSBASE	131
+#define	AMD64_GET_XFPUSTATE	132
 
 struct i386_ldt_args {
 	unsigned int start;
@@ -69,6 +71,16 @@
 	int	enable;
 };
 
+struct i386_get_xfpustate {
+	unsigned int addr;
+	int len;
+};
+
+struct amd64_get_xfpustate {
+	void *addr;
+	int len;
+};
+
 #ifndef _KERNEL
 __BEGIN_DECLS
 int amd64_get_fsbase(void **);
diff -r 0e49bd70bd10 -r 09f923a839c9 head/sys/amd64/include/ucontext.h
--- a/head/sys/amd64/include/ucontext.h	Wed Feb 01 11:53:00 2012 +0200
+++ b/head/sys/amd64/include/ucontext.h	Wed Feb 01 11:53:18 2012 +0200
@@ -26,7 +26,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/amd64/include/ucontext.h 227399 2011-11-09 18:25:50Z kib $
+ * $FreeBSD: head/sys/amd64/include/ucontext.h 230426 2012-01-21 17:45:27Z kib $
  */
 
 #ifndef _MACHINE_UCONTEXT_H_
@@ -37,7 +37,8 @@
  */
 #define	_MC_HASSEGS	0x1
 #define	_MC_HASBASES	0x2
-#define	_MC_FLAG_MASK	(_MC_HASSEGS | _MC_HASBASES)
+#define	_MC_HASFPXSTATE	0x4
+#define	_MC_FLAG_MASK	(_MC_HASSEGS | _MC_HASBASES | _MC_HASFPXSTATE)
 
 typedef struct __mcontext {
 	/*
@@ -93,7 +94,10 @@
 	__register_t	mc_fsbase;
 	__register_t	mc_gsbase;
 
-	long	mc_spare[6];
+	__register_t	mc_xfpustate;
+	__register_t	mc_xfpustate_len;
+
+	long	mc_spare[4];
 } mcontext_t;
 
 #endif /* !_MACHINE_UCONTEXT_H_ */


More information about the Zrouter-src-freebsd mailing list