From patchwork Wed Feb 26 01:07:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991199 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C9D4342A9D; Wed, 26 Feb 2025 01:07:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532058; cv=none; b=jRIAOPRgTAxUuFK+4K2Z9NoFHy4hh+6dOlQzrZEm0SvLosn3JObaLpzYiqHRQSTqxEut/STaTdqj0/TlYndjDwWTGVotD+YSmRIoELRRBY1g4tzCzmStgrIIJetFBzMzEmzHuVcywokJkISK5lkyB2r9r1asWdWEVRkpgyLSCic= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532058; c=relaxed/simple; bh=CDBcft1we3o/9e/Ovr02k3sW+m+b+C4klkPtxBiADrI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TfGYx02Xd1n82OxzLkjzMjo6T07SocDKXFErR+soM0NrNQ21truQiSZ0FtPvAachN3xZUb0sAUkpdxfz6uPXSsYDeg7c74il/qLR55+W6Yj3IQUch0ho/oBT30vK6KB/fmztHqXR8AS8g6owFiv/b7T4AkxTLs3kMke51An2q8I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=S6wJRlTP; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="S6wJRlTP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532055; x=1772068055; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CDBcft1we3o/9e/Ovr02k3sW+m+b+C4klkPtxBiADrI=; b=S6wJRlTP7j/YNnNuqtd/FBhdJpv4I2UssZapI2kaOLfW7C6/6xoHSNwW WBXos4vnhBvuZnPcsmK3VOxWryTh1ft/p0r/lNEkaPS/lv+eQfd52Ajmb WUNrDfO11GpmP1UN+XGYKa5juiDcNvlt34VAl87/59wnOsiSli1/Yn396 T1z1CZE5QFm/0kv/vHu7IRqefMhZCO6beTZ/EiyJ3O5E1IViZh2cRca98 kf6nn4cl+4z5IRiAfRJ06cuET3ejTVdTDBHhv7mf2wPY+frMAUxdtAcXF hSML001vqeox5zxZ9x+rPKU6vn9qHfzbjCyWp04kx4wR/7rQX19icr5az g==; X-CSE-ConnectionGUID: 8OjaT546SFOGaxe/N5XcWw== X-CSE-MsgGUID: ThwQq+EvRTyFaebYyj4Ttg== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362178" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362178" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:34 -0800 X-CSE-ConnectionGUID: Dk7yFpSgR96F6IbRCfxjCQ== X-CSE-MsgGUID: V3oTVSOnTL6JDtR63UvfLA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467335" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:33 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 1/9] selftests/x86: Consolidate redundant signal helper functions Date: Tue, 25 Feb 2025 17:07:21 -0800 Message-ID: <20250226010731.2456-2-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The x86 selftests frequently register and clean up signal handlers, but the sethandler() and clearhandler() functions have been redundantly copied across multiple .c files. Move these functions to helpers.h to enable reuse across tests, eliminating around 250 lines of duplicate code. Converge the error handling by using ksft_exit_fail_msg(), which is functionally equivalent with err() within the selftest framework. Signed-off-by: Chang S. Bae --- This change is a prerequisite for the upcoming xstate selftest, which requires signal handling for registering and cleaning up handlers. References: * ksft_exit_fail_msg() https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/testing/selftests/kselftest.h#n383 * err() https://sourceware.org/git/?p=glibc.git;a=blob;f=misc/err.c;h=2528d36e2da0f9c020c9a0bea3e18ae444f17ea8;hb=HEAD#l103 --- tools/testing/selftests/x86/amx.c | 25 +---------------- .../selftests/x86/corrupt_xstate_header.c | 14 +--------- tools/testing/selftests/x86/entry_from_vm86.c | 24 ++-------------- tools/testing/selftests/x86/fsgsbase.c | 24 ++-------------- tools/testing/selftests/x86/helpers.h | 28 +++++++++++++++++++ tools/testing/selftests/x86/ioperm.c | 25 ++--------------- tools/testing/selftests/x86/iopl.c | 25 ++--------------- tools/testing/selftests/x86/ldt_gdt.c | 18 +++--------- tools/testing/selftests/x86/mov_ss_trap.c | 14 +--------- tools/testing/selftests/x86/ptrace_syscall.c | 24 ++-------------- tools/testing/selftests/x86/sigaltstack.c | 26 ++--------------- tools/testing/selftests/x86/sigreturn.c | 24 ++-------------- .../selftests/x86/single_step_syscall.c | 22 --------------- .../testing/selftests/x86/syscall_arg_fault.c | 12 -------- tools/testing/selftests/x86/syscall_nt.c | 12 -------- tools/testing/selftests/x86/sysret_rip.c | 24 ++-------------- tools/testing/selftests/x86/test_vsyscall.c | 13 --------- tools/testing/selftests/x86/unwind_vdso.c | 12 -------- 18 files changed, 51 insertions(+), 315 deletions(-) diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index 1fdf35a4d7f6..0f355f331f41 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -20,6 +20,7 @@ #include #include "../kselftest.h" /* For __cpuid_count() */ +#include "helpers.h" #ifndef __x86_64__ # error This test is 64-bit only @@ -61,30 +62,6 @@ static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) /* err() exits and will not return */ #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__) -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - fatal_error("sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - fatal_error("sigaction"); -} - #define XFEATURE_XTILECFG 17 #define XFEATURE_XTILEDATA 18 #define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) diff --git a/tools/testing/selftests/x86/corrupt_xstate_header.c b/tools/testing/selftests/x86/corrupt_xstate_header.c index cf9ce8fbb656..93a89a5997ca 100644 --- a/tools/testing/selftests/x86/corrupt_xstate_header.c +++ b/tools/testing/selftests/x86/corrupt_xstate_header.c @@ -18,6 +18,7 @@ #include #include "../kselftest.h" /* For __cpuid_count() */ +#include "helpers.h" static inline int xsave_enabled(void) { @@ -29,19 +30,6 @@ static inline int xsave_enabled(void) return ecx & (1U << 27); } -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static void sigusr1(int sig, siginfo_t *info, void *uc_void) { ucontext_t *uc = uc_void; diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index d1e919b0c1dc..5cb8393737d0 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -24,31 +24,11 @@ #include #include +#include "helpers.h" + static unsigned long load_addr = 0x10000; static int nerrs = 0; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static sig_atomic_t got_signal; static void sighandler(int sig, siginfo_t *info, void *ctx_void) diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c index 50cf32de6313..0a75252d31b6 100644 --- a/tools/testing/selftests/x86/fsgsbase.c +++ b/tools/testing/selftests/x86/fsgsbase.c @@ -28,6 +28,8 @@ #include #include +#include "helpers.h" + #ifndef __x86_64__ # error This test is 64-bit only #endif @@ -39,28 +41,6 @@ static unsigned short *shared_scratch; static int nerrs; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static void sigsegv(int sig, siginfo_t *si, void *ctx_void) { ucontext_t *ctx = (ucontext_t*)ctx_void; diff --git a/tools/testing/selftests/x86/helpers.h b/tools/testing/selftests/x86/helpers.h index 4ef42c4559a9..6deaad035161 100644 --- a/tools/testing/selftests/x86/helpers.h +++ b/tools/testing/selftests/x86/helpers.h @@ -2,8 +2,13 @@ #ifndef __SELFTESTS_X86_HELPERS_H #define __SELFTESTS_X86_HELPERS_H +#include +#include + #include +#include "../kselftest.h" + static inline unsigned long get_eflags(void) { #ifdef __x86_64__ @@ -22,4 +27,27 @@ static inline void set_eflags(unsigned long eflags) #endif } +static inline void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), int flags) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + ksft_exit_fail_msg("sigaction failed"); +} + +static inline void clearhandler(int sig) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + if (sigaction(sig, &sa, 0)) + ksft_exit_fail_msg("sigaction failed"); +} + #endif /* __SELFTESTS_X86_HELPERS_H */ diff --git a/tools/testing/selftests/x86/ioperm.c b/tools/testing/selftests/x86/ioperm.c index 57ec5e99edb9..69d5fb7050c2 100644 --- a/tools/testing/selftests/x86/ioperm.c +++ b/tools/testing/selftests/x86/ioperm.c @@ -20,31 +20,10 @@ #include #include +#include "helpers.h" + static int nerrs = 0; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); - -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static jmp_buf jmpbuf; static void sigsegv(int sig, siginfo_t *si, void *ctx_void) diff --git a/tools/testing/selftests/x86/iopl.c b/tools/testing/selftests/x86/iopl.c index 7e3e09c1abac..457b6715542b 100644 --- a/tools/testing/selftests/x86/iopl.c +++ b/tools/testing/selftests/x86/iopl.c @@ -20,31 +20,10 @@ #include #include +#include "helpers.h" + static int nerrs = 0; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); - -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static jmp_buf jmpbuf; static void sigsegv(int sig, siginfo_t *si, void *ctx_void) diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c index 3a29346e1452..bb99a71380a5 100644 --- a/tools/testing/selftests/x86/ldt_gdt.c +++ b/tools/testing/selftests/x86/ldt_gdt.c @@ -26,6 +26,8 @@ #include #include +#include "helpers.h" + #define AR_ACCESSED (1<<8) #define AR_TYPE_RODATA (0 * (1<<9)) @@ -506,20 +508,6 @@ static void fix_sa_restorer(int sig) } #endif -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); - - fix_sa_restorer(sig); -} - static jmp_buf jmpbuf; static void sigsegv(int sig, siginfo_t *info, void *ctx_void) @@ -549,9 +537,11 @@ static void do_multicpu_tests(void) } sethandler(SIGSEGV, sigsegv, 0); + fix_sa_restorer(SIGSEGV); #ifdef __i386__ /* True 32-bit kernels send SIGILL instead of SIGSEGV on IRET faults. */ sethandler(SIGILL, sigsegv, 0); + fix_sa_restorer(SIGILL); #endif printf("[RUN]\tCross-CPU LDT invalidation\n"); diff --git a/tools/testing/selftests/x86/mov_ss_trap.c b/tools/testing/selftests/x86/mov_ss_trap.c index cc3de6ff9fba..f22cb6b382f9 100644 --- a/tools/testing/selftests/x86/mov_ss_trap.c +++ b/tools/testing/selftests/x86/mov_ss_trap.c @@ -36,7 +36,7 @@ #include #include -#define X86_EFLAGS_RF (1UL << 16) +#include "helpers.h" #if __x86_64__ # define REG_IP REG_RIP @@ -94,18 +94,6 @@ static void enable_watchpoint(void) } } -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static char const * const signames[] = { [SIGSEGV] = "SIGSEGV", [SIGBUS] = "SIBGUS", diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c index 12aaa063196e..360ec88d5432 100644 --- a/tools/testing/selftests/x86/ptrace_syscall.c +++ b/tools/testing/selftests/x86/ptrace_syscall.c @@ -15,6 +15,8 @@ #include #include +#include "helpers.h" + /* Bitness-agnostic defines for user_regs_struct fields. */ #ifdef __x86_64__ # define user_syscall_nr orig_rax @@ -93,18 +95,6 @@ static siginfo_t wait_trap(pid_t chld) return si; } -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static void setsigign(int sig, int flags) { struct sigaction sa; @@ -116,16 +106,6 @@ static void setsigign(int sig, int flags) err(1, "sigaction"); } -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - #ifdef __x86_64__ # define REG_BP REG_RBP #else diff --git a/tools/testing/selftests/x86/sigaltstack.c b/tools/testing/selftests/x86/sigaltstack.c index f689af75e979..0ae1b784498c 100644 --- a/tools/testing/selftests/x86/sigaltstack.c +++ b/tools/testing/selftests/x86/sigaltstack.c @@ -14,6 +14,8 @@ #include #include +#include "helpers.h" + /* sigaltstack()-enforced minimum stack */ #define ENFORCED_MINSIGSTKSZ 2048 @@ -27,30 +29,6 @@ static bool sigalrm_expected; static unsigned long at_minstack_size; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static int setup_altstack(void *start, unsigned long size) { stack_t ss; diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c index 0b75b29f794b..26ef562f4232 100644 --- a/tools/testing/selftests/x86/sigreturn.c +++ b/tools/testing/selftests/x86/sigreturn.c @@ -46,6 +46,8 @@ #include #include +#include "helpers.h" + /* Pull in AR_xyz defines. */ typedef unsigned int u32; typedef unsigned short u16; @@ -138,28 +140,6 @@ static unsigned short LDT3(int idx) return (idx << 3) | 7; } -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static void add_ldt(const struct user_desc *desc, unsigned short *var, const char *name) { diff --git a/tools/testing/selftests/x86/single_step_syscall.c b/tools/testing/selftests/x86/single_step_syscall.c index 9a30f443e928..280d7a22b9c9 100644 --- a/tools/testing/selftests/x86/single_step_syscall.c +++ b/tools/testing/selftests/x86/single_step_syscall.c @@ -33,28 +33,6 @@ #include "helpers.h" -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static volatile sig_atomic_t sig_traps, sig_eflags; sigjmp_buf jmpbuf; diff --git a/tools/testing/selftests/x86/syscall_arg_fault.c b/tools/testing/selftests/x86/syscall_arg_fault.c index 48ab065a76f9..f67a2df335ba 100644 --- a/tools/testing/selftests/x86/syscall_arg_fault.c +++ b/tools/testing/selftests/x86/syscall_arg_fault.c @@ -17,18 +17,6 @@ #include "helpers.h" -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static sigjmp_buf jmpbuf; static volatile sig_atomic_t n_errs; diff --git a/tools/testing/selftests/x86/syscall_nt.c b/tools/testing/selftests/x86/syscall_nt.c index a108b80dd082..f9c9814160f0 100644 --- a/tools/testing/selftests/x86/syscall_nt.c +++ b/tools/testing/selftests/x86/syscall_nt.c @@ -18,18 +18,6 @@ static unsigned int nerrs; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static void sigtrap(int sig, siginfo_t *si, void *ctx_void) { } diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c index b30de9aaa6d4..5fb531e3ad7c 100644 --- a/tools/testing/selftests/x86/sysret_rip.c +++ b/tools/testing/selftests/x86/sysret_rip.c @@ -22,6 +22,8 @@ #include #include +#include "helpers.h" + /* * These items are in clang_helpers_64.S, in order to avoid clang inline asm * limitations: @@ -31,28 +33,6 @@ extern const char test_page[]; static void const *current_test_page_addr = test_page; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - -static void clearhandler(int sig) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - /* State used by our signal handlers. */ static gregset_t initial_regs; diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c index 6de11b4df458..05e1e6774fba 100644 --- a/tools/testing/selftests/x86/test_vsyscall.c +++ b/tools/testing/selftests/x86/test_vsyscall.c @@ -310,19 +310,6 @@ static void test_getcpu(int cpu) static jmp_buf jmpbuf; static volatile unsigned long segv_err; -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - ksft_exit_fail_msg("sigaction failed\n"); -} - static void sigsegv(int sig, siginfo_t *info, void *ctx_void) { ucontext_t *ctx = (ucontext_t *)ctx_void; diff --git a/tools/testing/selftests/x86/unwind_vdso.c b/tools/testing/selftests/x86/unwind_vdso.c index 4c311e1af4c7..9cc17588d818 100644 --- a/tools/testing/selftests/x86/unwind_vdso.c +++ b/tools/testing/selftests/x86/unwind_vdso.c @@ -43,18 +43,6 @@ int main() #include #include -static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), - int flags) -{ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = handler; - sa.sa_flags = SA_SIGINFO | flags; - sigemptyset(&sa.sa_mask); - if (sigaction(sig, &sa, 0)) - err(1, "sigaction"); -} - static volatile sig_atomic_t nerrs; static unsigned long sysinfo; static bool got_sysinfo = false; From patchwork Wed Feb 26 01:07:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991200 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B586C154423; Wed, 26 Feb 2025 01:07:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532058; cv=none; b=euVZSfApTsJYJzefqMdSULZZn/xfUeD6yxuchsQWwbkFBxt3mYuR3jvm+Mao7dQn7/3X3n4AQuP/Ezd/pppb89vePG6QwRKVOH31FjODjF4WK97uJLGZYD3fPqGQQK8+pilgWTkR6LBRHHTuCoYMh8QyoO2rRShgYcSmyF9vrhY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532058; c=relaxed/simple; bh=c+B52D3/B02Xjnnbp8WNTgpN5fkvkKRB3fPrOFmGOJs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tsRDhM+YSaihIhXDfjovqgotpEtLUxIiJQXJ7zpJ1AGBgG4fm+2vbsr+/unlQK35eRaob83oGNx9XvE5PPQi7PAQWX91Kkb3loy8+DB7OyD4Q04rCmIWskZJMQFQYlX32qnMIrC2jVWJQcbEjnvINYhsj5aTh2KEIdvVDfhRhVc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=CztiJz6+; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="CztiJz6+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532057; x=1772068057; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=c+B52D3/B02Xjnnbp8WNTgpN5fkvkKRB3fPrOFmGOJs=; b=CztiJz6+VbN1nOpJn7GaELlFGE5Lk5zg/dYC0lQH9/VLmSRK9gmpY5GH Uc89Yf2OzKhxBWbDsFNI875Dv5oig6EAiS5bFZlqLqciG8b9KWaQ2If+X vBsoLMnKk+Xg2W5gymDBOIGgIqm5PU88rGv40IRFmIWtrZgLTa/2Z2rke JB3D2CNfwLI71z8IfztWnDtFcrq30YPDY/GaGkVeIBY+ldNbc6FB0KeN1 RREu+chDdX19vBZIEIGYOx0H9uNzBWJevzFYV/5xqNWh3lBb9gBVwp1yL 9JbFDZqRqBN/0ediLv0eVXmh5VeHk00CJU1ZSYqBu7rQwOJIfyfAvjS9Z Q==; X-CSE-ConnectionGUID: 3DiUE2tlQ9uMzO35MeS3ng== X-CSE-MsgGUID: GaMf3uT7Q3uvrlvS1x6KMw== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362184" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362184" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:35 -0800 X-CSE-ConnectionGUID: TwpKYaDWQ8a7fTfdDvAhaw== X-CSE-MsgGUID: yct9wnqPSdG/mcG+7xKHnw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467340" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:35 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 2/9] selftests/x86/xstate: Refactor XSAVE helpers for general use Date: Tue, 25 Feb 2025 17:07:22 -0800 Message-ID: <20250226010731.2456-3-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The AMX test introduced several XSAVE-related helper functions, but so far, it has been the only user of them. These helpers can be generalized for broader test of multiple xstate features. Move most XSAVE-related code into xsave.h, making it shareable. The restructuring includes: * Establishing low-level XSAVE helpers for saving and restoring register states, as well as handling XSAVE buffers. * Generalizing state data manipuldations: set_rand_data() * Introducing a generic feature query helper: get_xstate_info() While doing so, remove unused defines in amx.c. Signed-off-by: Chang S. Bae --- tools/testing/selftests/x86/amx.c | 142 ++------------------------- tools/testing/selftests/x86/xstate.h | 132 +++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 132 deletions(-) create mode 100644 tools/testing/selftests/x86/xstate.h diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index 0f355f331f41..366cfec221e4 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -19,46 +19,13 @@ #include #include -#include "../kselftest.h" /* For __cpuid_count() */ #include "helpers.h" +#include "xstate.h" #ifndef __x86_64__ # error This test is 64-bit only #endif -#define XSAVE_HDR_OFFSET 512 -#define XSAVE_HDR_SIZE 64 - -struct xsave_buffer { - union { - struct { - char legacy[XSAVE_HDR_OFFSET]; - char header[XSAVE_HDR_SIZE]; - char extended[0]; - }; - char bytes[0]; - }; -}; - -static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm) -{ - uint32_t rfbm_lo = rfbm; - uint32_t rfbm_hi = rfbm >> 32; - - asm volatile("xsave (%%rdi)" - : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi) - : "memory"); -} - -static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) -{ - uint32_t rfbm_lo = rfbm; - uint32_t rfbm_hi = rfbm >> 32; - - asm volatile("xrstor (%%rdi)" - : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)); -} - /* err() exits and will not return */ #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__) @@ -68,92 +35,12 @@ static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) -#define CPUID_LEAF1_ECX_XSAVE_MASK (1 << 26) -#define CPUID_LEAF1_ECX_OSXSAVE_MASK (1 << 27) - static uint32_t xbuf_size; -static struct { - uint32_t xbuf_offset; - uint32_t size; -} xtiledata; - -#define CPUID_LEAF_XSTATE 0xd -#define CPUID_SUBLEAF_XSTATE_USER 0x0 -#define TILE_CPUID 0x1d -#define TILE_PALETTE_ID 0x1 - -static void check_cpuid_xtiledata(void) -{ - uint32_t eax, ebx, ecx, edx; - - __cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER, - eax, ebx, ecx, edx); - - /* - * EBX enumerates the size (in bytes) required by the XSAVE - * instruction for an XSAVE area containing all the user state - * components corresponding to bits currently set in XCR0. - * - * Stash that off so it can be used to allocate buffers later. - */ - xbuf_size = ebx; - - __cpuid_count(CPUID_LEAF_XSTATE, XFEATURE_XTILEDATA, - eax, ebx, ecx, edx); - /* - * eax: XTILEDATA state component size - * ebx: XTILEDATA state component offset in user buffer - */ - if (!eax || !ebx) - fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d", - eax, ebx); - - xtiledata.size = eax; - xtiledata.xbuf_offset = ebx; -} +struct xstate_info xtiledata; /* The helpers for managing XSAVE buffer and tile states: */ -struct xsave_buffer *alloc_xbuf(void) -{ - struct xsave_buffer *xbuf; - - /* XSAVE buffer should be 64B-aligned. */ - xbuf = aligned_alloc(64, xbuf_size); - if (!xbuf) - fatal_error("aligned_alloc()"); - return xbuf; -} - -static inline void clear_xstate_header(struct xsave_buffer *buffer) -{ - memset(&buffer->header, 0, sizeof(buffer->header)); -} - -static inline void set_xstatebv(struct xsave_buffer *buffer, uint64_t bv) -{ - /* XSTATE_BV is at the beginning of the header: */ - *(uint64_t *)(&buffer->header) = bv; -} - -static void set_rand_tiledata(struct xsave_buffer *xbuf) -{ - int *ptr = (int *)&xbuf->bytes[xtiledata.xbuf_offset]; - int data; - int i; - - /* - * Ensure that 'data' is never 0. This ensures that - * the registers are never in their initial configuration - * and thus never tracked as being in the init state. - */ - data = rand() | 1; - - for (i = 0; i < xtiledata.size / sizeof(int); i++, ptr++) - *ptr = data; -} - struct xsave_buffer *stashed_xsave; static void init_stashed_xsave(void) @@ -169,21 +56,6 @@ static void free_stashed_xsave(void) free(stashed_xsave); } -/* See 'struct _fpx_sw_bytes' at sigcontext.h */ -#define SW_BYTES_OFFSET 464 -/* N.B. The struct's field name varies so read from the offset. */ -#define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8) - -static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *buffer) -{ - return (struct _fpx_sw_bytes *)(buffer + SW_BYTES_OFFSET); -} - -static inline uint64_t get_fpx_sw_bytes_features(void *buffer) -{ - return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); -} - /* Work around printf() being unsafe in signals: */ #define SIGNAL_BUF_LEN 1000 char signal_message_buffer[SIGNAL_BUF_LEN]; @@ -281,7 +153,7 @@ static inline bool load_rand_tiledata(struct xsave_buffer *xbuf) { clear_xstate_header(xbuf); set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA); - set_rand_tiledata(xbuf); + set_rand_data(&xtiledata, xbuf); return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA); } @@ -884,7 +756,13 @@ int main(void) return KSFT_SKIP; } - check_cpuid_xtiledata(); + xbuf_size = get_xbuf_size(); + + xtiledata = get_xstate_info(XFEATURE_XTILEDATA); + if (!xtiledata.size || !xtiledata.xbuf_offset) { + fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d", + xtiledata.size, xtiledata.xbuf_offset); + } init_stashed_xsave(); sethandler(SIGILL, handle_noperm, 0); diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h new file mode 100644 index 000000000000..6729ffde6cc4 --- /dev/null +++ b/tools/testing/selftests/x86/xstate.h @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +#ifndef __SELFTESTS_X86_XSTATE_H +#define __SELFTESTS_X86_XSTATE_H + +#include + +#include "../kselftest.h" + +#define XSAVE_HDR_OFFSET 512 +#define XSAVE_HDR_SIZE 64 + +struct xsave_buffer { + union { + struct { + char legacy[XSAVE_HDR_OFFSET]; + char header[XSAVE_HDR_SIZE]; + char extended[0]; + }; + char bytes[0]; + }; +}; + +static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm) +{ + uint32_t rfbm_hi = rfbm >> 32; + uint32_t rfbm_lo = rfbm; + + asm volatile("xsave (%%rdi)" + : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi) + : "memory"); +} + +static inline void xrstor(struct xsave_buffer *xbuf, uint64_t rfbm) +{ + uint32_t rfbm_hi = rfbm >> 32; + uint32_t rfbm_lo = rfbm; + + asm volatile("xrstor (%%rdi)" + : : "D" (xbuf), "a" (rfbm_lo), "d" (rfbm_hi)); +} + +#define CPUID_LEAF_XSTATE 0xd +#define CPUID_SUBLEAF_XSTATE_USER 0x0 + +static inline uint32_t get_xbuf_size(void) +{ + uint32_t eax, ebx, ecx, edx; + + __cpuid_count(CPUID_LEAF_XSTATE, CPUID_SUBLEAF_XSTATE_USER, + eax, ebx, ecx, edx); + + /* + * EBX enumerates the size (in bytes) required by the XSAVE + * instruction for an XSAVE area containing all the user state + * components corresponding to bits currently set in XCR0. + */ + return ebx; +} + +struct xstate_info { + uint32_t num; + uint32_t mask; + uint32_t xbuf_offset; + uint32_t size; +}; + +static inline struct xstate_info get_xstate_info(uint32_t xfeature_num) +{ + struct xstate_info xstate = { }; + uint32_t eax, ebx, ecx, edx; + + xstate.num = xfeature_num; + xstate.mask = 1 << xfeature_num; + + __cpuid_count(CPUID_LEAF_XSTATE, xfeature_num, + eax, ebx, ecx, edx); + xstate.size = eax; + xstate.xbuf_offset = ebx; + return xstate; +} + +static inline struct xsave_buffer *alloc_xbuf(void) +{ + uint32_t xbuf_size = get_xbuf_size(); + + /* XSAVE buffer should be 64B-aligned. */ + return aligned_alloc(64, xbuf_size); +} + +static inline void clear_xstate_header(struct xsave_buffer *xbuf) +{ + memset(&xbuf->header, 0, sizeof(xbuf->header)); +} + +static inline void set_xstatebv(struct xsave_buffer *xbuf, uint64_t bv) +{ + /* XSTATE_BV is at the beginning of the header: */ + *(uint64_t *)(&xbuf->header) = bv; +} + +/* See 'struct _fpx_sw_bytes' at sigcontext.h */ +#define SW_BYTES_OFFSET 464 +/* N.B. The struct's field name varies so read from the offset. */ +#define SW_BYTES_BV_OFFSET (SW_BYTES_OFFSET + 8) + +static inline struct _fpx_sw_bytes *get_fpx_sw_bytes(void *xbuf) +{ + return xbuf + SW_BYTES_OFFSET; +} + +static inline uint64_t get_fpx_sw_bytes_features(void *buffer) +{ + return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); +} + +static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer *xbuf) +{ + int *ptr = (int *)&xbuf->bytes[xstate->xbuf_offset]; + int data, i; + + /* + * Ensure that 'data' is never 0. This ensures that + * the registers are never in their initial configuration + * and thus never tracked as being in the init state. + */ + data = rand() | 1; + + for (i = 0; i < xstate->size / sizeof(int); i++, ptr++) + *ptr = data; +} + +#endif /* __SELFTESTS_X86_XSTATE_H */ From patchwork Wed Feb 26 01:07:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991201 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D638155A52; Wed, 26 Feb 2025 01:07:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532059; cv=none; b=k/EnEpiDibo1DguGx4v0D+mGGdHrqulpv+sGj4FKpB2jWcXUqcdq02A80AWlsUxOUlUKP+11F+NVJPGybct0aSBIgF7icRbmWpIPYw6lfBjEMjT7SQmwi4T+G2iDTcYPR9u8lmQoWGSiCQHoSg95SS1erJwnQSqhO55rEgi2Pv0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532059; c=relaxed/simple; bh=S+6m2ahVPH+LSNhzYKSi30AW7vgAqg0xXfDPaKKHiaA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=evpMjFvIR8YDu6MAo0uDn/HxHYY9e87DNueWm3mG6amIJ20V/RDcAyIeQV0rOw4o9UmJaB64y+TWP9uvusKKdRfjZsj5dVQGMOWswsx99ZAypKFHzchc3OCW5s35540RGWtyfjdrlqaYaUarq73ix2PUU1nCVQRQqF/2+Bb+Ktk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=h4RinY7j; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="h4RinY7j" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532058; x=1772068058; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=S+6m2ahVPH+LSNhzYKSi30AW7vgAqg0xXfDPaKKHiaA=; b=h4RinY7j021aoVBiVWNop3wVOC2POaPDx2jhP1IkhItsbSSI5Y0C12bh TqnRv5uBUDG+uJv5oxKXmHsajqarFQfbEZ3eu3JxfEeoAMxZn6/qoxX9Q mqEeAe1svjRiao/4Hv4iHP0uoZT87bddFjV+G/xqdM9IjLEj0rh8OftOe 2b0A7tsmSdY38wK4GPoNlhmaBaesLXo8E6UlMObxYQAbfsyqM2VcPQ/WR 38o8Cu6yZnq8J830Z7/uKDICpHwPtXe3i84IOfQKnaeJ3Iu7/5BQI+BQp o4Xps5T6IFhlIbrKVAUIuHrN/Yiz3ddnTzX9FAaVIdtZ9r+h7dMeeP3zf A==; X-CSE-ConnectionGUID: +r7naifvTLqcbLsEqJd03g== X-CSE-MsgGUID: c4qUxtfIT56ZVtqhCbBeOA== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362191" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362191" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:36 -0800 X-CSE-ConnectionGUID: 5xFzlMoER5Gzhv9UiAsAxA== X-CSE-MsgGUID: XwSt+c1ETn2Da42kjVCcEw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467345" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:36 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 3/9] selftests/x86/xstate: Enumerate and name xstate components Date: Tue, 25 Feb 2025 17:07:23 -0800 Message-ID: <20250226010731.2456-4-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 After moving essential helpers from amx.c, the code remains neutral regarding which xstate components it handles. However, explicitly listing known components helps users identify which features are ready for testing. Enumerate xstate components to facilitate identification. Extend struct xstate_info to include a name field, providing a human-readable identifier. Signed-off-by: Chang S. Bae --- tools/testing/selftests/x86/amx.c | 2 - tools/testing/selftests/x86/xstate.h | 60 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index 366cfec221e4..cde22f303905 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -29,8 +29,6 @@ /* err() exits and will not return */ #define fatal_error(msg, ...) err(1, "[FAIL]\t" msg, ##__VA_ARGS__) -#define XFEATURE_XTILECFG 17 -#define XFEATURE_XTILEDATA 18 #define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index 6729ffde6cc4..d3461c438461 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -9,6 +9,59 @@ #define XSAVE_HDR_OFFSET 512 #define XSAVE_HDR_SIZE 64 +/* + * List of XSAVE features Linux knows about. Copied from + * arch/x86/include/asm/fpu/types.h + */ +enum xfeature { + XFEATURE_FP, + XFEATURE_SSE, + XFEATURE_YMM, + XFEATURE_BNDREGS, + XFEATURE_BNDCSR, + XFEATURE_OPMASK, + XFEATURE_ZMM_Hi256, + XFEATURE_Hi16_ZMM, + XFEATURE_PT_UNIMPLEMENTED_SO_FAR, + XFEATURE_PKRU, + XFEATURE_PASID, + XFEATURE_CET_USER, + XFEATURE_CET_KERNEL_UNUSED, + XFEATURE_RSRVD_COMP_13, + XFEATURE_RSRVD_COMP_14, + XFEATURE_LBR, + XFEATURE_RSRVD_COMP_16, + XFEATURE_XTILECFG, + XFEATURE_XTILEDATA, + + XFEATURE_MAX, +}; + +/* Copied from arch/x86/kernel/fpu/xstate.c */ +static const char *xfeature_names[] = +{ + "x87 floating point registers", + "SSE registers", + "AVX registers", + "MPX bounds registers", + "MPX CSR", + "AVX-512 opmask", + "AVX-512 Hi256", + "AVX-512 ZMM_Hi256", + "Processor Trace (unused)", + "Protection Keys User registers", + "PASID state", + "Control-flow User registers", + "Control-flow Kernel registers (unused)", + "unknown xstate feature", + "unknown xstate feature", + "unknown xstate feature", + "unknown xstate feature", + "AMX Tile config", + "AMX Tile data", + "unknown xstate feature", +}; + struct xsave_buffer { union { struct { @@ -58,6 +111,7 @@ static inline uint32_t get_xbuf_size(void) } struct xstate_info { + const char *name; uint32_t num; uint32_t mask; uint32_t xbuf_offset; @@ -69,6 +123,12 @@ static inline struct xstate_info get_xstate_info(uint32_t xfeature_num) struct xstate_info xstate = { }; uint32_t eax, ebx, ecx, edx; + if (xfeature_num >= XFEATURE_MAX) { + ksft_print_msg("unknown state\n"); + return xstate; + } + + xstate.name = xfeature_names[xfeature_num]; xstate.num = xfeature_num; xstate.mask = 1 << xfeature_num; From patchwork Wed Feb 26 01:07:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991202 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4265415E5AE; Wed, 26 Feb 2025 01:07:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532060; cv=none; b=b3STnBtwWcchc8lpFsJ6T8q01YFpd0OXcOoKpx+qChZIxwcMBUs+SXkVqpgXHbmA82VbkastWrUpFOUwTU0O4riWdBqUVyCbVmpcBBfhmQanMlkWu2iD5oMoZMsmrVbw4FC2wBU6mGQUIhodxNWLRtMPDDt/UvMJ5Khphq3JJ3A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532060; c=relaxed/simple; bh=uAQBR6FPJgFLhph7bR7eMw2n3f7jdelY8wUjhm17dVA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=slkTjuUHqq54q+qd21/OqTgTW7Et+jw4It1zRqT1n0grrfY8OVvOGG5jGMJFghjeMfUWNeeQkUuwS2e4IsmUCbYO8f/U7ntCiCh+zDY07jkmS8WyGSWHsY+SknvvztvQCGYdkv2L1bEqe90ruGurm2Mj/Nol9RWidCfhMF7MZu8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Eq8SIuBh; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Eq8SIuBh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532058; x=1772068058; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=uAQBR6FPJgFLhph7bR7eMw2n3f7jdelY8wUjhm17dVA=; b=Eq8SIuBhAkMDE38s/PcK0ZkUoP4n3E2D0wjoqS12wCvCWzBUdZ9qkmSy TJMUOadOV1NoQI65fNsHfCNE19cMGKRI7NKeQVt9kIMS61Bcppc4TcBi2 USzzwptyASHa4sIDSdxo0O8h/wSDXQR908q6j90oGxghyEo/fMVyRDo0X e6bsID6J0mSvX7L14+XjesojO9vPbsSP8Yq989AiwHldNKaMltMiV1O2U O+kJUHhwMNYZkFx+VJiJPVvb/tPdywr/NkqnTSGRou0W8iKA/sWYJJroR wzSgwmQwRP2VniFbOXiNYnBP/u0HHeH6fkg7mhlmuK0lTkacilHxyWVkw Q==; X-CSE-ConnectionGUID: pHVVVUe3RZSkT/WW6GQNoQ== X-CSE-MsgGUID: Kr35KA6ZSyiF/reoqSzIBg== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362197" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362197" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:37 -0800 X-CSE-ConnectionGUID: vM/PrbbyR1+wC12nPd5VIA== X-CSE-MsgGUID: JonilOeUQpOYXx9H2eT4qw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467348" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:37 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 4/9] selftests/x86/xstate: Refactor context switching test Date: Tue, 25 Feb 2025 17:07:24 -0800 Message-ID: <20250226010731.2456-5-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The existing context switching and ptrace tests in amx.c are not specific to dynamic states, making them reusable for general xstate testing. As a first step, move the context switching test to xstate.c. Refactor the test code to allow specifying which xstate component being tested. To decouple the test from dynamic states, remove the permission request code. In fact, The permission request inside the test wrapper was redundant. Additionally, replace fatal_error() with ksft_exit_fail_msg() for consistency in error handling. Signed-off-by: Chang S. Bae --- Expected output: $ amx_64 ... [RUN] AMX Tile data: check context switches, 10 iterations, 5 threads. [OK] No incorrect case was found. --- tools/testing/selftests/x86/Makefile | 2 + tools/testing/selftests/x86/amx.c | 166 +--------------------- tools/testing/selftests/x86/xstate.c | 198 +++++++++++++++++++++++++++ tools/testing/selftests/x86/xstate.h | 2 + 4 files changed, 204 insertions(+), 164 deletions(-) create mode 100644 tools/testing/selftests/x86/xstate.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index d51249f14e2f..f15efdc6aef7 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -132,3 +132,5 @@ $(OUTPUT)/check_initial_reg_state_64: CFLAGS += -Wl,-ereal_start -static $(OUTPUT)/nx_stack_32: CFLAGS += -Wl,-z,noexecstack $(OUTPUT)/nx_stack_64: CFLAGS += -Wl,-z,noexecstack + +$(OUTPUT)/amx_64: EXTRA_FILES += xstate.c diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index cde22f303905..b3c51dd25abc 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -3,7 +3,6 @@ #define _GNU_SOURCE #include #include -#include #include #include #include @@ -434,14 +433,6 @@ static inline bool __validate_tiledata_regs(struct xsave_buffer *xbuf1) return true; } -static inline void validate_tiledata_regs_same(struct xsave_buffer *xbuf) -{ - int ret = __validate_tiledata_regs(xbuf); - - if (ret != 0) - fatal_error("TILEDATA registers changed"); -} - static inline void validate_tiledata_regs_changed(struct xsave_buffer *xbuf) { int ret = __validate_tiledata_regs(xbuf); @@ -498,158 +489,6 @@ static void test_fork(void) _exit(0); } -/* Context switching test */ - -static struct _ctxtswtest_cfg { - unsigned int iterations; - unsigned int num_threads; -} ctxtswtest_config; - -struct futex_info { - pthread_t thread; - int nr; - pthread_mutex_t mutex; - struct futex_info *next; -}; - -static void *check_tiledata(void *info) -{ - struct futex_info *finfo = (struct futex_info *)info; - struct xsave_buffer *xbuf; - int i; - - xbuf = alloc_xbuf(); - if (!xbuf) - fatal_error("unable to allocate XSAVE buffer"); - - /* - * Load random data into 'xbuf' and then restore - * it to the tile registers themselves. - */ - load_rand_tiledata(xbuf); - for (i = 0; i < ctxtswtest_config.iterations; i++) { - pthread_mutex_lock(&finfo->mutex); - - /* - * Ensure the register values have not - * diverged from those recorded in 'xbuf'. - */ - validate_tiledata_regs_same(xbuf); - - /* Load new, random values into xbuf and registers */ - load_rand_tiledata(xbuf); - - /* - * The last thread's last unlock will be for - * thread 0's mutex. However, thread 0 will - * have already exited the loop and the mutex - * will already be unlocked. - * - * Because this is not an ERRORCHECK mutex, - * that inconsistency will be silently ignored. - */ - pthread_mutex_unlock(&finfo->next->mutex); - } - - free(xbuf); - /* - * Return this thread's finfo, which is - * a unique value for this thread. - */ - return finfo; -} - -static int create_threads(int num, struct futex_info *finfo) -{ - int i; - - for (i = 0; i < num; i++) { - int next_nr; - - finfo[i].nr = i; - /* - * Thread 'i' will wait on this mutex to - * be unlocked. Lock it immediately after - * initialization: - */ - pthread_mutex_init(&finfo[i].mutex, NULL); - pthread_mutex_lock(&finfo[i].mutex); - - next_nr = (i + 1) % num; - finfo[i].next = &finfo[next_nr]; - - if (pthread_create(&finfo[i].thread, NULL, check_tiledata, &finfo[i])) - fatal_error("pthread_create()"); - } - return 0; -} - -static void affinitize_cpu0(void) -{ - cpu_set_t cpuset; - - CPU_ZERO(&cpuset); - CPU_SET(0, &cpuset); - - if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) - fatal_error("sched_setaffinity to CPU 0"); -} - -static void test_context_switch(void) -{ - struct futex_info *finfo; - int i; - - /* Affinitize to one CPU to force context switches */ - affinitize_cpu0(); - - req_xtiledata_perm(); - - printf("[RUN]\tCheck tiledata context switches, %d iterations, %d threads.\n", - ctxtswtest_config.iterations, - ctxtswtest_config.num_threads); - - - finfo = malloc(sizeof(*finfo) * ctxtswtest_config.num_threads); - if (!finfo) - fatal_error("malloc()"); - - create_threads(ctxtswtest_config.num_threads, finfo); - - /* - * This thread wakes up thread 0 - * Thread 0 will wake up 1 - * Thread 1 will wake up 2 - * ... - * the last thread will wake up 0 - * - * ... this will repeat for the configured - * number of iterations. - */ - pthread_mutex_unlock(&finfo[0].mutex); - - /* Wait for all the threads to finish: */ - for (i = 0; i < ctxtswtest_config.num_threads; i++) { - void *thread_retval; - int rc; - - rc = pthread_join(finfo[i].thread, &thread_retval); - - if (rc) - fatal_error("pthread_join() failed for thread %d err: %d\n", - i, rc); - - if (thread_retval != &finfo[i]) - fatal_error("unexpected thread retval for thread %d: %p\n", - i, thread_retval); - - } - - printf("[OK]\tNo incorrect case was found.\n"); - - free(finfo); -} - /* Ptrace test */ /* @@ -745,6 +584,7 @@ static void test_ptrace(void) int main(void) { + const unsigned int ctxtsw_num_threads = 5, ctxtsw_iterations = 10; unsigned long features; long rc; @@ -772,9 +612,7 @@ int main(void) test_fork(); - ctxtswtest_config.iterations = 10; - ctxtswtest_config.num_threads = 5; - test_context_switch(); + test_context_switch(XFEATURE_XTILEDATA, ctxtsw_num_threads, ctxtsw_iterations); test_ptrace(); diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests/x86/xstate.c new file mode 100644 index 000000000000..e5b51e7d13e1 --- /dev/null +++ b/tools/testing/selftests/x86/xstate.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include +#include + +#include "helpers.h" +#include "xstate.h" + +static struct xstate_info xstate; + +struct futex_info { + unsigned int iterations; + struct futex_info *next; + pthread_mutex_t mutex; + pthread_t thread; + bool valid; + int nr; +}; + +static inline void load_rand_xstate(struct xstate_info *xstate, struct xsave_buffer *xbuf) +{ + clear_xstate_header(xbuf); + set_xstatebv(xbuf, xstate->mask); + set_rand_data(xstate, xbuf); + xrstor(xbuf, xstate->mask); +} + +static inline bool validate_xstate_same(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2) +{ + int ret; + + ret = memcmp(&xbuf1->bytes[xstate.xbuf_offset], + &xbuf2->bytes[xstate.xbuf_offset], + xstate.size); + return ret == 0; +} + +static inline bool validate_xregs_same(struct xsave_buffer *xbuf1) +{ + struct xsave_buffer *xbuf2; + bool ret; + + xbuf2 = alloc_xbuf(); + if (!xbuf2) + ksft_exit_fail_msg("failed to allocate XSAVE buffer\n"); + + xsave(xbuf2, xstate.mask); + ret = validate_xstate_same(xbuf1, xbuf2); + + free(xbuf2); + return ret; +} + +/* Context switching test */ + +static void *check_xstate(void *info) +{ + struct futex_info *finfo = (struct futex_info *)info; + struct xsave_buffer *xbuf; + int i; + + xbuf = alloc_xbuf(); + if (!xbuf) + ksft_exit_fail_msg("unable to allocate XSAVE buffer\n"); + + /* + * Load random data into 'xbuf' and then restore it to the xstate + * registers. + */ + load_rand_xstate(&xstate, xbuf); + finfo->valid = true; + + for (i = 0; i < finfo->iterations; i++) { + pthread_mutex_lock(&finfo->mutex); + + /* + * Ensure the register values have not diverged from the + * record. Then reload a new random value. If it failed + * ever before, skip it. + */ + if (finfo->valid) { + finfo->valid = validate_xregs_same(xbuf); + load_rand_xstate(&xstate, xbuf); + } + + /* + * The last thread's last unlock will be for thread 0's + * mutex. However, thread 0 will have already exited the + * loop and the mutex will already be unlocked. + * + * Because this is not an ERRORCHECK mutex, that + * inconsistency will be silently ignored. + */ + pthread_mutex_unlock(&finfo->next->mutex); + } + + free(xbuf); + return finfo; +} + +static void create_threads(uint32_t num_threads, uint32_t iterations, struct futex_info *finfo) +{ + int i; + + for (i = 0; i < num_threads; i++) { + int next_nr; + + finfo[i].nr = i; + finfo[i].iterations = iterations; + + /* + * Thread 'i' will wait on this mutex to be unlocked. + * Lock it immediately after initialization: + */ + pthread_mutex_init(&finfo[i].mutex, NULL); + pthread_mutex_lock(&finfo[i].mutex); + + next_nr = (i + 1) % num_threads; + finfo[i].next = &finfo[next_nr]; + + if (pthread_create(&finfo[i].thread, NULL, check_xstate, &finfo[i])) + ksft_exit_fail_msg("pthread_create() failed\n"); + } +} + +static bool checkout_threads(uint32_t num_threads, struct futex_info *finfo) +{ + void *thread_retval; + bool valid = true; + int err, i; + + for (i = 0; i < num_threads; i++) { + err = pthread_join(finfo[i].thread, &thread_retval); + if (err) + ksft_exit_fail_msg("pthread_join() failed for thread %d err: %d\n", i, err); + + if (thread_retval != &finfo[i]) { + ksft_exit_fail_msg("unexpected thread retval for thread %d: %p\n", + i, thread_retval); + } + + valid &= finfo[i].valid; + } + + return valid; +} + +static void affinitize_cpu0(void) +{ + cpu_set_t cpuset; + + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + + if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) + ksft_exit_fail_msg("sched_setaffinity to CPU 0 failed\n"); +} + +void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations) +{ + struct futex_info *finfo; + + /* Affinitize to one CPU to force context switches */ + affinitize_cpu0(); + + xstate = get_xstate_info(feature_num); + + printf("[RUN]\t%s: check context switches, %d iterations, %d threads.\n", + xstate.name, iterations, num_threads); + + finfo = malloc(sizeof(*finfo) * num_threads); + if (!finfo) + ksft_exit_fail_msg("unable allocate memory\n"); + + create_threads(num_threads, iterations, finfo); + + /* + * This thread wakes up thread 0 + * Thread 0 will wake up 1 + * Thread 1 will wake up 2 + * ... + * The last thread will wake up 0 + * + * This will repeat for the configured + * number of iterations. + */ + pthread_mutex_unlock(&finfo[0].mutex); + + /* Wait for all the threads to finish: */ + if (checkout_threads(num_threads, finfo)) + printf("[OK]\tNo incorrect case was found.\n"); + else + printf("[FAIL]\tFailed with context switching test.\n"); + + free(finfo); +} diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index d3461c438461..5ef66f247eb9 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -189,4 +189,6 @@ static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer *ptr = data; } +void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations); + #endif /* __SELFTESTS_X86_XSTATE_H */ From patchwork Wed Feb 26 01:07:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991203 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C0612178372; Wed, 26 Feb 2025 01:07:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532060; cv=none; b=HVHXfS/omylmWSsuU9JyoWv8g15hEEswVZKni5rkZeu396h5xF7JHKBsjCfKy2bOD1pU/eixxzUv/jlDTJJkKdUk+4mMFbkcBIKs3CKMGJ6qqhTdGwq17ir80ifGrpD7UlNmAk5sELOlGpCBml/kq4w1NBtCk0uZOdAvX0Apg78= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532060; c=relaxed/simple; bh=b+YHZn2oe7fZ7lyCIm3gb0IseuEDVm4QkMMYsFhiiT8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sl0Ui2ppO0dkZZ47xciOExTGq2Ah0nKi0zZQC4/z9bykQSzKgFkxa7fKeLN0TdpV1G217gL4bAk38At7Y5IqjRWFWlmI9XQvqkXxbFhwbZ27cZRnMkBGNC2Ht1Begm0y6n5YpDFOPJe7M/nihOazhKPnVDpVttOhIf002UqTjUc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=FAIeS7Nm; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="FAIeS7Nm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532059; x=1772068059; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=b+YHZn2oe7fZ7lyCIm3gb0IseuEDVm4QkMMYsFhiiT8=; b=FAIeS7Nmu00CgX/H2ETGVZn3E414OxWBlspA4EXa/eb8zlfFZZ3CMW4H dSmJFy4xgkuSE7WFH2OBeo4w8uiUvIqgQb+BjiWBO7crduzT5go4SOhF2 vjeVZKe8asecAcI7c+A1N0aH93piDpuSeOJC563iQEjZRC4hUu2vt4Fcy bBdB3OnF3d58bUcO9+/EyWHs8iYca9iUNvzLJEKtLck4OUWHDyXgRzCAf qwRy2cVdKH/fPTLbqcjCdDedvVM4UCd68mB9E8SPGRII4b37HZa3OrVi+ XcHYJEWvdjedlDxsvd91/w0H3sWjK23ynBCUn8Uo/YUMOc4K0ZnlLF10d w==; X-CSE-ConnectionGUID: 9IcWbaYDTPWEvlrCW3NQUg== X-CSE-MsgGUID: jV8WEgZJTMe410czHx8pxg== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362208" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362208" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:38 -0800 X-CSE-ConnectionGUID: r1xqzPQjQDKN/mH9hUC9sw== X-CSE-MsgGUID: eXxteRbpRmWJOiUTaTDVfg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467352" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:38 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 5/9] selftests/x86/xstate: Refactor ptrace ABI test Date: Tue, 25 Feb 2025 17:07:25 -0800 Message-ID: <20250226010731.2456-6-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Following the refactor of the context switching test, the ptrace test is another component reusable for other xstate features. As part of this restructuring, add a missing check to validate the user_xstateregs->xstate_fx_sw field in the ABI. Also, replace err() and fatal_error() with ksft_exit_fail_msg() for consistency in error handling. Signed-off-by: Chang S. Bae --- Expected out: $ amx_64 ... [RUN] AMX Tile data: inject xstate via ptrace(). [OK] 'xfeatures' in SW reserved area was correctly written [OK] xstate was correctly updated. --- tools/testing/selftests/x86/amx.c | 108 +--------------------- tools/testing/selftests/x86/xstate.c | 129 +++++++++++++++++++++++++++ tools/testing/selftests/x86/xstate.h | 1 + 3 files changed, 131 insertions(+), 107 deletions(-) diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index b3c51dd25abc..4bafbb72aa1b 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -13,10 +13,8 @@ #include #include #include -#include #include #include -#include #include "helpers.h" #include "xstate.h" @@ -32,8 +30,6 @@ #define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) #define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) -static uint32_t xbuf_size; - struct xstate_info xtiledata; /* The helpers for managing XSAVE buffer and tile states: */ @@ -154,13 +150,6 @@ static inline bool load_rand_tiledata(struct xsave_buffer *xbuf) return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA); } -/* Return XTILEDATA to its initial configuration. */ -static inline void init_xtiledata(void) -{ - clear_xstate_header(stashed_xsave); - xrstor_safe(stashed_xsave, XFEATURE_MASK_XTILEDATA); -} - enum expected_result { FAIL_EXPECTED, SUCCESS_EXPECTED }; /* arch_prctl() and sigaltstack() test */ @@ -489,99 +478,6 @@ static void test_fork(void) _exit(0); } -/* Ptrace test */ - -/* - * Make sure the ptracee has the expanded kernel buffer on the first - * use. Then, initialize the state before performing the state - * injection from the ptracer. - */ -static inline void ptracee_firstuse_tiledata(void) -{ - load_rand_tiledata(stashed_xsave); - init_xtiledata(); -} - -/* - * Ptracer injects the randomized tile data state. It also reads - * before and after that, which will execute the kernel's state copy - * functions. So, the tester is advised to double-check any emitted - * kernel messages. - */ -static void ptracer_inject_tiledata(pid_t target) -{ - struct xsave_buffer *xbuf; - struct iovec iov; - - xbuf = alloc_xbuf(); - if (!xbuf) - fatal_error("unable to allocate XSAVE buffer"); - - printf("\tRead the init'ed tiledata via ptrace().\n"); - - iov.iov_base = xbuf; - iov.iov_len = xbuf_size; - - memset(stashed_xsave, 0, xbuf_size); - - if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) - fatal_error("PTRACE_GETREGSET"); - - if (!__compare_tiledata_state(stashed_xsave, xbuf)) - printf("[OK]\tThe init'ed tiledata was read from ptracee.\n"); - else - printf("[FAIL]\tThe init'ed tiledata was not read from ptracee.\n"); - - printf("\tInject tiledata via ptrace().\n"); - - load_rand_tiledata(xbuf); - - memcpy(&stashed_xsave->bytes[xtiledata.xbuf_offset], - &xbuf->bytes[xtiledata.xbuf_offset], - xtiledata.size); - - if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) - fatal_error("PTRACE_SETREGSET"); - - if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) - fatal_error("PTRACE_GETREGSET"); - - if (!__compare_tiledata_state(stashed_xsave, xbuf)) - printf("[OK]\tTiledata was correctly written to ptracee.\n"); - else - printf("[FAIL]\tTiledata was not correctly written to ptracee.\n"); -} - -static void test_ptrace(void) -{ - pid_t child; - int status; - - child = fork(); - if (child < 0) { - err(1, "fork"); - } else if (!child) { - if (ptrace(PTRACE_TRACEME, 0, NULL, NULL)) - err(1, "PTRACE_TRACEME"); - - ptracee_firstuse_tiledata(); - - raise(SIGTRAP); - _exit(0); - } - - do { - wait(&status); - } while (WSTOPSIG(status) != SIGTRAP); - - ptracer_inject_tiledata(child); - - ptrace(PTRACE_DETACH, child, NULL, NULL); - wait(&status); - if (!WIFEXITED(status) || WEXITSTATUS(status)) - err(1, "ptrace test"); -} - int main(void) { const unsigned int ctxtsw_num_threads = 5, ctxtsw_iterations = 10; @@ -594,8 +490,6 @@ int main(void) return KSFT_SKIP; } - xbuf_size = get_xbuf_size(); - xtiledata = get_xstate_info(XFEATURE_XTILEDATA); if (!xtiledata.size || !xtiledata.xbuf_offset) { fatal_error("xstate cpuid: invalid tile data size/offset: %d/%d", @@ -614,7 +508,7 @@ int main(void) test_context_switch(XFEATURE_XTILEDATA, ctxtsw_num_threads, ctxtsw_iterations); - test_ptrace(); + test_ptrace(XFEATURE_XTILEDATA); clearhandler(SIGILL); free_stashed_xsave(); diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests/x86/xstate.c index e5b51e7d13e1..d318b35ba547 100644 --- a/tools/testing/selftests/x86/xstate.c +++ b/tools/testing/selftests/x86/xstate.c @@ -2,12 +2,25 @@ #define _GNU_SOURCE +#include #include #include +#include +#include +#include + #include "helpers.h" #include "xstate.h" +static inline uint64_t xgetbv(uint32_t index) +{ + uint32_t eax, edx; + + asm volatile("xgetbv" : "=a" (eax), "=d" (edx) : "c" (index)); + return eax + ((uint64_t)edx << 32); +} + static struct xstate_info xstate; struct futex_info { @@ -27,6 +40,19 @@ static inline void load_rand_xstate(struct xstate_info *xstate, struct xsave_buf xrstor(xbuf, xstate->mask); } +static inline void load_init_xstate(struct xstate_info *xstate, struct xsave_buffer *xbuf) +{ + clear_xstate_header(xbuf); + xrstor(xbuf, xstate->mask); +} + +static inline void copy_xstate(struct xsave_buffer *xbuf_dst, struct xsave_buffer *xbuf_src) +{ + memcpy(&xbuf_dst->bytes[xstate.xbuf_offset], + &xbuf_src->bytes[xstate.xbuf_offset], + xstate.size); +} + static inline bool validate_xstate_same(struct xsave_buffer *xbuf1, struct xsave_buffer *xbuf2) { int ret; @@ -196,3 +222,106 @@ void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t it free(finfo); } + +/* + * Ptrace test for the ABI format as described in arch/x86/include/asm/user.h + */ + +/* + * Make sure the ptracee has the expanded kernel buffer on the first use. + * Then, initialize the state before performing the state injection from + * the ptracer. For non-dynamic states, this is benign. + */ +static inline void ptracee_touch_xstate(void) +{ + struct xsave_buffer *xbuf; + + xbuf = alloc_xbuf(); + + load_rand_xstate(&xstate, xbuf); + load_init_xstate(&xstate, xbuf); + + free(xbuf); +} + +/* + * Ptracer injects the randomized xstate data. It also reads before and + * after that, which will execute the kernel's state copy functions. + */ +static void ptracer_inject_xstate(pid_t target) +{ + uint32_t xbuf_size = get_xbuf_size(); + struct xsave_buffer *xbuf1, *xbuf2; + struct iovec iov; + + /* + * Allocate buffers to keep data while ptracer can write the + * other buffer + */ + xbuf1 = alloc_xbuf(); + xbuf2 = alloc_xbuf(); + if (!xbuf1 || !xbuf2) + ksft_exit_fail_msg("unable to allocate XSAVE buffer\n"); + + iov.iov_base = xbuf1; + iov.iov_len = xbuf_size; + + if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) + ksft_exit_fail_msg("PTRACE_GETREGSET failed\n"); + + printf("[RUN]\t%s: inject xstate via ptrace().\n", xstate.name); + + load_rand_xstate(&xstate, xbuf1); + copy_xstate(xbuf2, xbuf1); + + if (ptrace(PTRACE_SETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) + ksft_exit_fail_msg("PTRACE_SETREGSET failed\n"); + + if (ptrace(PTRACE_GETREGSET, target, (uint32_t)NT_X86_XSTATE, &iov)) + ksft_exit_fail_msg("PTRACE_GETREGSET failed\n"); + + if (*(uint64_t *)get_fpx_sw_bytes(xbuf1) == xgetbv(0)) + printf("[OK]\t'xfeatures' in SW reserved area was correctly written\n"); + else + printf("[FAIL]\t'xfeatures' in SW reserved area was not correctly written\n"); + + if (validate_xstate_same(xbuf2, xbuf1)) + printf("[OK]\txstate was correctly updated.\n"); + else + printf("[FAIL]\txstate was not correctly updated.\n"); + + free(xbuf1); + free(xbuf2); +} + +void test_ptrace(uint32_t feature_num) +{ + pid_t child; + int status; + + xstate = get_xstate_info(feature_num); + + child = fork(); + if (child < 0) { + ksft_exit_fail_msg("fork() failed\n"); + } else if (!child) { + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL)) + ksft_exit_fail_msg("PTRACE_TRACEME failed\n"); + + ptracee_touch_xstate(); + + raise(SIGTRAP); + _exit(0); + } + + do { + wait(&status); + } while (WSTOPSIG(status) != SIGTRAP); + + ptracer_inject_xstate(child); + + ptrace(PTRACE_DETACH, child, NULL, NULL); + wait(&status); + if (!WIFEXITED(status) || WEXITSTATUS(status)) + ksft_exit_fail_msg("ptracee exit error\n"); +} diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index 5ef66f247eb9..2bf11d3a3ce9 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -190,5 +190,6 @@ static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer } void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations); +void test_ptrace(uint32_t feature_num); #endif /* __SELFTESTS_X86_XSTATE_H */ From patchwork Wed Feb 26 01:07:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991204 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C213A187342; Wed, 26 Feb 2025 01:07:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532061; cv=none; b=hg4s7dHful26ron4h7lw/WhKiz90+MdjHJKMTPi+DNShoqntKHhxOsgl0aLzilhIZ2J2ttUaTRkOMvl+jpAn5eobeFeVygmczHB5YaagaDDMT6WO2jkdxG3Vr4EoAjSvzoLLnVUufjbhXLSJjTrjlm3YHhl05Och8ulm7LrDIl8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532061; c=relaxed/simple; bh=coXXT2jWow+DVw31djbygBL3uwg6cY+eFGQfiQPL7G8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FY37VKId4jiy9qZSlL8rqOAgVhAF41K4hxB4HVc8HeVR5zMaxJQvjF8cfpqC/G/lgR/R5DuqRhsDxMcRsCMTbXuzutmiBRcEwUyeJLg28vYBYk44kUgmR/mB67tIpE5RAUueuB47SKLGox1y4oFONdQb8JVvz1NdvKuyVJ09MQA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=V6hettGc; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="V6hettGc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532060; x=1772068060; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=coXXT2jWow+DVw31djbygBL3uwg6cY+eFGQfiQPL7G8=; b=V6hettGc0Xj/Qv4RiIcuzfQyLI1FY8HBRpwK0bOtslgApYq5R+exy+H9 2VdMb2eRU+76/b1BlolStHNz/uN2Wdnfu1qPmDePl5b5bt0qHoB876R9B ia/Rm+FCHVmDQ/49teyWC6P1pLsukRoaj2be9RLD4EXZg386trUc8+OAs /PGUiQqQSwHpcTxOrssNm3r8QktYLvP6wpyd7YIwS4jxzIClf3rzGiNKX ZEXCPpMlPJg62/qM6FAc0Ggas+RIh3GwxgRjwaD0XJcxeXNXYpzEeANK2 giWDLmLlbXjcMZJJZD5YP9tCw/oGlIuMu4/mn5jwOoOwCp5EV+RF6HTlR Q==; X-CSE-ConnectionGUID: wYHq7ZDbT6qaU0vAtXvb0g== X-CSE-MsgGUID: BMAo3DD6Qr2NZdksxjjRqw== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362214" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362214" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:39 -0800 X-CSE-ConnectionGUID: 0Kec9owVTN2U+DEYJ1KHNQ== X-CSE-MsgGUID: hv8aXUN7T6WRep0eqdL+IA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467355" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:39 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 6/9] selftests/x86/xstate: Introduce signal ABI test Date: Tue, 25 Feb 2025 17:07:26 -0800 Message-ID: <20250226010731.2456-7-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 With the refactored test cases, another xstate exposure to userspace is through signal delivery. While amx.c includes signal-related scenarios, its primary focus is on xstate permission management, which is largely specific to dynamic states. The remaining gap is testing xstate preservation and restoration across signal delivery. The kernel defines an ABI for presenting xstate in the signal frame, closely resembling the hardware XSAVE format, where xstate modification is also possible. Introduce a new test case to verify xstate preservation across signal delivery and return, that is ensuring ABI compatibility by: - Loading xstate before raising a signal. - Verifying correct exposure in the signal frame - Modifying xstate in the signal frame before returning. - Checking the state restoration upon signal return. Integrate this test into the AMX test suite as an initial usage site. Signed-off-by: Chang S. Bae --- Expected output: $ amx_64 ... [RUN] AMX Tile data: load xstate and raise SIGUSR1 [OK] 'magic1' is valid [OK] 'xfeatures' in SW reserved area is valid [OK] 'xfeatures' in XSAVE header is valid [OK] xstate delivery was successful [OK] 'magic2' is valid [RUN] AMX Tile data: load new xstate from sighandler and check it after sigreturn [OK] xstate was restored correctly --- tools/testing/selftests/x86/amx.c | 2 + tools/testing/selftests/x86/xstate.c | 108 +++++++++++++++++++++++++++ tools/testing/selftests/x86/xstate.h | 1 + 3 files changed, 111 insertions(+) diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index 4bafbb72aa1b..9cb691d67ef4 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -510,6 +510,8 @@ int main(void) test_ptrace(XFEATURE_XTILEDATA); + test_signal(XFEATURE_XTILEDATA); + clearhandler(SIGILL); free_stashed_xsave(); diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests/x86/xstate.c index d318b35ba547..b5600f492632 100644 --- a/tools/testing/selftests/x86/xstate.c +++ b/tools/testing/selftests/x86/xstate.c @@ -21,6 +21,11 @@ static inline uint64_t xgetbv(uint32_t index) return eax + ((uint64_t)edx << 32); } +static inline uint64_t get_xstatebv(struct xsave_buffer *xbuf) +{ + return *(uint64_t *)(&xbuf->header); +} + static struct xstate_info xstate; struct futex_info { @@ -325,3 +330,106 @@ void test_ptrace(uint32_t feature_num) if (!WIFEXITED(status) || WEXITSTATUS(status)) ksft_exit_fail_msg("ptracee exit error\n"); } + +/* + * Test signal delivery for the ABI compatibility. + * See the ABI format: arch/x86/include/uapi/asm/sigcontext.h + */ + +/* + * Avoid using printf() in signal handlers as it is not + * async-signal-safe. + */ +#define SIGNAL_BUF_LEN 1000 +static char signal_message_buffer[SIGNAL_BUF_LEN]; +static void sig_print(char *msg) +{ + int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1; + + strncat(signal_message_buffer, msg, left); +} + +static struct xsave_buffer *stashed_xbuf; + +static void validate_sigfpstate(int sig, siginfo_t *si, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t *)ctx_void; + void *xbuf = ctx->uc_mcontext.fpregs; + struct _fpx_sw_bytes *sw_bytes; + uint32_t magic2; + + /* Reset the signal message buffer: */ + signal_message_buffer[0] = '\0'; + + sw_bytes = get_fpx_sw_bytes(xbuf); + if (sw_bytes->magic1 == FP_XSTATE_MAGIC1) + sig_print("[OK]\t'magic1' is valid\n"); + else + sig_print("[FAIL]\t'magic1' is not valid\n"); + + if (get_fpx_sw_bytes_features(xbuf) & xstate.mask) + sig_print("[OK]\t'xfeatures' in SW reserved area is valid\n"); + else + sig_print("[FAIL]\t'xfeatures' in SW reserved area is not valid\n"); + + if (get_xstatebv(xbuf) & xstate.mask) + sig_print("[OK]\t'xfeatures' in XSAVE header is valid\n"); + else + sig_print("[FAIL]\t'xfeatures' in XSAVE hader is not valid\n"); + + if (validate_xstate_same(stashed_xbuf, xbuf)) + sig_print("[OK]\txstate delivery was successful\n"); + else + sig_print("[FAIL]\txstate delivery was not successful\n"); + + magic2 = *(uint32_t *)(xbuf + sw_bytes->xstate_size); + if (magic2 == FP_XSTATE_MAGIC2) + sig_print("[OK]\t'magic2' is valid\n"); + else + sig_print("[FAIL]\t'magic2' is not valid\n"); + + set_rand_data(&xstate, xbuf); + copy_xstate(stashed_xbuf, xbuf); +} + +void test_signal(uint32_t feature_num) +{ + bool valid_xstate; + + xstate = get_xstate_info(feature_num); + + /* + * The signal handler will access this to verify xstate context + * preservation. + */ + + stashed_xbuf = alloc_xbuf(); + if (!stashed_xbuf) + ksft_exit_fail_msg("unable to allocate XSAVE buffer\n"); + + printf("[RUN]\t%s: load xstate and raise SIGUSR1\n", xstate.name); + + sethandler(SIGUSR1, validate_sigfpstate, 0); + + load_rand_xstate(&xstate, stashed_xbuf); + + raise(SIGUSR1); + + /* + * Immediately record the test result, deferring printf() to + * prevent unintended state contamination by that. + */ + valid_xstate = validate_xregs_same(stashed_xbuf); + printf("%s", signal_message_buffer); + + printf("[RUN]\t%s: load new xstate from sighandler and check it after sigreturn\n", + xstate.name); + + if (valid_xstate) + printf("[OK]\txstate was restored correctly\n"); + else + printf("[FAIL]\txstate restoration failed\n"); + + clearhandler(SIGUSR1); + free(stashed_xbuf); +} diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index 2bf11d3a3ce9..4d0ffe9609f8 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -191,5 +191,6 @@ static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations); void test_ptrace(uint32_t feature_num); +void test_signal(uint32_t feature_num); #endif /* __SELFTESTS_X86_XSTATE_H */ From patchwork Wed Feb 26 01:07:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991205 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF10218BC1D; Wed, 26 Feb 2025 01:07:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532062; cv=none; b=hxSPtChjmiZuCJPrhtd8n8wmURldn7Pqr0vKHCnJP8//dIfQNZZVyEuqqM0IMqoqgS25uyGBVTA83MrXDk6feldWF8UTfIfdHzResOCtuhRjs/TwmJDWTWykAA8kD1M7sKv7/+xD6mmnTuThaHPTCaZqsYUFJwVROdASN0DnRuw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532062; c=relaxed/simple; bh=9YBDXFEcVpn+YUGYCCd7rdMdPLUA7BlZD2eLYNIaDkQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tnqzwnHdLkSg9s+8Tr71FBkEhTqx0T8cXqScLL/FGpwZSd/2Gr+zo0C6J/p3/Go80FNU7JCK4q14qVH09pRzsRZmJDLQrmPJcKQz0wQ1a3QbvPCnWcWhQL1YEPrfKrrCouv9jS4Wk+HVjB0os/esojhzFZQBM0qbEpeMuloXpKk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=O2ooicsm; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="O2ooicsm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532061; x=1772068061; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9YBDXFEcVpn+YUGYCCd7rdMdPLUA7BlZD2eLYNIaDkQ=; b=O2ooicsmsfqYkhyhDsV1wL7j0wk+B5HOdJ04rWOFPRsTsiAnImj+Ztme y0gch69EcbsajmTi02ODhgRGTTeYLja4ShKUECn25glNdvD/C6bSeqsh5 ynPPiVVe0BuMg1wN1GPKaknjSIkOXWnW+nLIZBLmcY2XpwKtr/RpH5/3W SufSC6z/mfFciqZkaJVVqK0r9cyrZEldrcKY+2pQeg0IOKAtmYr34667e a1d/1R36sGHe6Y1o/bfXZ1LIpzNlq9H4O5sWDF9tLDldFEl6VBE3QjwjP L2FQuiAN6IdtSVaXLXA0r+94wmOmbgfud6adleRBM/CJWxvIoq+zlqjLd A==; X-CSE-ConnectionGUID: W0rrWYqQTM6D7bPF3THZvg== X-CSE-MsgGUID: zcuBhHk8S/mzVP5MjOJldQ== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362221" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362221" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:40 -0800 X-CSE-ConnectionGUID: AS2vZx5xQgWBW6OOyybA5A== X-CSE-MsgGUID: z6RgEkpcTgu0EYobbzMi4A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467359" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:40 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 7/9] selftests/x86/xstate: Consolidate test invocations into a single entry Date: Tue, 25 Feb 2025 17:07:27 -0800 Message-ID: <20250226010731.2456-8-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently, each of the three xstate tests runs as a separate invocation, requiring the xstate number to be passed and state information to be reconstructed repeatedly. This approach arose from their individual and isolated development, but now it makes sense to unify them. Introduce a wrapper function that first verifies feature availability from the kernel and constructs the necessary state information once. The wrapper then sequentially invokes all tests to ensure consistent execution. Update the AMX test to use this unified invocation. Signed-off-by: Chang S. Bae --- tools/testing/selftests/x86/amx.c | 11 ++++---- tools/testing/selftests/x86/xstate.c | 38 ++++++++++++++++++++-------- tools/testing/selftests/x86/xstate.h | 5 ++-- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c index 9cb691d67ef4..40769c16de1b 100644 --- a/tools/testing/selftests/x86/amx.c +++ b/tools/testing/selftests/x86/amx.c @@ -480,7 +480,6 @@ static void test_fork(void) int main(void) { - const unsigned int ctxtsw_num_threads = 5, ctxtsw_iterations = 10; unsigned long features; long rc; @@ -506,11 +505,11 @@ int main(void) test_fork(); - test_context_switch(XFEATURE_XTILEDATA, ctxtsw_num_threads, ctxtsw_iterations); - - test_ptrace(XFEATURE_XTILEDATA); - - test_signal(XFEATURE_XTILEDATA); + /* + * Perform generic xstate tests for context switching, ptrace, + * and signal. + */ + test_xstate(XFEATURE_XTILEDATA); clearhandler(SIGILL); free_stashed_xsave(); diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests/x86/xstate.c index b5600f492632..fd8451e55f3f 100644 --- a/tools/testing/selftests/x86/xstate.c +++ b/tools/testing/selftests/x86/xstate.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include @@ -189,15 +191,13 @@ static void affinitize_cpu0(void) ksft_exit_fail_msg("sched_setaffinity to CPU 0 failed\n"); } -void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations) +static void test_context_switch(uint32_t num_threads, uint32_t iterations) { struct futex_info *finfo; /* Affinitize to one CPU to force context switches */ affinitize_cpu0(); - xstate = get_xstate_info(feature_num); - printf("[RUN]\t%s: check context switches, %d iterations, %d threads.\n", xstate.name, iterations, num_threads); @@ -299,13 +299,11 @@ static void ptracer_inject_xstate(pid_t target) free(xbuf2); } -void test_ptrace(uint32_t feature_num) +static void test_ptrace(void) { pid_t child; int status; - xstate = get_xstate_info(feature_num); - child = fork(); if (child < 0) { ksft_exit_fail_msg("fork() failed\n"); @@ -392,17 +390,14 @@ static void validate_sigfpstate(int sig, siginfo_t *si, void *ctx_void) copy_xstate(stashed_xbuf, xbuf); } -void test_signal(uint32_t feature_num) +static void test_signal(void) { bool valid_xstate; - xstate = get_xstate_info(feature_num); - /* * The signal handler will access this to verify xstate context * preservation. */ - stashed_xbuf = alloc_xbuf(); if (!stashed_xbuf) ksft_exit_fail_msg("unable to allocate XSAVE buffer\n"); @@ -433,3 +428,26 @@ void test_signal(uint32_t feature_num) clearhandler(SIGUSR1); free(stashed_xbuf); } + +void test_xstate(uint32_t feature_num) +{ + const unsigned int ctxtsw_num_threads = 5, ctxtsw_iterations = 10; + unsigned long features; + long rc; + + rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); + if (rc || !(features & (1 << feature_num))) { + ksft_print_msg("The kernel does not support feature number: %u\n", feature_num); + return; + } + + xstate = get_xstate_info(feature_num); + if (!xstate.size || !xstate.xbuf_offset) { + ksft_exit_fail_msg("invalid state size/offset (%d/%d)\n", + xstate.size, xstate.xbuf_offset); + } + + test_context_switch(ctxtsw_num_threads, ctxtsw_iterations); + test_ptrace(); + test_signal(); +} diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index 4d0ffe9609f8..42af36ec852f 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -189,8 +189,7 @@ static inline void set_rand_data(struct xstate_info *xstate, struct xsave_buffer *ptr = data; } -void test_context_switch(uint32_t feature_num, uint32_t num_threads, uint32_t iterations); -void test_ptrace(uint32_t feature_num); -void test_signal(uint32_t feature_num); +/* Testing kernel's context switching and ABI support for the xstate. */ +void test_xstate(uint32_t feature_num); #endif /* __SELFTESTS_X86_XSTATE_H */ From patchwork Wed Feb 26 01:07:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991206 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8EB9818DB3E; Wed, 26 Feb 2025 01:07:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532063; cv=none; b=SkZ6tndtvZKaEoqq6koDmQg2MQTiANsl0Ny96lV3u6lpu+013pmOEnkBT5I9x4SteiDal3EC/uv2/RQrkGSm19HtE6oiFKPPFsajoaiTu3OjfPWg4ny+YwKih9SO/U/IDDM5HCcUmKFP4clVFdmSsQC+/PSyrtEhPTTDbDxjKMQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532063; c=relaxed/simple; bh=4sTOw2av5PulmOSKLaCJyfyuR6ivrfW3vA9KaO3Cjfc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VCJwfX2qrjukSoCUjjln7Mj/o/ce7LQeSsx0kLHxD1Ng2X4jlRAP37FZFvczt9OPYh3i/9Hyrck+4eC2EudO/B9r51pOLYAjaUA/Pl4WeQoXrQZ16BH2ZCPH1KPmC0CxFu1SVLdO1E8dSKK+uaRqQylHghgMHJwy8VAgwW8MCY4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=cHbjbEcw; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="cHbjbEcw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532061; x=1772068061; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4sTOw2av5PulmOSKLaCJyfyuR6ivrfW3vA9KaO3Cjfc=; b=cHbjbEcw33YKPGUVSIT7ukl1HngEwpG791Ls8sZyyE7P61VSxz7pQQmp LaFayXKxxN+Q/09T3oetWgiDPW/YEYdXDU2YVgu7oNtdvOcPHRAF3Lz3P pnfYnrPB3SyDkOWKbdyWjZlj0dwxLkJoRUVfQL2bEqCIQ73nPvRK0NnQC BVN1pLNqFqO+S2Obzji/JDIQevJtUTmUN9qLAUA26SrUbAl47VwN8EibW u4XbfvJgtEqlCUDEUjWaU36VUkoGEIItf1Wxq2DNq5rnXn4Z/Ffbf0zGM qnb/7cADB9j7FdufvzWbUXm+Rxc571w+cJEExsGOuHzUkW96gl239s8TU Q==; X-CSE-ConnectionGUID: 4o9VWn48TpGBmEhP6/o/Vg== X-CSE-MsgGUID: it2iQC/+R/2ZMP5borl5Lw== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362228" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362228" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:41 -0800 X-CSE-ConnectionGUID: D4RKixikTgmzrFGdginQ4g== X-CSE-MsgGUID: Y07lTYroRtK1SdRbGK0oTg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467363" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:41 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 8/9] selftests/x86/xstate: Clarify supported xstates Date: Tue, 25 Feb 2025 17:07:28 -0800 Message-ID: <20250226010731.2456-9-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The established xstate test code is designed to be generic, but certain xstates require special handling and cannot be tested without additional adjustments. Clarify which xstates are currently supported, and enforce testing only for them. Signed-off-by: Chang S. Bae --- tools/testing/selftests/x86/xstate.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests/x86/xstate.c index fd8451e55f3f..875777911d82 100644 --- a/tools/testing/selftests/x86/xstate.c +++ b/tools/testing/selftests/x86/xstate.c @@ -15,6 +15,24 @@ #include "helpers.h" #include "xstate.h" +/* + * The userspace xstate test suite is designed to be generic and operates + * with randomized xstate data. However, some states require special handling: + * + * - PKRU and XTILECFG need specific adjustments, such as modifying + * randomization behavior or using fixed values. + * - But, PKRU already has a dedicated test suite in /tools/selftests/mm. + * - Legacy states (FP and SSE) are excluded, as they are not considered + * part of extended states (xstates) and their usage is already deeply + * integrated into user-space libraries. + */ +#define XFEATURE_MASK_TEST_SUPPORTED \ + ((1 << XFEATURE_YMM) | \ + (1 << XFEATURE_OPMASK) | \ + (1 << XFEATURE_ZMM_Hi256) | \ + (1 << XFEATURE_Hi16_ZMM) | \ + (1 << XFEATURE_XTILEDATA)) + static inline uint64_t xgetbv(uint32_t index) { uint32_t eax, edx; @@ -435,6 +453,12 @@ void test_xstate(uint32_t feature_num) unsigned long features; long rc; + if (!(XFEATURE_MASK_TEST_SUPPORTED & (1 << feature_num))) { + ksft_print_msg("The xstate test does not fully support the component %u, yet.\n", + feature_num); + return; + } + rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); if (rc || !(features & (1 << feature_num))) { ksft_print_msg("The kernel does not support feature number: %u\n", feature_num); From patchwork Wed Feb 26 01:07:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 13991207 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7E712192D76; Wed, 26 Feb 2025 01:07:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532065; cv=none; b=VT/ZSZIU+nQfUT6y7yfvSl7RzZE+M85aDo00hddwIrWULN0Mc0gM2/zPwVFESHpRLx9nVQ4QlRttZqws1eR8loWmt3A2JcwjtYkIuCeIpUvO3XeP4+Gqeaz8XBEqMHdpttlhlShezyQzO/1YYeklG+oEygjTpZlNeE2dkLUOtjM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740532065; c=relaxed/simple; bh=QOJubvXVS/z+HN4zuJjtVNV1JTEpRBGWWqwVUZO8LIc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gX/xNZS7q6Rd84hZtE56ZjJBzZCcjxMyoSfyN0Exr0ZMzycqa1q7drFudtYIqCPLCS70SO/aD3OJQrgVK10mmNMhYF0gddAP0ZZLkbeXMZQ8rUKnMjNrRsBAfGggW3HT8gqD8Pt2HoPDv6I3gRSMCUHGE/A7+FMxMogHdwYsGKQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=lfmYjdG/; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="lfmYjdG/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1740532063; x=1772068063; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QOJubvXVS/z+HN4zuJjtVNV1JTEpRBGWWqwVUZO8LIc=; b=lfmYjdG/Y0fLrFgsnyhinUfkiuOqjT6GiEKC8OfZp/7JMyiVEaV8c5aT +B9AM5HMyNgJ9qiMQ03o8sunSJfCdXg+SE7NfYb+VWl/aaeYqAqFxHGmf 8bJcl1Eik1W2G24wvN5hfGr9lBr6yrH4+KY+CVrG+BDofwjB+xlW3LBij BiSVFFCSkDTPIftnS8qI/7raC30ftWLuC5IhxCWBFDmbgZ/Wux+xN5ulP Z0kg/RSLWZ2TIPg8o2TodhQX9Knwz8LHZ0cf1lIxyj8l75rnBFBYxOsg0 /AMPbSki8Sxolka8WJci993uYAy1g8zXxOQR6/em4qN9vS+WYc/OhHe1s Q==; X-CSE-ConnectionGUID: 5feO+N/lTQaSYXCPUNdXvg== X-CSE-MsgGUID: 07gsZhJDSOKEeK/vQZE6rA== X-IronPort-AV: E=McAfee;i="6700,10204,11356"; a="52362233" X-IronPort-AV: E=Sophos;i="6.13,316,1732608000"; d="scan'208";a="52362233" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Feb 2025 17:07:43 -0800 X-CSE-ConnectionGUID: hJErFlpRSMebY3lem8Horg== X-CSE-MsgGUID: 3v3Eec9NQe2TzaXxrRCxnA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,224,1728975600"; d="scan'208";a="147467368" Received: from cbae1-mobl.amr.corp.intel.com (HELO cbae1-mobl.intel.com) ([10.124.166.169]) by fmviesa001.fm.intel.com with ESMTP; 25 Feb 2025 17:07:42 -0800 From: "Chang S. Bae" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: x86@kernel.org, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, shuah@kernel.org, chang.seok.bae@intel.com Subject: [PATCH 9/9] selftests/x86/avx: Add AVX test Date: Tue, 25 Feb 2025 17:07:29 -0800 Message-ID: <20250226010731.2456-10-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250226010731.2456-1-chang.seok.bae@intel.com> References: <20250226010731.2456-1-chang.seok.bae@intel.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add xstate testing specifically for those vector register states, validating kernel's context switching and ensuring ABI compliance. Use the established xstate testing framework. Signed-off-by: Chang S. Bae --- Alternatively, this invocation could be placed directly in xstate.c::main(). However, the current test file naming convention, which clearly specifies the tested area, seems reasonable. Adding avx.c considerably aligns with that convention. The test output should be like this for ZMM_Hi256 as an example: $ avx_64 ... [RUN] AVX-512 ZMM_Hi256: check context switches, 10 iterations, 5 threads. [OK] No incorrect case was found. [RUN] AVX-512 ZMM_Hi256: inject xstate via ptrace(). [OK] 'xfeatures' in SW reserved area was correctly written [OK] xstate was correctly updated. [RUN] AVX-512 ZMM_Hi256: load xstate and raise SIGUSR1 [OK] 'magic1' is valid [OK] 'xfeatures' in SW reserved area is valid [OK] 'xfeatures' in XSAVE header is valid [OK] xstate delivery was successful [OK] 'magic2' is valid [RUN] AVX-512 ZMM_Hi256: load new xstate from sighandler and check it after sigreturn [OK] xstate was restored correctly But systems without AVX-512 will look like: ... The kernel does not support feature number: 5 The kernel does not support feature number: 6 The kernel does not support feature number: 7 --- tools/testing/selftests/x86/Makefile | 4 +++- tools/testing/selftests/x86/avx.c | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/avx.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index f15efdc6aef7..28422c32cc8f 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -19,7 +19,7 @@ TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer TARGETS_C_64BIT_ONLY := fsgsbase sysret_rip syscall_numbering \ - corrupt_xstate_header amx lam test_shadow_stack + corrupt_xstate_header amx lam test_shadow_stack avx # Some selftests require 32bit support enabled also on 64bit systems TARGETS_C_32BIT_NEEDED := ldt_gdt ptrace_syscall @@ -133,4 +133,6 @@ $(OUTPUT)/check_initial_reg_state_64: CFLAGS += -Wl,-ereal_start -static $(OUTPUT)/nx_stack_32: CFLAGS += -Wl,-z,noexecstack $(OUTPUT)/nx_stack_64: CFLAGS += -Wl,-z,noexecstack +$(OUTPUT)/avx_64: CFLAGS += -mno-avx -mno-avx512f $(OUTPUT)/amx_64: EXTRA_FILES += xstate.c +$(OUTPUT)/avx_64: EXTRA_FILES += xstate.c diff --git a/tools/testing/selftests/x86/avx.c b/tools/testing/selftests/x86/avx.c new file mode 100644 index 000000000000..11d5367c235f --- /dev/null +++ b/tools/testing/selftests/x86/avx.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE /* Required for inline xstate helpers */ +#include "xstate.h" + +int main(void) +{ + test_xstate(XFEATURE_YMM); + test_xstate(XFEATURE_OPMASK); + test_xstate(XFEATURE_ZMM_Hi256); + test_xstate(XFEATURE_Hi16_ZMM); +}