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 * This test verifies the following: 18 * 19 * o xregs and fpregs report the same content for the xmm registers at least. 20 * o A write to xregs is reflected in reads of fpregs. 21 * o A write to the fpregs is reflected in reads of xregs and doesn't 22 * clobber additional state in xregs. 23 * o A thread in our victim process sees the final state here and can print 24 * that out. 25 * o As a side effect it makes sure that libproc isn't incorrectly caching 26 * register info on handles. 27 * 28 * We use the xsu_dump process of the same bitness as us. 29 */ 30 31 #include <err.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <string.h> 35 36 #include "xsave_util.h" 37 38 static xsu_fpu_t fpu; 39 40 int 41 main(int argc, char *argv[]) 42 { 43 uint32_t seed, hwsup; 44 unsigned long ul; 45 char *eptr; 46 prxregset_t *prx, *cmp_prx; 47 size_t prx_len, cmp_prx_len; 48 xsu_proc_t xp; 49 fpregset_t fpr; 50 51 if (argc != 5) { 52 errx(EXIT_FAILURE, "missing args: <prog> <output file> " 53 "<seed> <func>"); 54 } 55 56 errno = 0; 57 ul = strtoul(argv[3], &eptr, 0); 58 if (errno != 0 || *eptr != '\0') { 59 errx(EXIT_FAILURE, "seed value is bad: %s", argv[3]); 60 } 61 62 #if defined(_LP64) 63 if (ul > UINT32_MAX) { 64 errx(EXIT_FAILURE, "seed %s outside of [0, UINT32_MAX]", 65 argv[3]); 66 } 67 #endif 68 69 seed = (uint32_t)ul; 70 hwsup = xsu_hwsupport(); 71 xsu_fill(&fpu, hwsup, seed); 72 xsu_fpu_to_xregs(&fpu, hwsup, &prx, &prx_len); 73 74 (void) memset(&xp, 0, sizeof (xsu_proc_t)); 75 xp.xp_prog = argv[1]; 76 xp.xp_arg = argv[2]; 77 xp.xp_object = "a.out"; 78 xp.xp_symname = argv[4]; 79 xsu_proc_bkpt(&xp); 80 81 /* 82 * First get the xregs into a reasonable place. 83 */ 84 if (Plwp_setxregs(xp.xp_proc, 1, prx, prx_len) != 0) { 85 err(EXIT_FAILURE, "failed to set target's xregs"); 86 } 87 88 /* 89 * Now that we have that, let's go and get the fpregs. Because of 90 * differences between the 32-bit representation and the xsave state in 91 * the xregs, we stick to different checking in an ILP32 vs. LP64 pieces 92 * of this. 93 */ 94 if (Plwp_getfpregs(xp.xp_proc, 1, &fpr) != 0) { 95 err(EXIT_FAILURE, "failed to get the fp registers"); 96 } 97 98 if (!xsu_fpregs_cmp(&fpr, prx)) { 99 errx(EXIT_FAILURE, "fpregs do not reflect xsave changes!"); 100 } 101 (void) printf("TEST PASSED: fpregs read respects xregs write\n"); 102 103 /* 104 * Override the xmm registers with the known variant of the seed and set 105 * that. Update the xregs data so we can later compare them usefully. 106 */ 107 xsu_fpregset_xmm_set(&fpr, seed + INT32_MAX); 108 xsu_xregs_xmm_set(prx, seed + INT32_MAX); 109 if (Plwp_setfpregs(xp.xp_proc, 1, &fpr) != 0) { 110 err(EXIT_FAILURE, "failed to set fpregs"); 111 } 112 113 if (Plwp_getxregs(xp.xp_proc, 1, &cmp_prx, &cmp_prx_len) != 0) { 114 err(EXIT_FAILURE, "failed to get comparison xregs"); 115 } 116 117 if (!xsu_fpregs_cmp(&fpr, cmp_prx)) { 118 errx(EXIT_FAILURE, "fpregs do not reflect xsave changes!"); 119 } 120 (void) printf("TEST PASSED: xregs read respects fpregs write\n"); 121 122 if (!xsu_xregs_comp_equal(prx, cmp_prx, PRX_INFO_YMM)) { 123 errx(EXIT_FAILURE, "%%ymm state changed across fpregs write"); 124 } 125 (void) printf("TEST PASSED: fpregs did not change other xregs " 126 "components\n"); 127 128 xsu_proc_finish(&xp); 129 130 return (EXIT_SUCCESS); 131 } 132