#ifdef T_NAMESPACE #undef T_NAMESPACE #endif #include #include #include #include #include #include #include #include #include #include #include T_GLOBAL_META( T_META_NAMESPACE("xnu.intel"), T_META_CHECK_LEAKS(false), T_META_RADAR_COMPONENT_NAME("xnu"), T_META_RADAR_COMPONENT_VERSION("intel"), T_META_OWNER("seth_goldberg"), T_META_RUN_CONCURRENTLY(true) ); #define QUICK_RUN_TIME (2) #define NORMAL_RUN_TIME (10) #define LONG_RUN_TIME (10*60) #define TIMEOUT_OVERHEAD (10) volatile boolean_t checking = true; char vec_str_buf[8196]; char karray_str_buf[1024]; /* * ymm defines/globals/prototypes */ #define STOP_COOKIE_256 0x01234567 #if defined(__x86_64__) #define YMM_MAX 16 #define X86_AVX_STATE_T x86_avx_state64_t #define X86_AVX_STATE_COUNT x86_AVX_STATE64_COUNT #define X86_AVX_STATE_FLAVOR x86_AVX_STATE64 #define MCONTEXT_SIZE_256 sizeof(struct __darwin_mcontext_avx64) #else #define YMM_MAX 8 #define X86_AVX_STATE_T x86_avx_state32_t #define X86_AVX_STATE_COUNT x86_AVX_STATE32_COUNT #define X86_AVX_STATE_FLAVOR x86_AVX_STATE32 #define MCONTEXT_SIZE_256 sizeof(struct __darwin_mcontext_avx32) #endif #define VECTOR256 __m256 #define VEC256ALIGN __attribute ((aligned(32))) static inline void populate_ymm(void); static inline void check_ymm(void); VECTOR256 vec256array0[YMM_MAX] VEC256ALIGN; VECTOR256 vec256array1[YMM_MAX] VEC256ALIGN; VECTOR256 vec256array2[YMM_MAX] VEC256ALIGN; VECTOR256 vec256array3[YMM_MAX] VEC256ALIGN; /* * zmm defines/globals/prototypes */ #define STOP_COOKIE_512 0x0123456789abcdefULL #if defined(__x86_64__) #define ZMM_MAX 32 #define X86_AVX512_STATE_T x86_avx512_state64_t #define X86_AVX512_STATE_COUNT x86_AVX512_STATE64_COUNT #define X86_AVX512_STATE_FLAVOR x86_AVX512_STATE64 #define MCONTEXT_SIZE_512 sizeof(struct __darwin_mcontext_avx512_64) #else #define ZMM_MAX 8 #define X86_AVX512_STATE_T x86_avx512_state32_t #define X86_AVX512_STATE_COUNT x86_AVX512_STATE32_COUNT #define X86_AVX512_STATE_FLAVOR x86_AVX512_STATE32 #define MCONTEXT_SIZE_512 sizeof(struct __darwin_mcontext_avx512_32) #endif #define VECTOR512 __m512 #define VEC512ALIGN __attribute ((aligned(64))) #define OPMASK uint64_t #define KARRAY_MAX 8 static inline void zero_zmm(void); static inline void zero_opmask(void); static inline void populate_zmm(void); static inline void populate_opmask(void); static inline void check_zmm(boolean_t check_cookie); VECTOR512 vec512array0[ZMM_MAX] VEC512ALIGN; VECTOR512 vec512array1[ZMM_MAX] VEC512ALIGN; VECTOR512 vec512array2[ZMM_MAX] VEC512ALIGN; VECTOR512 vec512array3[ZMM_MAX] VEC512ALIGN; OPMASK karray0[8]; OPMASK karray1[8]; OPMASK karray2[8]; OPMASK karray3[8]; kern_return_t _thread_get_state_avx(thread_t thread, int flavor, thread_state_t state, mach_msg_type_number_t *state_count); kern_return_t _thread_get_state_avx512(thread_t thread, int flavor, thread_state_t state, mach_msg_type_number_t *state_count); /* * Common functions */ int memcmp_unoptimized(const void *s1, const void *s2, size_t n) { if (n != 0) { const unsigned char *p1 = s1, *p2 = s2; do { if (*p1++ != *p2++) { return *--p1 - *--p2; } } while (--n != 0); } return 0; } void start_timer(int seconds, void (*handler)(int, siginfo_t *, void *)) { struct sigaction sigalrm_action = { .sa_sigaction = handler, .sa_flags = SA_RESTART, .sa_mask = 0 }; struct itimerval timer = { .it_value.tv_sec = seconds, .it_value.tv_usec = 0, .it_interval.tv_sec = 0, .it_interval.tv_usec = 0 }; T_QUIET; T_WITH_ERRNO; T_ASSERT_NE(sigaction(SIGALRM, &sigalrm_action, NULL), -1, NULL); T_QUIET; T_WITH_ERRNO; T_ASSERT_NE(setitimer(ITIMER_REAL, &timer, NULL), -1, NULL); } void require_avx(void) { if ((_get_cpu_capabilities() & kHasAVX1_0) != kHasAVX1_0) { T_SKIP("AVX not supported on this system"); } } void require_avx512(void) { if ((_get_cpu_capabilities() & kHasAVX512F) != kHasAVX512F) { T_SKIP("AVX-512 not supported on this system"); } } /* * ymm functions */ static inline void store_ymm(VECTOR256 *vec256array) { int i = 0; __asm__ volatile ("vmovaps %%ymm0, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm1, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm2, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm3, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm4, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm5, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm6, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm7, %0" :"=m" (vec256array[i])); #if defined(__x86_64__) i++; __asm__ volatile ("vmovaps %%ymm8, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm9, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm10, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm11, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm12, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm13, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm14, %0" :"=m" (vec256array[i])); i++; __asm__ volatile ("vmovaps %%ymm15, %0" :"=m" (vec256array[i])); #endif } static inline void restore_ymm(VECTOR256 *vec256array) { VECTOR256 *p = vec256array; __asm__ volatile ("vmovaps %0, %%ymm0" :: "m" (*(__m256i*)p) : "ymm0"); p++; __asm__ volatile ("vmovaps %0, %%ymm1" :: "m" (*(__m256i*)p) : "ymm1"); p++; __asm__ volatile ("vmovaps %0, %%ymm2" :: "m" (*(__m256i*)p) : "ymm2"); p++; __asm__ volatile ("vmovaps %0, %%ymm3" :: "m" (*(__m256i*)p) : "ymm3"); p++; __asm__ volatile ("vmovaps %0, %%ymm4" :: "m" (*(__m256i*)p) : "ymm4"); p++; __asm__ volatile ("vmovaps %0, %%ymm5" :: "m" (*(__m256i*)p) : "ymm5"); p++; __asm__ volatile ("vmovaps %0, %%ymm6" :: "m" (*(__m256i*)p) : "ymm6"); p++; __asm__ volatile ("vmovaps %0, %%ymm7" :: "m" (*(__m256i*)p) : "ymm7"); #if defined(__x86_64__) ++p; __asm__ volatile ("vmovaps %0, %%ymm8" :: "m" (*(__m256i*)p) : "ymm8"); p++; __asm__ volatile ("vmovaps %0, %%ymm9" :: "m" (*(__m256i*)p) : "ymm9"); p++; __asm__ volatile ("vmovaps %0, %%ymm10" :: "m" (*(__m256i*)p) : "ymm10"); p++; __asm__ volatile ("vmovaps %0, %%ymm11" :: "m" (*(__m256i*)p) : "ymm11"); p++; __asm__ volatile ("vmovaps %0, %%ymm12" :: "m" (*(__m256i*)p) : "ymm12"); p++; __asm__ volatile ("vmovaps %0, %%ymm13" :: "m" (*(__m256i*)p) : "ymm13"); p++; __asm__ volatile ("vmovaps %0, %%ymm14" :: "m" (*(__m256i*)p) : "ymm14"); p++; __asm__ volatile ("vmovaps %0, %%ymm15" :: "m" (*(__m256i*)p) : "ymm15"); #endif } static inline void populate_ymm(void) { int j; uint32_t p[8] VEC256ALIGN; for (j = 0; j < (int) (sizeof(p) / sizeof(p[0])); j++) { p[j] = getpid(); } p[0] = 0x22222222; p[7] = 0x77777777; __asm__ volatile ("vmovaps %0, %%ymm0" :: "m" (*(__m256i*)p) : "ymm0"); __asm__ volatile ("vmovaps %0, %%ymm1" :: "m" (*(__m256i*)p) : "ymm1"); __asm__ volatile ("vmovaps %0, %%ymm2" :: "m" (*(__m256i*)p) : "ymm2"); __asm__ volatile ("vmovaps %0, %%ymm3" :: "m" (*(__m256i*)p) : "ymm3"); p[0] = 0x44444444; p[7] = 0xEEEEEEEE; __asm__ volatile ("vmovaps %0, %%ymm4" :: "m" (*(__m256i*)p) : "ymm4"); __asm__ volatile ("vmovaps %0, %%ymm5" :: "m" (*(__m256i*)p) : "ymm5"); __asm__ volatile ("vmovaps %0, %%ymm6" :: "m" (*(__m256i*)p) : "ymm6"); __asm__ volatile ("vmovaps %0, %%ymm7" :: "m" (*(__m256i*)p) : "ymm7"); #if defined(__x86_64__) p[0] = 0x88888888; p[7] = 0xAAAAAAAA; __asm__ volatile ("vmovaps %0, %%ymm8" :: "m" (*(__m256i*)p) : "ymm8"); __asm__ volatile ("vmovaps %0, %%ymm9" :: "m" (*(__m256i*)p) : "ymm9"); __asm__ volatile ("vmovaps %0, %%ymm10" :: "m" (*(__m256i*)p) : "ymm10"); __asm__ volatile ("vmovaps %0, %%ymm11" :: "m" (*(__m256i*)p) : "ymm11"); p[0] = 0xBBBBBBBB; p[7] = 0xCCCCCCCC; __asm__ volatile ("vmovaps %0, %%ymm12" :: "m" (*(__m256i*)p) : "ymm12"); __asm__ volatile ("vmovaps %0, %%ymm13" :: "m" (*(__m256i*)p) : "ymm13"); __asm__ volatile ("vmovaps %0, %%ymm14" :: "m" (*(__m256i*)p) : "ymm14"); __asm__ volatile ("vmovaps %0, %%ymm15" :: "m" (*(__m256i*)p) : "ymm15"); #endif store_ymm(vec256array0); } void vec256_to_string(VECTOR256 *vec, char *buf) { unsigned int vec_idx = 0; unsigned int buf_idx = 0; int ret = 0; for (vec_idx = 0; vec_idx < YMM_MAX; vec_idx++) { uint64_t a[4]; bcopy(&vec[vec_idx], &a[0], sizeof(a)); ret = sprintf( buf + buf_idx, "0x%016llx:%016llx:%016llx:%016llx\n", a[0], a[1], a[2], a[3] ); T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sprintf()"); buf_idx += ret; } } void assert_ymm_eq(void *a, void *b, int c) { if (memcmp_unoptimized(a, b, c)) { vec256_to_string(a, vec_str_buf); T_LOG("Compare failed, vector A:\n%s", vec_str_buf); vec256_to_string(b, vec_str_buf); T_LOG("Compare failed, vector B:\n%s", vec_str_buf); T_ASSERT_FAIL("vectors not equal"); } } void check_ymm(void) { uint32_t *p = (uint32_t *) &vec256array1[7]; store_ymm(vec256array1); if (p[0] == STOP_COOKIE_256) { return; } assert_ymm_eq(vec256array0, vec256array1, sizeof(vec256array0)); } static void copy_ymm_state_to_vector(X86_AVX_STATE_T *sp, VECTOR256 *vp) { int i; struct __darwin_xmm_reg *xmm = &sp->__fpu_xmm0; struct __darwin_xmm_reg *ymmh = &sp->__fpu_ymmh0; for (i = 0; i < YMM_MAX; i++) { bcopy(&xmm[i], &vp[i], sizeof(*xmm)); bcopy(&ymmh[i], (void *) ((uint64_t)&vp[i] + sizeof(*ymmh)), sizeof(*ymmh)); } } static void ymm_sigalrm_handler(int signum __unused, siginfo_t *info __unused, void *ctx) { ucontext_t *contextp = (ucontext_t *) ctx; mcontext_t mcontext = contextp->uc_mcontext; X86_AVX_STATE_T *avx_state = (X86_AVX_STATE_T *) &mcontext->__fs; uint32_t *xp = (uint32_t *) &avx_state->__fpu_xmm7; uint32_t *yp = (uint32_t *) &avx_state->__fpu_ymmh7; T_LOG("Got SIGALRM"); /* Check for AVX state */ T_QUIET; T_ASSERT_GE(contextp->uc_mcsize, MCONTEXT_SIZE_256, "check context size"); /* Check that the state in the context is what's set and expected */ copy_ymm_state_to_vector(avx_state, vec256array3); assert_ymm_eq(vec256array3, vec256array0, sizeof(vec256array1)); /* Change the context and break the main loop */ xp[0] = STOP_COOKIE_256; yp[0] = STOP_COOKIE_256; checking = FALSE; } kern_return_t _thread_get_state_avx( thread_t thread, int flavor, thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count) /*IN/OUT*/ { kern_return_t rv; VECTOR256 ymms[YMM_MAX]; /* * We must save and restore the YMMs across thread_get_state() because * code in thread_get_state changes at least one xmm register AFTER the * thread_get_state has saved the state in userspace. While it's still * possible for something to muck with %xmms BEFORE making the mach * system call (and rendering this save/restore useless), that does not * currently occur, and since we depend on the avx state saved in the * thread_get_state to be the same as that manually copied from YMMs after * thread_get_state returns, we have to go through these machinations. */ store_ymm(ymms); rv = thread_get_state(thread, flavor, state, state_count); restore_ymm(ymms); return rv; } void ymm_integrity(int time) { mach_msg_type_number_t avx_count = X86_AVX_STATE_COUNT; kern_return_t kret; X86_AVX_STATE_T avx_state, avx_state2; mach_port_t ts = mach_thread_self(); bzero(&avx_state, sizeof(avx_state)); bzero(&avx_state2, sizeof(avx_state)); kret = _thread_get_state_avx( ts, X86_AVX_STATE_FLAVOR, (thread_state_t)&avx_state, &avx_count ); store_ymm(vec256array2); T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "thread_get_state()"); vec256_to_string(vec256array2, vec_str_buf); T_LOG("Initial state:\n%s", vec_str_buf); copy_ymm_state_to_vector(&avx_state, vec256array1); assert_ymm_eq(vec256array2, vec256array1, sizeof(vec256array1)); populate_ymm(); kret = _thread_get_state_avx( ts, X86_AVX_STATE_FLAVOR, (thread_state_t)&avx_state2, &avx_count ); store_ymm(vec256array2); T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "thread_get_state()"); vec256_to_string(vec256array2, vec_str_buf); T_LOG("Populated state:\n%s", vec_str_buf); copy_ymm_state_to_vector(&avx_state2, vec256array1); assert_ymm_eq(vec256array2, vec256array1, sizeof(vec256array0)); T_LOG("Running for %ds…", time); start_timer(time, ymm_sigalrm_handler); /* re-populate because printing mucks up XMMs */ populate_ymm(); /* Check state until timer fires */ while (checking) { check_ymm(); } /* Check that the sig handler changed out AVX state */ store_ymm(vec256array1); uint32_t *p = (uint32_t *) &vec256array1[7]; if (p[0] != STOP_COOKIE_256 || p[4] != STOP_COOKIE_256) { vec256_to_string(vec256array1, vec_str_buf); T_ASSERT_FAIL("sigreturn failed to stick"); T_LOG("State:\n%s", vec_str_buf); } T_LOG("Ran for %ds", time); T_PASS("No ymm register corruption occurred"); } /* * zmm functions */ static inline void store_opmask(OPMASK k[]) { __asm__ volatile ("kmovq %%k0, %0" :"=m" (k[0])); __asm__ volatile ("kmovq %%k1, %0" :"=m" (k[1])); __asm__ volatile ("kmovq %%k2, %0" :"=m" (k[2])); __asm__ volatile ("kmovq %%k3, %0" :"=m" (k[3])); __asm__ volatile ("kmovq %%k4, %0" :"=m" (k[4])); __asm__ volatile ("kmovq %%k5, %0" :"=m" (k[5])); __asm__ volatile ("kmovq %%k6, %0" :"=m" (k[6])); __asm__ volatile ("kmovq %%k7, %0" :"=m" (k[7])); } static inline void store_zmm(VECTOR512 *vecarray) { int i = 0; __asm__ volatile ("vmovaps %%zmm0, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm1, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm2, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm3, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm4, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm5, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm6, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm7, %0" :"=m" (vecarray[i])); #if defined(__x86_64__) i++; __asm__ volatile ("vmovaps %%zmm8, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm9, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm10, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm11, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm12, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm13, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm14, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm15, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm16, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm17, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm18, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm19, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm20, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm21, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm22, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm23, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm24, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm25, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm26, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm27, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm28, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm29, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm30, %0" :"=m" (vecarray[i])); i++; __asm__ volatile ("vmovaps %%zmm31, %0" :"=m" (vecarray[i])); #endif } static inline void restore_zmm(VECTOR512 *vecarray) { VECTOR512 *p = vecarray; __asm__ volatile ("vmovaps %0, %%zmm0" :: "m" (*(__m512i*)p) : "zmm0"); p++; __asm__ volatile ("vmovaps %0, %%zmm1" :: "m" (*(__m512i*)p) : "zmm1"); p++; __asm__ volatile ("vmovaps %0, %%zmm2" :: "m" (*(__m512i*)p) : "zmm2"); p++; __asm__ volatile ("vmovaps %0, %%zmm3" :: "m" (*(__m512i*)p) : "zmm3"); p++; __asm__ volatile ("vmovaps %0, %%zmm4" :: "m" (*(__m512i*)p) : "zmm4"); p++; __asm__ volatile ("vmovaps %0, %%zmm5" :: "m" (*(__m512i*)p) : "zmm5"); p++; __asm__ volatile ("vmovaps %0, %%zmm6" :: "m" (*(__m512i*)p) : "zmm6"); p++; __asm__ volatile ("vmovaps %0, %%zmm7" :: "m" (*(__m512i*)p) : "zmm7"); #if defined(__x86_64__) ++p; __asm__ volatile ("vmovaps %0, %%zmm8" :: "m" (*(__m512i*)p) : "zmm8"); p++; __asm__ volatile ("vmovaps %0, %%zmm9" :: "m" (*(__m512i*)p) : "zmm9"); p++; __asm__ volatile ("vmovaps %0, %%zmm10" :: "m" (*(__m512i*)p) : "zmm10"); p++; __asm__ volatile ("vmovaps %0, %%zmm11" :: "m" (*(__m512i*)p) : "zmm11"); p++; __asm__ volatile ("vmovaps %0, %%zmm12" :: "m" (*(__m512i*)p) : "zmm12"); p++; __asm__ volatile ("vmovaps %0, %%zmm13" :: "m" (*(__m512i*)p) : "zmm13"); p++; __asm__ volatile ("vmovaps %0, %%zmm14" :: "m" (*(__m512i*)p) : "zmm14"); p++; __asm__ volatile ("vmovaps %0, %%zmm15" :: "m" (*(__m512i*)p) : "zmm15"); p++; __asm__ volatile ("vmovaps %0, %%zmm16" :: "m" (*(__m512i*)p) : "zmm16"); p++; __asm__ volatile ("vmovaps %0, %%zmm17" :: "m" (*(__m512i*)p) : "zmm17"); p++; __asm__ volatile ("vmovaps %0, %%zmm18" :: "m" (*(__m512i*)p) : "zmm18"); p++; __asm__ volatile ("vmovaps %0, %%zmm19" :: "m" (*(__m512i*)p) : "zmm19"); p++; __asm__ volatile ("vmovaps %0, %%zmm20" :: "m" (*(__m512i*)p) : "zmm20"); p++; __asm__ volatile ("vmovaps %0, %%zmm21" :: "m" (*(__m512i*)p) : "zmm21"); p++; __asm__ volatile ("vmovaps %0, %%zmm22" :: "m" (*(__m512i*)p) : "zmm22"); p++; __asm__ volatile ("vmovaps %0, %%zmm23" :: "m" (*(__m512i*)p) : "zmm23"); p++; __asm__ volatile ("vmovaps %0, %%zmm24" :: "m" (*(__m512i*)p) : "zmm24"); p++; __asm__ volatile ("vmovaps %0, %%zmm25" :: "m" (*(__m512i*)p) : "zmm25"); p++; __asm__ volatile ("vmovaps %0, %%zmm26" :: "m" (*(__m512i*)p) : "zmm26"); p++; __asm__ volatile ("vmovaps %0, %%zmm27" :: "m" (*(__m512i*)p) : "zmm27"); p++; __asm__ volatile ("vmovaps %0, %%zmm28" :: "m" (*(__m512i*)p) : "zmm28"); p++; __asm__ volatile ("vmovaps %0, %%zmm29" :: "m" (*(__m512i*)p) : "zmm29"); p++; __asm__ volatile ("vmovaps %0, %%zmm30" :: "m" (*(__m512i*)p) : "zmm30"); p++; __asm__ volatile ("vmovaps %0, %%zmm31" :: "m" (*(__m512i*)p) : "zmm31"); #endif } static inline void zero_opmask(void) { uint64_t zero = 0x0000000000000000ULL; __asm__ volatile ("kmovq %0, %%k0" : :"m" (zero) : "k0"); __asm__ volatile ("kmovq %0, %%k1" : :"m" (zero) : "k1"); __asm__ volatile ("kmovq %0, %%k2" : :"m" (zero) : "k2"); __asm__ volatile ("kmovq %0, %%k3" : :"m" (zero) : "k3"); __asm__ volatile ("kmovq %0, %%k4" : :"m" (zero) : "k4"); __asm__ volatile ("kmovq %0, %%k5" : :"m" (zero) : "k5"); __asm__ volatile ("kmovq %0, %%k6" : :"m" (zero) : "k6"); __asm__ volatile ("kmovq %0, %%k7" : :"m" (zero) : "k7"); store_opmask(karray0); } static inline void populate_opmask(void) { uint64_t k[8]; for (int j = 0; j < 8; j++) { k[j] = ((uint64_t) getpid() << 32) + (0x11111111 * j); } __asm__ volatile ("kmovq %0, %%k0" : :"m" (k[0]) : "k0"); __asm__ volatile ("kmovq %0, %%k1" : :"m" (k[1]) : "k1"); __asm__ volatile ("kmovq %0, %%k2" : :"m" (k[2]) : "k2"); __asm__ volatile ("kmovq %0, %%k3" : :"m" (k[3]) : "k3"); __asm__ volatile ("kmovq %0, %%k4" : :"m" (k[4]) : "k4"); __asm__ volatile ("kmovq %0, %%k5" : :"m" (k[5]) : "k5"); __asm__ volatile ("kmovq %0, %%k6" : :"m" (k[6]) : "k6"); __asm__ volatile ("kmovq %0, %%k7" : :"m" (k[7]) : "k7"); store_opmask(karray0); } kern_return_t _thread_get_state_avx512( thread_t thread, int flavor, thread_state_t state, /* pointer to OUT array */ mach_msg_type_number_t *state_count) /*IN/OUT*/ { kern_return_t rv; VECTOR512 zmms[ZMM_MAX]; /* * We must save and restore the ZMMs across thread_get_state() because * code in thread_get_state changes at least one xmm register AFTER the * thread_get_state has saved the state in userspace. While it's still * possible for something to muck with %XMMs BEFORE making the mach * system call (and rendering this save/restore useless), that does not * currently occur, and since we depend on the avx512 state saved in the * thread_get_state to be the same as that manually copied from ZMMs after * thread_get_state returns, we have to go through these machinations. */ store_zmm(zmms); rv = thread_get_state(thread, flavor, state, state_count); restore_zmm(zmms); return rv; } static inline void zero_zmm(void) { uint64_t zero[8] VEC512ALIGN = {0}; __asm__ volatile ("vmovaps %0, %%zmm0" :: "m" (zero) : "zmm0"); __asm__ volatile ("vmovaps %0, %%zmm1" :: "m" (zero) : "zmm1"); __asm__ volatile ("vmovaps %0, %%zmm2" :: "m" (zero) : "zmm2"); __asm__ volatile ("vmovaps %0, %%zmm3" :: "m" (zero) : "zmm3"); __asm__ volatile ("vmovaps %0, %%zmm4" :: "m" (zero) : "zmm4"); __asm__ volatile ("vmovaps %0, %%zmm5" :: "m" (zero) : "zmm5"); __asm__ volatile ("vmovaps %0, %%zmm6" :: "m" (zero) : "zmm6"); __asm__ volatile ("vmovaps %0, %%zmm7" :: "m" (zero) : "zmm7"); #if defined(__x86_64__) __asm__ volatile ("vmovaps %0, %%zmm8" :: "m" (zero) : "zmm8"); __asm__ volatile ("vmovaps %0, %%zmm9" :: "m" (zero) : "zmm9"); __asm__ volatile ("vmovaps %0, %%zmm10" :: "m" (zero) : "zmm10"); __asm__ volatile ("vmovaps %0, %%zmm11" :: "m" (zero) : "zmm11"); __asm__ volatile ("vmovaps %0, %%zmm12" :: "m" (zero) : "zmm12"); __asm__ volatile ("vmovaps %0, %%zmm13" :: "m" (zero) : "zmm13"); __asm__ volatile ("vmovaps %0, %%zmm14" :: "m" (zero) : "zmm14"); __asm__ volatile ("vmovaps %0, %%zmm15" :: "m" (zero) : "zmm15"); __asm__ volatile ("vmovaps %0, %%zmm16" :: "m" (zero) : "zmm16"); __asm__ volatile ("vmovaps %0, %%zmm17" :: "m" (zero) : "zmm17"); __asm__ volatile ("vmovaps %0, %%zmm18" :: "m" (zero) : "zmm18"); __asm__ volatile ("vmovaps %0, %%zmm19" :: "m" (zero) : "zmm19"); __asm__ volatile ("vmovaps %0, %%zmm20" :: "m" (zero) : "zmm20"); __asm__ volatile ("vmovaps %0, %%zmm21" :: "m" (zero) : "zmm21"); __asm__ volatile ("vmovaps %0, %%zmm22" :: "m" (zero) : "zmm22"); __asm__ volatile ("vmovaps %0, %%zmm23" :: "m" (zero) : "zmm23"); __asm__ volatile ("vmovaps %0, %%zmm24" :: "m" (zero) : "zmm24"); __asm__ volatile ("vmovaps %0, %%zmm25" :: "m" (zero) : "zmm25"); __asm__ volatile ("vmovaps %0, %%zmm26" :: "m" (zero) : "zmm26"); __asm__ volatile ("vmovaps %0, %%zmm27" :: "m" (zero) : "zmm27"); __asm__ volatile ("vmovaps %0, %%zmm28" :: "m" (zero) : "zmm28"); __asm__ volatile ("vmovaps %0, %%zmm29" :: "m" (zero) : "zmm29"); __asm__ volatile ("vmovaps %0, %%zmm30" :: "m" (zero) : "zmm30"); __asm__ volatile ("vmovaps %0, %%zmm31" :: "m" (zero) : "zmm31"); #endif store_zmm(vec512array0); } static inline void populate_zmm(void) { int j; uint64_t p[8] VEC512ALIGN; for (j = 0; j < (int) (sizeof(p) / sizeof(p[0])); j++) { p[j] = ((uint64_t) getpid() << 32) + getpid(); } p[0] = 0x0000000000000000ULL; p[2] = 0x4444444444444444ULL; p[4] = 0x8888888888888888ULL; p[7] = 0xCCCCCCCCCCCCCCCCULL; __asm__ volatile ("vmovaps %0, %%zmm0" :: "m" (*(__m512i*)p) : "zmm0"); __asm__ volatile ("vmovaps %0, %%zmm1" :: "m" (*(__m512i*)p) : "zmm1"); __asm__ volatile ("vmovaps %0, %%zmm2" :: "m" (*(__m512i*)p) : "zmm2"); __asm__ volatile ("vmovaps %0, %%zmm3" :: "m" (*(__m512i*)p) : "zmm3"); __asm__ volatile ("vmovaps %0, %%zmm4" :: "m" (*(__m512i*)p) : "zmm4"); __asm__ volatile ("vmovaps %0, %%zmm5" :: "m" (*(__m512i*)p) : "zmm5"); __asm__ volatile ("vmovaps %0, %%zmm6" :: "m" (*(__m512i*)p) : "zmm6"); __asm__ volatile ("vmovaps %0, %%zmm7" :: "m" (*(__m512i*)p) : "zmm7"); #if defined(__x86_64__) p[0] = 0x1111111111111111ULL; p[2] = 0x5555555555555555ULL; p[4] = 0x9999999999999999ULL; p[7] = 0xDDDDDDDDDDDDDDDDULL; __asm__ volatile ("vmovaps %0, %%zmm8" :: "m" (*(__m512i*)p) : "zmm8"); __asm__ volatile ("vmovaps %0, %%zmm9" :: "m" (*(__m512i*)p) : "zmm9"); __asm__ volatile ("vmovaps %0, %%zmm10" :: "m" (*(__m512i*)p) : "zmm10"); __asm__ volatile ("vmovaps %0, %%zmm11" :: "m" (*(__m512i*)p) : "zmm11"); __asm__ volatile ("vmovaps %0, %%zmm12" :: "m" (*(__m512i*)p) : "zmm12"); __asm__ volatile ("vmovaps %0, %%zmm13" :: "m" (*(__m512i*)p) : "zmm13"); __asm__ volatile ("vmovaps %0, %%zmm14" :: "m" (*(__m512i*)p) : "zmm14"); __asm__ volatile ("vmovaps %0, %%zmm15" :: "m" (*(__m512i*)p) : "zmm15"); p[0] = 0x2222222222222222ULL; p[2] = 0x6666666666666666ULL; p[4] = 0xAAAAAAAAAAAAAAAAULL; p[7] = 0xEEEEEEEEEEEEEEEEULL; __asm__ volatile ("vmovaps %0, %%zmm16" :: "m" (*(__m512i*)p) : "zmm16"); __asm__ volatile ("vmovaps %0, %%zmm17" :: "m" (*(__m512i*)p) : "zmm17"); __asm__ volatile ("vmovaps %0, %%zmm18" :: "m" (*(__m512i*)p) : "zmm18"); __asm__ volatile ("vmovaps %0, %%zmm19" :: "m" (*(__m512i*)p) : "zmm19"); __asm__ volatile ("vmovaps %0, %%zmm20" :: "m" (*(__m512i*)p) : "zmm20"); __asm__ volatile ("vmovaps %0, %%zmm21" :: "m" (*(__m512i*)p) : "zmm21"); __asm__ volatile ("vmovaps %0, %%zmm22" :: "m" (*(__m512i*)p) : "zmm22"); __asm__ volatile ("vmovaps %0, %%zmm23" :: "m" (*(__m512i*)p) : "zmm23"); p[0] = 0x3333333333333333ULL; p[2] = 0x7777777777777777ULL; p[4] = 0xBBBBBBBBBBBBBBBBULL; p[7] = 0xFFFFFFFFFFFFFFFFULL; __asm__ volatile ("vmovaps %0, %%zmm24" :: "m" (*(__m512i*)p) : "zmm24"); __asm__ volatile ("vmovaps %0, %%zmm25" :: "m" (*(__m512i*)p) : "zmm25"); __asm__ volatile ("vmovaps %0, %%zmm26" :: "m" (*(__m512i*)p) : "zmm26"); __asm__ volatile ("vmovaps %0, %%zmm27" :: "m" (*(__m512i*)p) : "zmm27"); __asm__ volatile ("vmovaps %0, %%zmm28" :: "m" (*(__m512i*)p) : "zmm28"); __asm__ volatile ("vmovaps %0, %%zmm29" :: "m" (*(__m512i*)p) : "zmm29"); __asm__ volatile ("vmovaps %0, %%zmm30" :: "m" (*(__m512i*)p) : "zmm30"); __asm__ volatile ("vmovaps %0, %%zmm31" :: "m" (*(__m512i*)p) : "zmm31"); #endif store_zmm(vec512array0); } void vec512_to_string(VECTOR512 *vec, char *buf) { unsigned int vec_idx = 0; unsigned int buf_idx = 0; int ret = 0; for (vec_idx = 0; vec_idx < ZMM_MAX; vec_idx++) { uint64_t a[8]; bcopy(&vec[vec_idx], &a[0], sizeof(a)); ret = sprintf( buf + buf_idx, "0x%016llx:%016llx:%016llx:%016llx:" "%016llx:%016llx:%016llx:%016llx%s", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], vec_idx < ZMM_MAX - 1 ? "\n" : "" ); T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sprintf()"); buf_idx += ret; } } void opmask_to_string(OPMASK *karray, char *buf) { unsigned int karray_idx = 0; unsigned int buf_idx = 0; int ret = 0; for (karray_idx = 0; karray_idx < KARRAY_MAX; karray_idx++) { ret = sprintf( buf + buf_idx, "k%d: 0x%016llx%s", karray_idx, karray[karray_idx], karray_idx < KARRAY_MAX ? "\n" : "" ); T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sprintf()"); buf_idx += ret; } } static void assert_zmm_eq(void *a, void *b, int c) { if (memcmp_unoptimized(a, b, c)) { vec512_to_string(a, vec_str_buf); T_LOG("Compare failed, vector A:\n%s", vec_str_buf); vec512_to_string(b, vec_str_buf); T_LOG("Compare failed, vector B:\n%s", vec_str_buf); T_ASSERT_FAIL("Vectors not equal"); } } static void assert_opmask_eq(OPMASK *a, OPMASK *b) { for (int i = 0; i < KARRAY_MAX; i++) { if (a[i] != b[i]) { opmask_to_string(a, karray_str_buf); T_LOG("Compare failed, opmask A:\n%s", karray_str_buf); opmask_to_string(b, karray_str_buf); T_LOG("Compare failed, opmask B:\n%s", karray_str_buf); T_ASSERT_FAIL("opmasks not equal"); } } } void check_zmm(boolean_t check_cookie) { uint64_t *p = (uint64_t *) &vec512array1[7]; store_opmask(karray1); store_zmm(vec512array1); if (check_cookie && p[0] == STOP_COOKIE_512) { return; } assert_zmm_eq(vec512array0, vec512array1, sizeof(vec512array0)); assert_opmask_eq(karray0, karray1); } static void copy_state_to_opmask(X86_AVX512_STATE_T *sp, OPMASK *op) { OPMASK *k = (OPMASK *) &sp->__fpu_k0; for (int i = 0; i < KARRAY_MAX; i++) { bcopy(&k[i], &op[i], sizeof(*op)); } } static void copy_zmm_state_to_vector(X86_AVX512_STATE_T *sp, VECTOR512 *vp) { int i; struct __darwin_xmm_reg *xmm = &sp->__fpu_xmm0; struct __darwin_xmm_reg *ymmh = &sp->__fpu_ymmh0; struct __darwin_ymm_reg *zmmh = &sp->__fpu_zmmh0; #if defined(__x86_64__) struct __darwin_zmm_reg *zmm = &sp->__fpu_zmm16; for (i = 0; i < ZMM_MAX / 2; i++) { bcopy(&xmm[i], &vp[i], sizeof(*xmm)); bcopy(&ymmh[i], (void *) ((uint64_t)&vp[i] + sizeof(*ymmh)), sizeof(*ymmh)); bcopy(&zmmh[i], (void *) ((uint64_t)&vp[i] + sizeof(*zmmh)), sizeof(*zmmh)); bcopy(&zmm[i], &vp[(ZMM_MAX / 2) + i], sizeof(*zmm)); } #else for (i = 0; i < ZMM_MAX; i++) { bcopy(&xmm[i], &vp[i], sizeof(*xmm)); bcopy(&ymmh[i], (void *) ((uint64_t)&vp[i] + sizeof(*ymmh)), sizeof(*ymmh)); bcopy(&zmmh[i], (void *) ((uint64_t)&vp[i] + sizeof(*zmmh)), sizeof(*zmmh)); } #endif } static void zmm_sigalrm_handler(int signum __unused, siginfo_t *info __unused, void *ctx) { ucontext_t *contextp = (ucontext_t *) ctx; mcontext_t mcontext = contextp->uc_mcontext; X86_AVX512_STATE_T *avx_state = (X86_AVX512_STATE_T *) &mcontext->__fs; uint64_t *xp = (uint64_t *) &avx_state->__fpu_xmm7; uint64_t *yp = (uint64_t *) &avx_state->__fpu_ymmh7; uint64_t *zp = (uint64_t *) &avx_state->__fpu_zmmh7; uint64_t *kp = (uint64_t *) &avx_state->__fpu_k0; /* Check for AVX512 state */ T_QUIET; T_ASSERT_GE(contextp->uc_mcsize, MCONTEXT_SIZE_512, "check context size"); /* Check that the state in the context is what's set and expected */ copy_zmm_state_to_vector(avx_state, vec512array3); assert_zmm_eq(vec512array3, vec512array0, sizeof(vec512array3)); copy_state_to_opmask(avx_state, karray3); assert_opmask_eq(karray3, karray0); /* Change the context and break the main loop */ xp[0] = STOP_COOKIE_512; yp[0] = STOP_COOKIE_512; zp[0] = STOP_COOKIE_512; kp[7] = STOP_COOKIE_512; checking = FALSE; } static void zmm_sigalrm_handler_no_mod(int signum __unused, siginfo_t *info __unused, void *ctx) { ucontext_t *contextp = (ucontext_t *) ctx; mcontext_t mcontext = contextp->uc_mcontext; X86_AVX512_STATE_T *avx_state = (X86_AVX512_STATE_T *) &mcontext->__fs; uint64_t *xp = (uint64_t *) &avx_state->__fpu_xmm7; uint64_t *yp = (uint64_t *) &avx_state->__fpu_ymmh7; uint64_t *zp = (uint64_t *) &avx_state->__fpu_zmmh7; uint64_t *kp = (uint64_t *) &avx_state->__fpu_k0; /* Check for AVX512 state */ T_QUIET; T_ASSERT_GE(contextp->uc_mcsize, MCONTEXT_SIZE_512, "check context size"); /* Check that the state in the context is what's set and expected */ copy_zmm_state_to_vector(avx_state, vec512array3); assert_zmm_eq(vec512array3, vec512array0, sizeof(vec512array3)); copy_state_to_opmask(avx_state, karray3); assert_opmask_eq(karray3, karray0); /* Change the context and break the main loop */ checking = FALSE; } void zmm_integrity(int time) { mach_msg_type_number_t avx_count = X86_AVX512_STATE_COUNT; kern_return_t kret; X86_AVX512_STATE_T avx_state, avx_state2; mach_port_t ts = mach_thread_self(); bzero(&avx_state, sizeof(avx_state)); bzero(&avx_state2, sizeof(avx_state)); store_zmm(vec512array2); store_opmask(karray2); kret = _thread_get_state_avx512( ts, X86_AVX512_STATE_FLAVOR, (thread_state_t)&avx_state, &avx_count ); T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "thread_get_state()"); vec512_to_string(vec512array2, vec_str_buf); opmask_to_string(karray2, karray_str_buf); T_LOG("Initial state:\n%s\n%s", vec_str_buf, karray_str_buf); copy_zmm_state_to_vector(&avx_state, vec512array1); assert_zmm_eq(vec512array2, vec512array1, sizeof(vec512array1)); copy_state_to_opmask(&avx_state, karray1); assert_opmask_eq(karray2, karray1); populate_zmm(); populate_opmask(); kret = _thread_get_state_avx512( ts, X86_AVX512_STATE_FLAVOR, (thread_state_t)&avx_state2, &avx_count ); store_zmm(vec512array2); store_opmask(karray2); T_QUIET; T_ASSERT_MACH_SUCCESS(kret, "thread_get_state()"); vec512_to_string(vec512array2, vec_str_buf); opmask_to_string(karray2, karray_str_buf); T_LOG("Populated state:\n%s\n%s", vec_str_buf, karray_str_buf); copy_zmm_state_to_vector(&avx_state2, vec512array1); assert_zmm_eq(vec512array2, vec512array1, sizeof(vec512array1)); copy_state_to_opmask(&avx_state2, karray1); assert_opmask_eq(karray2, karray1); T_LOG("Running for %ds…", time); start_timer(time, zmm_sigalrm_handler); /* re-populate because printing mucks up XMMs */ populate_zmm(); populate_opmask(); /* Check state until timer fires */ while (checking) { check_zmm(TRUE); } /* Check that the sig handler changed our AVX state */ store_zmm(vec512array1); store_opmask(karray1); uint64_t *p = (uint64_t *) &vec512array1[7]; if (p[0] != STOP_COOKIE_512 || p[2] != STOP_COOKIE_512 || p[4] != STOP_COOKIE_512 || karray1[7] != STOP_COOKIE_512) { vec512_to_string(vec512array1, vec_str_buf); opmask_to_string(karray1, karray_str_buf); T_ASSERT_FAIL("sigreturn failed to stick"); T_LOG("State:\n%s\n%s", vec_str_buf, karray_str_buf); } T_LOG("Ran for %ds", time); T_PASS("No zmm register corruption occurred"); } void zmm_zeroing_optimization_integrity(int time) { /* * Check ZMM zero and OpMask zero */ T_LOG("Checking ZMM zero and OpMask zero"); checking = true; zero_zmm(); zero_opmask(); T_LOG("Running for %ds…", time); start_timer(time, zmm_sigalrm_handler_no_mod); /* re-populate because printing mucks up XMMs */ zero_zmm(); zero_opmask(); /* Check state until timer fires */ while (checking) { check_zmm(FALSE); } /* Check that sig handler did not changed our AVX state */ store_zmm(vec512array2); store_opmask(karray2); assert_zmm_eq(vec512array0, vec512array2, sizeof(vec512array2)); assert_opmask_eq(karray0, karray2); T_LOG("Ran for %ds", time); T_PASS("ZMM zero and OpMask zero"); /* * Check ZMM zero and OpMask non-zero */ T_LOG("Checking ZMM zero and OpMask non-zero"); checking = true; zero_zmm(); populate_opmask(); T_LOG("Running for %ds…", time); start_timer(time, zmm_sigalrm_handler_no_mod); /* re-populate because printing mucks up XMMs */ zero_zmm(); populate_opmask(); /* Check state until timer fires */ while (checking) { check_zmm(FALSE); } /* Check that sig handler did not changed our AVX state */ store_zmm(vec512array2); store_opmask(karray2); assert_zmm_eq(vec512array0, vec512array2, sizeof(vec512array2)); assert_opmask_eq(karray0, karray2); T_LOG("Ran for %ds", time); T_PASS("ZMM zero and OpMask non-zero"); /* * Check ZMM non-zero and OpMask zero */ T_LOG("Checking ZMM non-zero and OpMask zero"); checking = true; populate_zmm(); zero_opmask(); T_LOG("Running for %ds…", time); start_timer(time, zmm_sigalrm_handler_no_mod); /* re-populate because printing mucks up XMMs */ populate_zmm(); zero_opmask(); /* Check state until timer fires */ while (checking) { check_zmm(FALSE); } /* Check that sig handler did not changed our AVX state */ store_zmm(vec512array2); store_opmask(karray2); assert_zmm_eq(vec512array0, vec512array2, sizeof(vec512array2)); assert_opmask_eq(karray0, karray2); T_LOG("Ran for %ds", time); T_PASS("ZMM non-zero and OpMask zero"); /* * Check ZMM non-zero and OpMask non-zero */ T_LOG("Checking ZMM non-zero and OpMask non-zero"); checking = true; populate_zmm(); populate_opmask(); T_LOG("Running for %ds…", time); start_timer(time, zmm_sigalrm_handler_no_mod); /* re-populate because printing mucks up XMMs */ populate_zmm(); populate_opmask(); /* Check state until timer fires */ while (checking) { check_zmm(FALSE); } /* Check that sig handler did not changed our AVX state */ store_zmm(vec512array2); store_opmask(karray2); assert_zmm_eq(vec512array0, vec512array2, sizeof(vec512array2)); assert_opmask_eq(karray0, karray2); T_LOG("Ran for %ds", time); T_PASS("ZMM non-zero and OpMask non-zero"); } /* * Main test declarations */ T_DECL(ymm_integrity, "Quick soak test to verify that AVX " "register state is maintained correctly", T_META_TIMEOUT(NORMAL_RUN_TIME + TIMEOUT_OVERHEAD)) { require_avx(); ymm_integrity(NORMAL_RUN_TIME); } T_DECL(ymm_integrity_stress, "Extended soak test to verify that AVX " "register state is maintained correctly", T_META_TIMEOUT(LONG_RUN_TIME + TIMEOUT_OVERHEAD), T_META_ENABLED(false)) { require_avx(); ymm_integrity(LONG_RUN_TIME); } T_DECL(zmm_integrity, "Quick soak test to verify that AVX-512 " "register state is maintained correctly", T_META_TIMEOUT(NORMAL_RUN_TIME + TIMEOUT_OVERHEAD)) { require_avx512(); zmm_integrity(NORMAL_RUN_TIME); } T_DECL(zmm_integrity_stress, "Extended soak test to verify that AVX-512 " "register state is maintained correctly", T_META_TIMEOUT(LONG_RUN_TIME + TIMEOUT_OVERHEAD), T_META_ENABLED(false)) { require_avx512(); zmm_integrity(LONG_RUN_TIME); } T_DECL(zmm_zeroing_optimization_integrity, "Quick soak test to verify AVX-512 " "register state is maintained with " "zeroing optimizations enabled", T_META_TIMEOUT(QUICK_RUN_TIME + TIMEOUT_OVERHEAD)) { require_avx512(); zmm_zeroing_optimization_integrity(QUICK_RUN_TIME); }