162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#define _GNU_SOURCE 462306a36Sopenharmony_ci#include <err.h> 562306a36Sopenharmony_ci#include <errno.h> 662306a36Sopenharmony_ci#include <pthread.h> 762306a36Sopenharmony_ci#include <setjmp.h> 862306a36Sopenharmony_ci#include <stdio.h> 962306a36Sopenharmony_ci#include <string.h> 1062306a36Sopenharmony_ci#include <stdbool.h> 1162306a36Sopenharmony_ci#include <unistd.h> 1262306a36Sopenharmony_ci#include <x86intrin.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <sys/auxv.h> 1562306a36Sopenharmony_ci#include <sys/mman.h> 1662306a36Sopenharmony_ci#include <sys/shm.h> 1762306a36Sopenharmony_ci#include <sys/ptrace.h> 1862306a36Sopenharmony_ci#include <sys/syscall.h> 1962306a36Sopenharmony_ci#include <sys/wait.h> 2062306a36Sopenharmony_ci#include <sys/uio.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "../kselftest.h" /* For __cpuid_count() */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifndef __x86_64__ 2562306a36Sopenharmony_ci# error This test is 64-bit only 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define XSAVE_HDR_OFFSET 512 2962306a36Sopenharmony_ci#define XSAVE_HDR_SIZE 64 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct xsave_buffer { 3262306a36Sopenharmony_ci union { 3362306a36Sopenharmony_ci struct { 3462306a36Sopenharmony_ci char legacy[XSAVE_HDR_OFFSET]; 3562306a36Sopenharmony_ci char header[XSAVE_HDR_SIZE]; 3662306a36Sopenharmony_ci char extended[0]; 3762306a36Sopenharmony_ci }; 3862306a36Sopenharmony_ci char bytes[0]; 3962306a36Sopenharmony_ci }; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic inline uint64_t xgetbv(uint32_t index) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci uint32_t eax, edx; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci asm volatile("xgetbv;" 4762306a36Sopenharmony_ci : "=a" (eax), "=d" (edx) 4862306a36Sopenharmony_ci : "c" (index)); 4962306a36Sopenharmony_ci return eax + ((uint64_t)edx << 32); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci uint32_t rfbm_lo = rfbm; 5562306a36Sopenharmony_ci uint32_t rfbm_hi = rfbm >> 32; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci asm volatile("xsave (%%rdi)" 5862306a36Sopenharmony_ci : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi) 5962306a36Sopenharmony_ci : "memory"); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci uint32_t rfbm_lo = rfbm; 6562306a36Sopenharmony_ci uint32_t rfbm_hi = rfbm >> 32; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci asm volatile("xrstor (%%rdi)" 6862306a36Sopenharmony_ci : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* err() exits and will not return */ 7262306a36Sopenharmony_ci#define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 7562306a36Sopenharmony_ci int flags) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct sigaction sa; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 8062306a36Sopenharmony_ci sa.sa_sigaction = handler; 8162306a36Sopenharmony_ci sa.sa_flags = SA_SIGINFO | flags; 8262306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 8362306a36Sopenharmony_ci if (sigaction(sig, &sa, 0)) 8462306a36Sopenharmony_ci fatal_error("sigaction"); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void clearhandler(int sig) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct sigaction sa; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 9262306a36Sopenharmony_ci sa.sa_handler = SIG_DFL; 9362306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 9462306a36Sopenharmony_ci if (sigaction(sig, &sa, 0)) 9562306a36Sopenharmony_ci fatal_error("sigaction"); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define XFEATURE_XTILECFG 17 9962306a36Sopenharmony_ci#define XFEATURE_XTILEDATA 18 10062306a36Sopenharmony_ci#define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) 10162306a36Sopenharmony_ci#define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) 10262306a36Sopenharmony_ci#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define CPUID_LEAF1_ECX_XSAVE_MASK (1 << 26) 10562306a36Sopenharmony_ci#define CPUID_LEAF1_ECX_OSXSAVE_MASK (1 << 27) 10662306a36Sopenharmony_cistatic inline void check_cpuid_xsave(void) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci uint32_t eax, ebx, ecx, edx; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * CPUID.1:ECX.XSAVE[bit 26] enumerates general 11262306a36Sopenharmony_ci * support for the XSAVE feature set, including 11362306a36Sopenharmony_ci * XGETBV. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci __cpuid_count(1, 0, eax, ebx, ecx, edx); 11662306a36Sopenharmony_ci if (!(ecx & CPUID_LEAF1_ECX_XSAVE_MASK)) 11762306a36Sopenharmony_ci fatal_error("cpuid: no CPU xsave support"); 11862306a36Sopenharmony_ci if (!(ecx & CPUID_LEAF1_ECX_OSXSAVE_MASK)) 11962306a36Sopenharmony_ci fatal_error("cpuid: no OS xsave support"); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic uint32_t xbuf_size; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic struct { 12562306a36Sopenharmony_ci uint32_t xbuf_offset; 12662306a36Sopenharmony_ci uint32_t size; 12762306a36Sopenharmony_ci} xtiledata; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define CPUID_LEAF_XSTATE 0xd 13062306a36Sopenharmony_ci#define CPUID_SUBLEAF_XSTATE_USER 0x0 13162306a36Sopenharmony_ci#define TILE_CPUID 0x1d 13262306a36Sopenharmony_ci#define TILE_PALETTE_ID 0x1 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void check_cpuid_xtiledata(void) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci uint32_t eax, ebx, ecx, edx; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci __cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER, 13962306a36Sopenharmony_ci eax, ebx, ecx, edx); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * EBX enumerates the size (in bytes) required by the XSAVE 14362306a36Sopenharmony_ci * instruction for an XSAVE area containing all the user state 14462306a36Sopenharmony_ci * components corresponding to bits currently set in XCR0. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * Stash that off so it can be used to allocate buffers later. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci xbuf_size = ebx; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci __cpuid_count(CPUID_LEAF_XSTATE, XFEATURE_XTILEDATA, 15162306a36Sopenharmony_ci eax, ebx, ecx, edx); 15262306a36Sopenharmony_ci /* 15362306a36Sopenharmony_ci * eax: XTILEDATA state component size 15462306a36Sopenharmony_ci * ebx: XTILEDATA state component offset in user buffer 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (!eax || !ebx) 15762306a36Sopenharmony_ci fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d", 15862306a36Sopenharmony_ci eax, ebx); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci xtiledata.size = eax; 16162306a36Sopenharmony_ci xtiledata.xbuf_offset = ebx; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* The helpers for managing XSAVE buffer and tile states: */ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistruct xsave_buffer *alloc_xbuf(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct xsave_buffer *xbuf; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* XSAVE buffer should be 64B-aligned. */ 17162306a36Sopenharmony_ci xbuf = aligned_alloc(64, xbuf_size); 17262306a36Sopenharmony_ci if (!xbuf) 17362306a36Sopenharmony_ci fatal_error("aligned_alloc()"); 17462306a36Sopenharmony_ci return xbuf; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic inline void clear_xstate_header(struct xsave_buffer *buffer) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci memset(&buffer->header, 0, sizeof(buffer->header)); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic inline uint64_t get_xstatebv(struct xsave_buffer *buffer) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci /* XSTATE_BV is at the beginning of the header: */ 18562306a36Sopenharmony_ci return *(uint64_t *)&buffer->header; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic inline void set_xstatebv(struct xsave_buffer *buffer, uint64_t bv) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci /* XSTATE_BV is at the beginning of the header: */ 19162306a36Sopenharmony_ci *(uint64_t *)(&buffer->header) = bv; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void set_rand_tiledata(struct xsave_buffer *xbuf) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int *ptr = (int *)&xbuf->bytes[xtiledata.xbuf_offset]; 19762306a36Sopenharmony_ci int data; 19862306a36Sopenharmony_ci int i; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * Ensure that 'data' is never 0. This ensures that 20262306a36Sopenharmony_ci * the registers are never in their initial configuration 20362306a36Sopenharmony_ci * and thus never tracked as being in the init state. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci data = rand() | 1; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci for (i = 0; i < xtiledata.size / sizeof(int); i++, ptr++) 20862306a36Sopenharmony_ci *ptr = data; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistruct xsave_buffer *stashed_xsave; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic void init_stashed_xsave(void) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci stashed_xsave = alloc_xbuf(); 21662306a36Sopenharmony_ci if (!stashed_xsave) 21762306a36Sopenharmony_ci fatal_error("failed to allocate stashed_xsave\n"); 21862306a36Sopenharmony_ci clear_xstate_header(stashed_xsave); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void free_stashed_xsave(void) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci free(stashed_xsave); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/* See 'struct _fpx_sw_bytes' at sigcontext.h */ 22762306a36Sopenharmony_ci#define SW_BYTES_OFFSET 464 22862306a36Sopenharmony_ci/* N.B. The struct's field name varies so read from the offset. */ 22962306a36Sopenharmony_ci#define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8) 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *buffer) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return (struct _fpx_sw_bytes *)(buffer + SW_BYTES_OFFSET); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic inline uint64_t get_fpx_sw_bytes_features(void *buffer) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* Work around printf() being unsafe in signals: */ 24262306a36Sopenharmony_ci#define SIGNAL_BUF_LEN 1000 24362306a36Sopenharmony_cichar signal_message_buffer[SIGNAL_BUF_LEN]; 24462306a36Sopenharmony_civoid sig_print(char *msg) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci strncat(signal_message_buffer, msg, left); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic volatile bool noperm_signaled; 25262306a36Sopenharmony_cistatic int noperm_errs; 25362306a36Sopenharmony_ci/* 25462306a36Sopenharmony_ci * Signal handler for when AMX is used but 25562306a36Sopenharmony_ci * permission has not been obtained. 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cistatic void handle_noperm(int sig, siginfo_t *si, void *ctx_void) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci ucontext_t *ctx = (ucontext_t *)ctx_void; 26062306a36Sopenharmony_ci void *xbuf = ctx->uc_mcontext.fpregs; 26162306a36Sopenharmony_ci struct _fpx_sw_bytes *sw_bytes; 26262306a36Sopenharmony_ci uint64_t features; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Reset the signal message buffer: */ 26562306a36Sopenharmony_ci signal_message_buffer[0] = '\0'; 26662306a36Sopenharmony_ci sig_print("\tAt SIGILL handler,\n"); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (si->si_code != ILL_ILLOPC) { 26962306a36Sopenharmony_ci noperm_errs++; 27062306a36Sopenharmony_ci sig_print("[FAIL]\tInvalid signal code.\n"); 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n"); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci sw_bytes = get_fpx_sw_bytes(xbuf); 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * Without permission, the signal XSAVE buffer should not 27862306a36Sopenharmony_ci * have room for AMX register state (aka. xtiledata). 27962306a36Sopenharmony_ci * Check that the size does not overlap with where xtiledata 28062306a36Sopenharmony_ci * will reside. 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * This also implies that no state components *PAST* 28362306a36Sopenharmony_ci * XTILEDATA (features >=19) can be present in the buffer. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci if (sw_bytes->xstate_size <= xtiledata.xbuf_offset) { 28662306a36Sopenharmony_ci sig_print("[OK]\tValid xstate size\n"); 28762306a36Sopenharmony_ci } else { 28862306a36Sopenharmony_ci noperm_errs++; 28962306a36Sopenharmony_ci sig_print("[FAIL]\tInvalid xstate size\n"); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci features = get_fpx_sw_bytes_features(xbuf); 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * Without permission, the XTILEDATA feature 29562306a36Sopenharmony_ci * bit should not be set. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci if ((features & XFEATURE_MASK_XTILEDATA) == 0) { 29862306a36Sopenharmony_ci sig_print("[OK]\tValid xstate mask\n"); 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci noperm_errs++; 30162306a36Sopenharmony_ci sig_print("[FAIL]\tInvalid xstate mask\n"); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci noperm_signaled = true; 30562306a36Sopenharmony_ci ctx->uc_mcontext.gregs[REG_RIP] += 3; /* Skip the faulting XRSTOR */ 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* Return true if XRSTOR is successful; otherwise, false. */ 30962306a36Sopenharmony_cistatic inline bool xrstor_safe(struct xsave_buffer *xbuf, uint64_t mask) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci noperm_signaled = false; 31262306a36Sopenharmony_ci xrstor(xbuf, mask); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Print any messages produced by the signal code: */ 31562306a36Sopenharmony_ci printf("%s", signal_message_buffer); 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * Reset the buffer to make sure any future printing 31862306a36Sopenharmony_ci * only outputs new messages: 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci signal_message_buffer[0] = '\0'; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (noperm_errs) 32362306a36Sopenharmony_ci fatal_error("saw %d errors in noperm signal handler\n", noperm_errs); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return !noperm_signaled; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* 32962306a36Sopenharmony_ci * Use XRSTOR to populate the XTILEDATA registers with 33062306a36Sopenharmony_ci * random data. 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Return true if successful; otherwise, false. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_cistatic inline bool load_rand_tiledata(struct xsave_buffer *xbuf) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci clear_xstate_header(xbuf); 33762306a36Sopenharmony_ci set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA); 33862306a36Sopenharmony_ci set_rand_tiledata(xbuf); 33962306a36Sopenharmony_ci return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/* Return XTILEDATA to its initial configuration. */ 34362306a36Sopenharmony_cistatic inline void init_xtiledata(void) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci clear_xstate_header(stashed_xsave); 34662306a36Sopenharmony_ci xrstor_safe(stashed_xsave, XFEATURE_MASK_XTILEDATA); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cienum expected_result { FAIL_EXPECTED, SUCCESS_EXPECTED }; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* arch_prctl() and sigaltstack() test */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci#define ARCH_GET_XCOMP_PERM 0x1022 35462306a36Sopenharmony_ci#define ARCH_REQ_XCOMP_PERM 0x1023 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void req_xtiledata_perm(void) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void validate_req_xcomp_perm(enum expected_result exp) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci unsigned long bitmask, expected_bitmask; 36462306a36Sopenharmony_ci long rc; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask); 36762306a36Sopenharmony_ci if (rc) { 36862306a36Sopenharmony_ci fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc); 36962306a36Sopenharmony_ci } else if (!(bitmask & XFEATURE_MASK_XTILECFG)) { 37062306a36Sopenharmony_ci fatal_error("ARCH_GET_XCOMP_PERM returns XFEATURE_XTILECFG off."); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILEDATA); 37462306a36Sopenharmony_ci if (exp == FAIL_EXPECTED) { 37562306a36Sopenharmony_ci if (rc) { 37662306a36Sopenharmony_ci printf("[OK]\tARCH_REQ_XCOMP_PERM saw expected failure..\n"); 37762306a36Sopenharmony_ci return; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected success.\n"); 38162306a36Sopenharmony_ci } else if (rc) { 38262306a36Sopenharmony_ci fatal_error("ARCH_REQ_XCOMP_PERM saw unexpected failure.\n"); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci expected_bitmask = bitmask | XFEATURE_MASK_XTILEDATA; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_PERM, &bitmask); 38862306a36Sopenharmony_ci if (rc) { 38962306a36Sopenharmony_ci fatal_error("prctl(ARCH_GET_XCOMP_PERM) error: %ld", rc); 39062306a36Sopenharmony_ci } else if (bitmask != expected_bitmask) { 39162306a36Sopenharmony_ci fatal_error("ARCH_REQ_XCOMP_PERM set a wrong bitmask: %lx, expected: %lx.\n", 39262306a36Sopenharmony_ci bitmask, expected_bitmask); 39362306a36Sopenharmony_ci } else { 39462306a36Sopenharmony_ci printf("\tARCH_REQ_XCOMP_PERM is successful.\n"); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic void validate_xcomp_perm(enum expected_result exp) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci bool load_success = load_rand_tiledata(stashed_xsave); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (exp == FAIL_EXPECTED) { 40362306a36Sopenharmony_ci if (load_success) { 40462306a36Sopenharmony_ci noperm_errs++; 40562306a36Sopenharmony_ci printf("[FAIL]\tLoad tiledata succeeded.\n"); 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci printf("[OK]\tLoad tiledata failed.\n"); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci } else if (exp == SUCCESS_EXPECTED) { 41062306a36Sopenharmony_ci if (load_success) { 41162306a36Sopenharmony_ci printf("[OK]\tLoad tiledata succeeded.\n"); 41262306a36Sopenharmony_ci } else { 41362306a36Sopenharmony_ci noperm_errs++; 41462306a36Sopenharmony_ci printf("[FAIL]\tLoad tiledata failed.\n"); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci#ifndef AT_MINSIGSTKSZ 42062306a36Sopenharmony_ci# define AT_MINSIGSTKSZ 51 42162306a36Sopenharmony_ci#endif 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void *alloc_altstack(unsigned int size) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci void *altstack; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci altstack = mmap(NULL, size, PROT_READ | PROT_WRITE, 42862306a36Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (altstack == MAP_FAILED) 43162306a36Sopenharmony_ci fatal_error("mmap() for altstack"); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return altstack; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic void setup_altstack(void *addr, unsigned long size, enum expected_result exp) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci stack_t ss; 43962306a36Sopenharmony_ci int rc; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci memset(&ss, 0, sizeof(ss)); 44262306a36Sopenharmony_ci ss.ss_size = size; 44362306a36Sopenharmony_ci ss.ss_sp = addr; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci rc = sigaltstack(&ss, NULL); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (exp == FAIL_EXPECTED) { 44862306a36Sopenharmony_ci if (rc) { 44962306a36Sopenharmony_ci printf("[OK]\tsigaltstack() failed.\n"); 45062306a36Sopenharmony_ci } else { 45162306a36Sopenharmony_ci fatal_error("sigaltstack() succeeded unexpectedly.\n"); 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } else if (rc) { 45462306a36Sopenharmony_ci fatal_error("sigaltstack()"); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void test_dynamic_sigaltstack(void) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci unsigned int small_size, enough_size; 46162306a36Sopenharmony_ci unsigned long minsigstksz; 46262306a36Sopenharmony_ci void *altstack; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci minsigstksz = getauxval(AT_MINSIGSTKSZ); 46562306a36Sopenharmony_ci printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz); 46662306a36Sopenharmony_ci /* 46762306a36Sopenharmony_ci * getauxval() itself can return 0 for failure or 46862306a36Sopenharmony_ci * success. But, in this case, AT_MINSIGSTKSZ 46962306a36Sopenharmony_ci * will always return a >=0 value if implemented. 47062306a36Sopenharmony_ci * Just check for 0. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci if (minsigstksz == 0) { 47362306a36Sopenharmony_ci printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n"); 47462306a36Sopenharmony_ci return; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci enough_size = minsigstksz * 2; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci altstack = alloc_altstack(enough_size); 48062306a36Sopenharmony_ci printf("\tAllocate memory for altstack (%u bytes).\n", enough_size); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * Try setup_altstack() with a size which can not fit 48462306a36Sopenharmony_ci * XTILEDATA. ARCH_REQ_XCOMP_PERM should fail. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci small_size = minsigstksz - xtiledata.size; 48762306a36Sopenharmony_ci printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size); 48862306a36Sopenharmony_ci setup_altstack(altstack, small_size, SUCCESS_EXPECTED); 48962306a36Sopenharmony_ci validate_req_xcomp_perm(FAIL_EXPECTED); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * Try setup_altstack() with a size derived from 49362306a36Sopenharmony_ci * AT_MINSIGSTKSZ. It should be more than large enough 49462306a36Sopenharmony_ci * and thus ARCH_REQ_XCOMP_PERM should succeed. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size); 49762306a36Sopenharmony_ci setup_altstack(altstack, enough_size, SUCCESS_EXPECTED); 49862306a36Sopenharmony_ci validate_req_xcomp_perm(SUCCESS_EXPECTED); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* 50162306a36Sopenharmony_ci * Try to coerce setup_altstack() to again accept a 50262306a36Sopenharmony_ci * too-small altstack. This ensures that big-enough 50362306a36Sopenharmony_ci * sigaltstacks can not shrink to a too-small value 50462306a36Sopenharmony_ci * once XTILEDATA permission is established. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size); 50762306a36Sopenharmony_ci setup_altstack(altstack, small_size, FAIL_EXPECTED); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void test_dynamic_state(void) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci pid_t parent, child, grandchild; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci parent = fork(); 51562306a36Sopenharmony_ci if (parent < 0) { 51662306a36Sopenharmony_ci /* fork() failed */ 51762306a36Sopenharmony_ci fatal_error("fork"); 51862306a36Sopenharmony_ci } else if (parent > 0) { 51962306a36Sopenharmony_ci int status; 52062306a36Sopenharmony_ci /* fork() succeeded. Now in the parent. */ 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci wait(&status); 52362306a36Sopenharmony_ci if (!WIFEXITED(status) || WEXITSTATUS(status)) 52462306a36Sopenharmony_ci fatal_error("arch_prctl test parent exit"); 52562306a36Sopenharmony_ci return; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci /* fork() succeeded. Now in the child . */ 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n"); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci printf("\tFork a child.\n"); 53262306a36Sopenharmony_ci child = fork(); 53362306a36Sopenharmony_ci if (child < 0) { 53462306a36Sopenharmony_ci fatal_error("fork"); 53562306a36Sopenharmony_ci } else if (child > 0) { 53662306a36Sopenharmony_ci int status; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci wait(&status); 53962306a36Sopenharmony_ci if (!WIFEXITED(status) || WEXITSTATUS(status)) 54062306a36Sopenharmony_ci fatal_error("arch_prctl test child exit"); 54162306a36Sopenharmony_ci _exit(0); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* 54562306a36Sopenharmony_ci * The permission request should fail without an 54662306a36Sopenharmony_ci * XTILEDATA-compatible signal stack 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci printf("\tTest XCOMP_PERM at child.\n"); 54962306a36Sopenharmony_ci validate_xcomp_perm(FAIL_EXPECTED); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* 55262306a36Sopenharmony_ci * Set up an XTILEDATA-compatible signal stack and 55362306a36Sopenharmony_ci * also obtain permission to populate XTILEDATA. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci printf("\tTest dynamic sigaltstack at child:\n"); 55662306a36Sopenharmony_ci test_dynamic_sigaltstack(); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Ensure that XTILEDATA can be populated. */ 55962306a36Sopenharmony_ci printf("\tTest XCOMP_PERM again at child.\n"); 56062306a36Sopenharmony_ci validate_xcomp_perm(SUCCESS_EXPECTED); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci printf("\tFork a grandchild.\n"); 56362306a36Sopenharmony_ci grandchild = fork(); 56462306a36Sopenharmony_ci if (grandchild < 0) { 56562306a36Sopenharmony_ci /* fork() failed */ 56662306a36Sopenharmony_ci fatal_error("fork"); 56762306a36Sopenharmony_ci } else if (!grandchild) { 56862306a36Sopenharmony_ci /* fork() succeeded. Now in the (grand)child. */ 56962306a36Sopenharmony_ci printf("\tTest XCOMP_PERM at grandchild.\n"); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * Ensure that the grandchild inherited 57362306a36Sopenharmony_ci * permission and a compatible sigaltstack: 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_ci validate_xcomp_perm(SUCCESS_EXPECTED); 57662306a36Sopenharmony_ci } else { 57762306a36Sopenharmony_ci int status; 57862306a36Sopenharmony_ci /* fork() succeeded. Now in the parent. */ 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci wait(&status); 58162306a36Sopenharmony_ci if (!WIFEXITED(status) || WEXITSTATUS(status)) 58262306a36Sopenharmony_ci fatal_error("fork test grandchild"); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci _exit(0); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic inline int __compare_tiledata_state(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci return memcmp(&xbuf1->bytes[xtiledata.xbuf_offset], 59162306a36Sopenharmony_ci &xbuf2->bytes[xtiledata.xbuf_offset], 59262306a36Sopenharmony_ci xtiledata.size); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* 59662306a36Sopenharmony_ci * Save current register state and compare it to @xbuf1.' 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * Returns false if @xbuf1 matches the registers. 59962306a36Sopenharmony_ci * Returns true if @xbuf1 differs from the registers. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_cistatic inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct xsave_buffer *xbuf2; 60462306a36Sopenharmony_ci int ret; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci xbuf2 = alloc_xbuf(); 60762306a36Sopenharmony_ci if (!xbuf2) 60862306a36Sopenharmony_ci fatal_error("failed to allocate XSAVE buffer\n"); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci xsave(xbuf2, XFEATURE_MASK_XTILEDATA); 61162306a36Sopenharmony_ci ret = __compare_tiledata_state(xbuf1, xbuf2); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci free(xbuf2); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (ret == 0) 61662306a36Sopenharmony_ci return false; 61762306a36Sopenharmony_ci return true; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic inline void validate_tiledata_regs_same(struct xsave_buffer *xbuf) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci int ret = __validate_tiledata_regs(xbuf); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (ret != 0) 62562306a36Sopenharmony_ci fatal_error("TILEDATA registers changed"); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic inline void validate_tiledata_regs_changed(struct xsave_buffer *xbuf) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci int ret = __validate_tiledata_regs(xbuf); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (ret == 0) 63362306a36Sopenharmony_ci fatal_error("TILEDATA registers did not change"); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/* tiledata inheritance test */ 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic void test_fork(void) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci pid_t child, grandchild; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci child = fork(); 64362306a36Sopenharmony_ci if (child < 0) { 64462306a36Sopenharmony_ci /* fork() failed */ 64562306a36Sopenharmony_ci fatal_error("fork"); 64662306a36Sopenharmony_ci } else if (child > 0) { 64762306a36Sopenharmony_ci /* fork() succeeded. Now in the parent. */ 64862306a36Sopenharmony_ci int status; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci wait(&status); 65162306a36Sopenharmony_ci if (!WIFEXITED(status) || WEXITSTATUS(status)) 65262306a36Sopenharmony_ci fatal_error("fork test child"); 65362306a36Sopenharmony_ci return; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci /* fork() succeeded. Now in the child. */ 65662306a36Sopenharmony_ci printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n"); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci load_rand_tiledata(stashed_xsave); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci grandchild = fork(); 66162306a36Sopenharmony_ci if (grandchild < 0) { 66262306a36Sopenharmony_ci /* fork() failed */ 66362306a36Sopenharmony_ci fatal_error("fork"); 66462306a36Sopenharmony_ci } else if (grandchild > 0) { 66562306a36Sopenharmony_ci /* fork() succeeded. Still in the first child. */ 66662306a36Sopenharmony_ci int status; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci wait(&status); 66962306a36Sopenharmony_ci if (!WIFEXITED(status) || WEXITSTATUS(status)) 67062306a36Sopenharmony_ci fatal_error("fork test grand child"); 67162306a36Sopenharmony_ci _exit(0); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci /* fork() succeeded. Now in the (grand)child. */ 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* 67662306a36Sopenharmony_ci * TILEDATA registers are not preserved across fork(). 67762306a36Sopenharmony_ci * Ensure that their value has changed: 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci validate_tiledata_regs_changed(stashed_xsave); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci _exit(0); 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci/* Context switching test */ 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic struct _ctxtswtest_cfg { 68762306a36Sopenharmony_ci unsigned int iterations; 68862306a36Sopenharmony_ci unsigned int num_threads; 68962306a36Sopenharmony_ci} ctxtswtest_config; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistruct futex_info { 69262306a36Sopenharmony_ci pthread_t thread; 69362306a36Sopenharmony_ci int nr; 69462306a36Sopenharmony_ci pthread_mutex_t mutex; 69562306a36Sopenharmony_ci struct futex_info *next; 69662306a36Sopenharmony_ci}; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic void *check_tiledata(void *info) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct futex_info *finfo = (struct futex_info *)info; 70162306a36Sopenharmony_ci struct xsave_buffer *xbuf; 70262306a36Sopenharmony_ci int i; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci xbuf = alloc_xbuf(); 70562306a36Sopenharmony_ci if (!xbuf) 70662306a36Sopenharmony_ci fatal_error("unable to allocate XSAVE buffer"); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* 70962306a36Sopenharmony_ci * Load random data into 'xbuf' and then restore 71062306a36Sopenharmony_ci * it to the tile registers themselves. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci load_rand_tiledata(xbuf); 71362306a36Sopenharmony_ci for (i = 0; i < ctxtswtest_config.iterations; i++) { 71462306a36Sopenharmony_ci pthread_mutex_lock(&finfo->mutex); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* 71762306a36Sopenharmony_ci * Ensure the register values have not 71862306a36Sopenharmony_ci * diverged from those recorded in 'xbuf'. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci validate_tiledata_regs_same(xbuf); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* Load new, random values into xbuf and registers */ 72362306a36Sopenharmony_ci load_rand_tiledata(xbuf); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* 72662306a36Sopenharmony_ci * The last thread's last unlock will be for 72762306a36Sopenharmony_ci * thread 0's mutex. However, thread 0 will 72862306a36Sopenharmony_ci * have already exited the loop and the mutex 72962306a36Sopenharmony_ci * will already be unlocked. 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * Because this is not an ERRORCHECK mutex, 73262306a36Sopenharmony_ci * that inconsistency will be silently ignored. 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_ci pthread_mutex_unlock(&finfo->next->mutex); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci free(xbuf); 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * Return this thread's finfo, which is 74062306a36Sopenharmony_ci * a unique value for this thread. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci return finfo; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int create_threads(int num, struct futex_info *finfo) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci int i; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci for (i = 0; i < num; i++) { 75062306a36Sopenharmony_ci int next_nr; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci finfo[i].nr = i; 75362306a36Sopenharmony_ci /* 75462306a36Sopenharmony_ci * Thread 'i' will wait on this mutex to 75562306a36Sopenharmony_ci * be unlocked. Lock it immediately after 75662306a36Sopenharmony_ci * initialization: 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ci pthread_mutex_init(&finfo[i].mutex, NULL); 75962306a36Sopenharmony_ci pthread_mutex_lock(&finfo[i].mutex); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci next_nr = (i + 1) % num; 76262306a36Sopenharmony_ci finfo[i].next = &finfo[next_nr]; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (pthread_create(&finfo[i].thread, NULL, check_tiledata, &finfo[i])) 76562306a36Sopenharmony_ci fatal_error("pthread_create()"); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void affinitize_cpu0(void) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci cpu_set_t cpuset; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci CPU_ZERO(&cpuset); 77562306a36Sopenharmony_ci CPU_SET(0, &cpuset); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) 77862306a36Sopenharmony_ci fatal_error("sched_setaffinity to CPU 0"); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic void test_context_switch(void) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct futex_info *finfo; 78462306a36Sopenharmony_ci int i; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* Affinitize to one CPU to force context switches */ 78762306a36Sopenharmony_ci affinitize_cpu0(); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci req_xtiledata_perm(); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci printf("[RUN]\tCheck tiledata context switches, %d iterations, %d threads.\n", 79262306a36Sopenharmony_ci ctxtswtest_config.iterations, 79362306a36Sopenharmony_ci ctxtswtest_config.num_threads); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci finfo = malloc(sizeof(*finfo) * ctxtswtest_config.num_threads); 79762306a36Sopenharmony_ci if (!finfo) 79862306a36Sopenharmony_ci fatal_error("malloc()"); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci create_threads(ctxtswtest_config.num_threads, finfo); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * This thread wakes up thread 0 80462306a36Sopenharmony_ci * Thread 0 will wake up 1 80562306a36Sopenharmony_ci * Thread 1 will wake up 2 80662306a36Sopenharmony_ci * ... 80762306a36Sopenharmony_ci * the last thread will wake up 0 80862306a36Sopenharmony_ci * 80962306a36Sopenharmony_ci * ... this will repeat for the configured 81062306a36Sopenharmony_ci * number of iterations. 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_ci pthread_mutex_unlock(&finfo[0].mutex); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Wait for all the threads to finish: */ 81562306a36Sopenharmony_ci for (i = 0; i < ctxtswtest_config.num_threads; i++) { 81662306a36Sopenharmony_ci void *thread_retval; 81762306a36Sopenharmony_ci int rc; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci rc = pthread_join(finfo[i].thread, &thread_retval); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (rc) 82262306a36Sopenharmony_ci fatal_error("pthread_join() failed for thread %d err: %d\n", 82362306a36Sopenharmony_ci i, rc); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (thread_retval != &finfo[i]) 82662306a36Sopenharmony_ci fatal_error("unexpected thread retval for thread %d: %p\n", 82762306a36Sopenharmony_ci i, thread_retval); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci printf("[OK]\tNo incorrect case was found.\n"); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci free(finfo); 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci/* Ptrace test */ 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/* 83962306a36Sopenharmony_ci * Make sure the ptracee has the expanded kernel buffer on the first 84062306a36Sopenharmony_ci * use. Then, initialize the state before performing the state 84162306a36Sopenharmony_ci * injection from the ptracer. 84262306a36Sopenharmony_ci */ 84362306a36Sopenharmony_cistatic inline void ptracee_firstuse_tiledata(void) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci load_rand_tiledata(stashed_xsave); 84662306a36Sopenharmony_ci init_xtiledata(); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci/* 85062306a36Sopenharmony_ci * Ptracer injects the randomized tile data state. It also reads 85162306a36Sopenharmony_ci * before and after that, which will execute the kernel's state copy 85262306a36Sopenharmony_ci * functions. So, the tester is advised to double-check any emitted 85362306a36Sopenharmony_ci * kernel messages. 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_cistatic void ptracer_inject_tiledata(pid_t target) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct xsave_buffer *xbuf; 85862306a36Sopenharmony_ci struct iovec iov; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci xbuf = alloc_xbuf(); 86162306a36Sopenharmony_ci if (!xbuf) 86262306a36Sopenharmony_ci fatal_error("unable to allocate XSAVE buffer"); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci printf("\tRead the init'ed tiledata via ptrace().\n"); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci iov.iov_base = xbuf; 86762306a36Sopenharmony_ci iov.iov_len = xbuf_size; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci memset(stashed_xsave, 0, xbuf_size); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) 87262306a36Sopenharmony_ci fatal_error("PTRACE_GETREGSET"); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (!__compare_tiledata_state(stashed_xsave, xbuf)) 87562306a36Sopenharmony_ci printf("[OK]\tThe init'ed tiledata was read from ptracee.\n"); 87662306a36Sopenharmony_ci else 87762306a36Sopenharmony_ci printf("[FAIL]\tThe init'ed tiledata was not read from ptracee.\n"); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci printf("\tInject tiledata via ptrace().\n"); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci load_rand_tiledata(xbuf); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci memcpy(&stashed_xsave->bytes[xtiledata.xbuf_offset], 88462306a36Sopenharmony_ci &xbuf->bytes[xtiledata.xbuf_offset], 88562306a36Sopenharmony_ci xtiledata.size); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) 88862306a36Sopenharmony_ci fatal_error("PTRACE_SETREGSET"); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) 89162306a36Sopenharmony_ci fatal_error("PTRACE_GETREGSET"); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (!__compare_tiledata_state(stashed_xsave, xbuf)) 89462306a36Sopenharmony_ci printf("[OK]\tTiledata was correctly written to ptracee.\n"); 89562306a36Sopenharmony_ci else 89662306a36Sopenharmony_ci printf("[FAIL]\tTiledata was not correctly written to ptracee.\n"); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic void test_ptrace(void) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci pid_t child; 90262306a36Sopenharmony_ci int status; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci child = fork(); 90562306a36Sopenharmony_ci if (child < 0) { 90662306a36Sopenharmony_ci err(1, "fork"); 90762306a36Sopenharmony_ci } else if (!child) { 90862306a36Sopenharmony_ci if (ptrace(PTRACE_TRACEME, 0, NULL, NULL)) 90962306a36Sopenharmony_ci err(1, "PTRACE_TRACEME"); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci ptracee_firstuse_tiledata(); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci raise(SIGTRAP); 91462306a36Sopenharmony_ci _exit(0); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci do { 91862306a36Sopenharmony_ci wait(&status); 91962306a36Sopenharmony_ci } while (WSTOPSIG(status) != SIGTRAP); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ptracer_inject_tiledata(child); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci ptrace(PTRACE_DETACH, child, NULL, NULL); 92462306a36Sopenharmony_ci wait(&status); 92562306a36Sopenharmony_ci if (!WIFEXITED(status) || WEXITSTATUS(status)) 92662306a36Sopenharmony_ci err(1, "ptrace test"); 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ciint main(void) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci /* Check hardware availability at first */ 93262306a36Sopenharmony_ci check_cpuid_xsave(); 93362306a36Sopenharmony_ci check_cpuid_xtiledata(); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci init_stashed_xsave(); 93662306a36Sopenharmony_ci sethandler(SIGILL, handle_noperm, 0); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci test_dynamic_state(); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* Request permission for the following tests */ 94162306a36Sopenharmony_ci req_xtiledata_perm(); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci test_fork(); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci ctxtswtest_config.iterations = 10; 94662306a36Sopenharmony_ci ctxtswtest_config.num_threads = 5; 94762306a36Sopenharmony_ci test_context_switch(); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci test_ptrace(); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci clearhandler(SIGILL); 95262306a36Sopenharmony_ci free_stashed_xsave(); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci} 956