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