--- old/usr/src/uts/intel/os/sendsig.c	Wed Apr 12 20:33:33 2023
+++ new/usr/src/uts/intel/os/sendsig.c	Wed Apr 12 20:33:33 2023
@@ -31,6 +31,10 @@
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T   */
 /*	All Rights Reserved   */
 
+/*
+ * Copyright 2023 Oxide Computer Company
+ */
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/sysmacros.h>
@@ -112,9 +116,10 @@
  *		<128 bytes of untouched stack space>
  *		<a siginfo_t [optional]>
  *		<a ucontext_t>
- *		<siginfo_t *>
- *		<signal number>
- * new %rsp:	<return address (deliberately invalid)>
+ *		<a ucontext_t's xsave state>
+ *		<siginfo_t *>                             ---+
+ *		<signal number>                              | sigframe
+ * new %rsp:	<return address (deliberately invalid)>   ---+
  *
  * The signal number and siginfo_t pointer are only pushed onto the stack in
  * order to allow stack backtraces.  The actual signal handling code expects the
@@ -130,8 +135,10 @@
 int
 sendsig(int sig, k_siginfo_t *sip, void (*hdlr)())
 {
-	volatile int minstacksz;
-	int newstack;
+	volatile size_t minstacksz;
+	boolean_t newstack;
+	size_t xsave_size;
+	int ret;
 	label_t ljb;
 	volatile caddr_t sp;
 	caddr_t fp;
@@ -171,14 +178,26 @@
 	 * which must be 16-byte aligned. Because of this, for correct
 	 * alignment, sigframe must be a multiple of 8-bytes in length, but
 	 * not 16-bytes. This will place ucontext_t at a nice 16-byte boundary.
+	 *
+	 * When we move onto the xsave state, right now, we don't guarantee any
+	 * alignment of the resulting data, but we will ensure that the
+	 * resulting sp does have proper alignment. This will ensure that the
+	 * guarantee on the ucontex_t is not violated.
 	 */
 
-	/* LINTED: logical expression always true: op "||" */
-	ASSERT((sizeof (struct sigframe) % 16) == 8);
+	CTASSERT((sizeof (struct sigframe) % 16) == 8);
 
 	minstacksz = sizeof (struct sigframe) + SA(sizeof (*uc));
 	if (sip != NULL)
 		minstacksz += SA(sizeof (siginfo_t));
+
+	if (fpu_xsave_enabled()) {
+		xsave_size = SA(fpu_signal_size(lwp));
+		minstacksz += xsave_size;
+	} else {
+		xsave_size = 0;
+	}
+
 	ASSERT((minstacksz & (STACK_ENTRY_ALIGN - 1ul)) == 0);
 
 	/*
@@ -295,16 +314,26 @@
 	} else
 		sip_addr = NULL;
 
+	no_fault();
+
 	/*
-	 * save the current context on the user stack directly after the
-	 * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned,
-	 * and since sizeof (struct sigframe) is 24, this guarantees
-	 * 16-byte alignment for ucontext_t and its %xmm registers.
+	 * Save the current context on the user stack directly after the
+	 * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned, and since
+	 * sizeof (struct sigframe) is 24, this guarantees 16-byte alignment for
+	 * ucontext_t and its %xmm registers. The xsave state part of the
+	 * ucontext_t may be inbetween these two. However, we have ensured that
+	 * the size of the stack space is 16-byte aligned as the actual size may
+	 * vary.
 	 */
-	uc = (ucontext_t *)(sp + sizeof (struct sigframe));
 	tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
-	no_fault();
-	savecontext(tuc, &lwp->lwp_sigoldmask);
+	if (xsave_size != 0) {
+		tuc->uc_xsave = (unsigned long)(sp + sizeof (struct sigframe));
+	}
+	uc = (ucontext_t *)(sp + sizeof (struct sigframe) + xsave_size);
+	ret = savecontext(tuc, &lwp->lwp_sigoldmask, SAVECTXT_F_EXTD |
+	    SAVECTXT_F_ONFAULT);
+	if (ret != 0)
+		goto postfault;
 	if (on_fault(&ljb))
 		goto badstack;
 	copyout_noerr(tuc, uc, sizeof (*tuc));
@@ -378,6 +407,7 @@
 
 badstack:
 	no_fault();
+postfault:
 	if (watched)
 		watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE);
 	if (tuc)
@@ -399,6 +429,7 @@
  * old %esp:
  *		<a siginfo32_t [optional]>
  *		<a ucontext32_t>
+ *		<a ucontext32_t's xsave state>
  *		<pointer to that ucontext32_t>
  *		<pointer to that siginfo32_t>
  *		<signo>
@@ -414,8 +445,10 @@
 int
 sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)())
 {
-	volatile int minstacksz;
-	int newstack;
+	volatile size_t minstacksz;
+	boolean_t newstack;
+	size_t xsave_size;
+	int ret;
 	label_t ljb;
 	volatile caddr_t sp;
 	caddr_t fp;
@@ -434,6 +467,13 @@
 	minstacksz = SA32(sizeof (struct sigframe32)) + SA32(sizeof (*uc));
 	if (sip != NULL)
 		minstacksz += SA32(sizeof (siginfo32_t));
+
+	if (fpu_xsave_enabled()) {
+		xsave_size = SA32(fpu_signal_size(lwp));
+		minstacksz += xsave_size;
+	} else {
+		xsave_size = 0;
+	}
 	ASSERT((minstacksz & (STACK_ALIGN32 - 1)) == 0);
 
 	/*
@@ -540,13 +580,20 @@
 		}
 	} else
 		sip_addr = NULL;
+	no_fault();
 
 	/* save the current context on the user stack */
+	tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
 	fp -= SA32(sizeof (*tuc));
 	uc = (ucontext32_t *)fp;
-	tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
-	no_fault();
-	savecontext32(tuc, &lwp->lwp_sigoldmask);
+	if (xsave_size != 0) {
+		fp -= xsave_size;
+		tuc->uc_xsave = (int32_t)(uintptr_t)fp;
+	}
+	ret = savecontext32(tuc, &lwp->lwp_sigoldmask, SAVECTXT_F_EXTD |
+	    SAVECTXT_F_ONFAULT);
+	if (ret != 0)
+		goto postfault;
 	if (on_fault(&ljb))
 		goto badstack;
 	copyout_noerr(tuc, uc, sizeof (*tuc));
@@ -620,6 +667,7 @@
 
 badstack:
 	no_fault();
+postfault:
 	if (watched)
 		watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE);
 	if (tuc)
