xref: /illumos-gate/usr/src/test/os-tests/tests/xsave/fpregs_xbv.c (revision 1e56f352c1c208679012bca47d552e127f5b1072)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2023 Oxide Computer Company
14  */
15 
16 /*
17  * In illumos#15367 we noted that on some CPUs it was possible to get the xsave
18  * state into a place where it has not set components that are used for the x87
19  * and XMM state in the xsave component bit-vector (what we call the
20  * xsh_xstate_bv or xbv for short). This test attempts to create those
21  * situations and then get a ucontext_t to see that we actually have cleared it
22  * out. Because this behavior varies from CPU to CPU (e.g. in the original case
23  * we only saw this on AMD and not Intel), it can be tricky to guarantee we've
24  * recreated this.
25  */
26 
27 #include <err.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <ucontext.h>
31 #include <stdlib.h>
32 
33 int
34 main(void)
35 {
36 	ucontext_t ctx;
37 	upad128_t u, *up;
38 
39 	u._l[0] = 0x1;
40 	u._l[1] = 0x2;
41 	u._l[2] = 0x3;
42 	u._l[3] = 0x4;
43 
44 	/*
45 	 * Load %xmm0 and then lock in the data into the pcb with a call to
46 	 * getcontext(2) which will force an FPU save.
47 	 */
48 	/* BEGIN CSTYLED */
49 	__asm__ __volatile__ ("movdqu %0, %%xmm0" : : "m" (u));
50 	__asm__ __volatile__ ("fldl %0" : : "m" (u));
51 	/* END CSTYLED */
52 	if (getcontext(&ctx) != 0) {
53 		errx(EXIT_FAILURE, "TEST_FAILED: failed to get initial "
54 		    "ucontext");
55 	}
56 
57 	/*
58 	 * Attempt to reset the FPU at this point and then call getcontext. The
59 	 * fninit is for the x87 part. The vzeroall covers all the higher
60 	 * registers and this combined should reset the x87 and xmm regions back
61 	 * to 0. It appears that on some Intel processors, the vzeroall is
62 	 * required to get the XMM set to not be written out as opposed to just
63 	 * doing a pxor or similar.
64 	 */
65 	/* BEGIN CSTYLED */
66         __asm__ __volatile__ ("fninit" : : :);
67         __asm__ __volatile__ ("vzeroall" : : :);
68 	/* END CSTYLED */
69 	if (getcontext(&ctx) != 0) {
70 		errx(EXIT_FAILURE, "TEST_FAILED: failed to get second "
71 		    "ucontext");
72 	}
73 	up = &ctx.uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[0];
74 	if (up->_l[0] != 0 || up->_l[1] != 0 || up->_l[2] != 0 ||
75 	    up->_l[3] != 0) {
76 		errx(EXIT_FAILURE, "TEST FAILED: %%xmm0 was not zero, found: "
77 		    "0x%x 0x%x 0x%x 0x%x", up->_l[3], up->_l[2],
78 		    up->_l[1], up->_l[0]);
79 	}
80 
81 	(void) printf("TEST PASSED: successfully got zeored %%xmm0\n");
82 	return (EXIT_SUCCESS);
83 }
84