--- /dev/null	Wed Apr 12 20:33:29 2023
+++ new/usr/src/test/os-tests/tests/xsave/xsave_asm64.S	Wed Apr 12 20:33:29 2023
@@ -0,0 +1,247 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2023 Oxide Computer Company
+ */
+
+	.file	"xsave_asm64.s"
+
+/*
+ * Test utility routines that we need assembler for. 64-bit addition.
+ */
+
+#include <sys/asm_linkage.h>
+#include "xsave_util.h"
+
+#define	GET_FPU_XMM(src, i)	\
+	leaq	(i * XSU_ZMM_U32 * 4)(src), %rax; \
+	movdqu	%xmm##i, (%rax)
+
+#define	GET_FPU_YMM(src, i)	\
+	leaq	(i * XSU_ZMM_U32 * 4)(src), %rax; \
+	vmovdqu	%ymm##i, (%rax)
+
+#define	GET_FPU_ZMM(src, i)	\
+	leaq	(i * XSU_ZMM_U32 * 4)(src), %rax; \
+	vmovdqu64	%zmm##i, (%rax)
+
+#define	GET_MASK(src, i)	\
+	leaq	(0x800 + i * 8)(src), %rax; \
+	kmovq	%k##i, (%rax)
+
+	/*
+	 * void xsu_getfpu(xsu_fpu_t *data, uint32_t type)
+	 *
+	 * Our job is to get the entire contents of the FPU and save it into our
+	 * data structure.
+	 */
+	ENTRY(xsu_getfpu)
+	cmpl	$XSU_XMM, %esi
+	je	get_xmm
+	cmpl	$XSU_YMM, %esi
+	je	get_ymm
+	cmpl	$XSU_ZMM, %esi
+	je	get_zmm
+	call	abort
+get_xmm:
+	GET_FPU_XMM(%rdi, 0)
+	GET_FPU_XMM(%rdi, 1)
+	GET_FPU_XMM(%rdi, 2)
+	GET_FPU_XMM(%rdi, 3)
+	GET_FPU_XMM(%rdi, 4)
+	GET_FPU_XMM(%rdi, 5)
+	GET_FPU_XMM(%rdi, 6)
+	GET_FPU_XMM(%rdi, 7)
+	GET_FPU_XMM(%rdi, 8)
+	GET_FPU_XMM(%rdi, 9)
+	GET_FPU_XMM(%rdi, 10)
+	GET_FPU_XMM(%rdi, 11)
+	GET_FPU_XMM(%rdi, 12)
+	GET_FPU_XMM(%rdi, 13)
+	GET_FPU_XMM(%rdi, 14)
+	GET_FPU_XMM(%rdi, 15)
+	jmp	get_done
+get_ymm:
+	GET_FPU_YMM(%rdi, 0)
+	GET_FPU_YMM(%rdi, 1)
+	GET_FPU_YMM(%rdi, 2)
+	GET_FPU_YMM(%rdi, 3)
+	GET_FPU_YMM(%rdi, 4)
+	GET_FPU_YMM(%rdi, 5)
+	GET_FPU_YMM(%rdi, 6)
+	GET_FPU_YMM(%rdi, 7)
+	GET_FPU_YMM(%rdi, 8)
+	GET_FPU_YMM(%rdi, 9)
+	GET_FPU_YMM(%rdi, 10)
+	GET_FPU_YMM(%rdi, 11)
+	GET_FPU_YMM(%rdi, 12)
+	GET_FPU_YMM(%rdi, 13)
+	GET_FPU_YMM(%rdi, 14)
+	GET_FPU_YMM(%rdi, 15)
+	jmp	get_done
+get_zmm:
+	GET_FPU_ZMM(%rdi, 0)
+	GET_FPU_ZMM(%rdi, 1)
+	GET_FPU_ZMM(%rdi, 2)
+	GET_FPU_ZMM(%rdi, 3)
+	GET_FPU_ZMM(%rdi, 4)
+	GET_FPU_ZMM(%rdi, 5)
+	GET_FPU_ZMM(%rdi, 6)
+	GET_FPU_ZMM(%rdi, 7)
+	GET_FPU_ZMM(%rdi, 8)
+	GET_FPU_ZMM(%rdi, 9)
+	GET_FPU_ZMM(%rdi, 10)
+	GET_FPU_ZMM(%rdi, 11)
+	GET_FPU_ZMM(%rdi, 12)
+	GET_FPU_ZMM(%rdi, 13)
+	GET_FPU_ZMM(%rdi, 14)
+	GET_FPU_ZMM(%rdi, 15)
+	GET_FPU_ZMM(%rdi, 16)
+	GET_FPU_ZMM(%rdi, 17)
+	GET_FPU_ZMM(%rdi, 18)
+	GET_FPU_ZMM(%rdi, 19)
+	GET_FPU_ZMM(%rdi, 20)
+	GET_FPU_ZMM(%rdi, 21)
+	GET_FPU_ZMM(%rdi, 22)
+	GET_FPU_ZMM(%rdi, 23)
+	GET_FPU_ZMM(%rdi, 24)
+	GET_FPU_ZMM(%rdi, 25)
+	GET_FPU_ZMM(%rdi, 25)
+	GET_FPU_ZMM(%rdi, 26)
+	GET_FPU_ZMM(%rdi, 27)
+	GET_FPU_ZMM(%rdi, 28)
+	GET_FPU_ZMM(%rdi, 29)
+	GET_FPU_ZMM(%rdi, 30)
+	GET_FPU_ZMM(%rdi, 31)
+	GET_MASK(%rdi, 0)
+	GET_MASK(%rdi, 1)
+	GET_MASK(%rdi, 2)
+	GET_MASK(%rdi, 3)
+	GET_MASK(%rdi, 4)
+	GET_MASK(%rdi, 5)
+	GET_MASK(%rdi, 6)
+	GET_MASK(%rdi, 7)
+get_done:
+	ret
+	SET_SIZE(xsu_getfpu)
+
+#define	SET_FPU_XMM(src, i)	\
+	leaq	(i * XSU_ZMM_U32 * 4)(src), %rax; \
+	movdqu	(%rax), %xmm##i
+
+#define	SET_FPU_YMM(src, i)	\
+	leaq	(i * XSU_ZMM_U32 * 4)(src), %rax; \
+	vmovdqu	(%rax), %ymm##i
+
+#define	SET_FPU_ZMM(src, i)	\
+	leaq	(i * XSU_ZMM_U32 * 4)(src), %rax; \
+	vmovdqu64	(%rax), %zmm##i
+
+#define	SET_MASK(src, i)	\
+	leaq	(0x800 + i * 8)(src), %rax; \
+	kmovq	(%rax), %k##i
+
+	/*
+	 * void xsu_setfpu(const xsu_fpu_t *data, uint32_t type)
+	 *
+	 * Our job is to override the contents of the FPU with this structure
+	 * that we've been given. The type indicates how much of it to use.
+	 */
+	ENTRY(xsu_setfpu)
+	cmpl	$XSU_XMM, %esi
+	je	set_xmm
+	cmpl	$XSU_YMM, %esi
+	je	set_ymm
+	cmpl	$XSU_ZMM, %esi
+	je	set_zmm
+	call	abort
+set_xmm:
+	SET_FPU_XMM(%rdi, 0)
+	SET_FPU_XMM(%rdi, 1)
+	SET_FPU_XMM(%rdi, 2)
+	SET_FPU_XMM(%rdi, 3)
+	SET_FPU_XMM(%rdi, 4)
+	SET_FPU_XMM(%rdi, 5)
+	SET_FPU_XMM(%rdi, 6)
+	SET_FPU_XMM(%rdi, 7)
+	SET_FPU_XMM(%rdi, 8)
+	SET_FPU_XMM(%rdi, 9)
+	SET_FPU_XMM(%rdi, 10)
+	SET_FPU_XMM(%rdi, 11)
+	SET_FPU_XMM(%rdi, 12)
+	SET_FPU_XMM(%rdi, 13)
+	SET_FPU_XMM(%rdi, 14)
+	SET_FPU_XMM(%rdi, 15)
+	jmp	set_done
+set_ymm:
+	SET_FPU_YMM(%rdi, 0)
+	SET_FPU_YMM(%rdi, 1)
+	SET_FPU_YMM(%rdi, 2)
+	SET_FPU_YMM(%rdi, 3)
+	SET_FPU_YMM(%rdi, 4)
+	SET_FPU_YMM(%rdi, 5)
+	SET_FPU_YMM(%rdi, 6)
+	SET_FPU_YMM(%rdi, 7)
+	SET_FPU_YMM(%rdi, 8)
+	SET_FPU_YMM(%rdi, 9)
+	SET_FPU_YMM(%rdi, 10)
+	SET_FPU_YMM(%rdi, 11)
+	SET_FPU_YMM(%rdi, 12)
+	SET_FPU_YMM(%rdi, 13)
+	SET_FPU_YMM(%rdi, 14)
+	SET_FPU_YMM(%rdi, 15)
+	jmp	set_done
+set_zmm:
+	SET_FPU_ZMM(%rdi, 0)
+	SET_FPU_ZMM(%rdi, 1)
+	SET_FPU_ZMM(%rdi, 2)
+	SET_FPU_ZMM(%rdi, 3)
+	SET_FPU_ZMM(%rdi, 4)
+	SET_FPU_ZMM(%rdi, 5)
+	SET_FPU_ZMM(%rdi, 6)
+	SET_FPU_ZMM(%rdi, 7)
+	SET_FPU_ZMM(%rdi, 8)
+	SET_FPU_ZMM(%rdi, 9)
+	SET_FPU_ZMM(%rdi, 10)
+	SET_FPU_ZMM(%rdi, 11)
+	SET_FPU_ZMM(%rdi, 12)
+	SET_FPU_ZMM(%rdi, 13)
+	SET_FPU_ZMM(%rdi, 14)
+	SET_FPU_ZMM(%rdi, 15)
+	SET_FPU_ZMM(%rdi, 16)
+	SET_FPU_ZMM(%rdi, 17)
+	SET_FPU_ZMM(%rdi, 18)
+	SET_FPU_ZMM(%rdi, 19)
+	SET_FPU_ZMM(%rdi, 20)
+	SET_FPU_ZMM(%rdi, 21)
+	SET_FPU_ZMM(%rdi, 22)
+	SET_FPU_ZMM(%rdi, 23)
+	SET_FPU_ZMM(%rdi, 24)
+	SET_FPU_ZMM(%rdi, 25)
+	SET_FPU_ZMM(%rdi, 25)
+	SET_FPU_ZMM(%rdi, 26)
+	SET_FPU_ZMM(%rdi, 27)
+	SET_FPU_ZMM(%rdi, 28)
+	SET_FPU_ZMM(%rdi, 29)
+	SET_FPU_ZMM(%rdi, 30)
+	SET_FPU_ZMM(%rdi, 31)
+	SET_MASK(%rdi, 0)
+	SET_MASK(%rdi, 1)
+	SET_MASK(%rdi, 2)
+	SET_MASK(%rdi, 3)
+	SET_MASK(%rdi, 4)
+	SET_MASK(%rdi, 5)
+	SET_MASK(%rdi, 6)
+	SET_MASK(%rdi, 7)
+set_done:
+	ret
+	SET_SIZE(xsu_setfpu)
