diff mbox series

[v5,26/28] selftest/x86/amx: Test case for AMX state copy optimization in signal delivery

Message ID 20210523193259.26200-27-chang.seok.bae@intel.com
State New
Headers show
Series None | expand

Commit Message

Chang S. Bae May 23, 2021, 7:32 p.m. UTC
Add a test case to verify that unused states are excluded, by leaving a
known pattern on the signal stack and verifying that it is still intact
after taking a subsequent signal.

Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Reviewed-by: Len Brown <len.brown@intel.com>
Cc: x86@kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
---
Changes from v4:
* Separated out as a new patch.
* Improved the test routine by explicitly checking sigframe write.
---
 tools/testing/selftests/x86/amx.c | 137 ++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)
diff mbox series

Patch

diff --git a/tools/testing/selftests/x86/amx.c b/tools/testing/selftests/x86/amx.c
index 7d177c03cdcf..c5a5582e2b6f 100644
--- a/tools/testing/selftests/x86/amx.c
+++ b/tools/testing/selftests/x86/amx.c
@@ -562,6 +562,142 @@  static void test_ptrace(void)
 	test_tile_write();
 }
 
+/* Signal handling test */
+
+static bool init_tiledata_state_before_signal;
+static bool load_tiledata_at_first;
+static bool sigalarmed, sigused;
+
+#define SIGFRAME_TILEDATA_SIGNATURE	0xFF
+
+static void handle_sigusr1(int sig, siginfo_t *info, void *ctx_void)
+{
+	void *xsave = ((ucontext_t *)ctx_void)->uc_mcontext.fpregs;
+
+	memset(xsave + xsave_xtiledata_offset, SIGFRAME_TILEDATA_SIGNATURE, xsave_xtiledata_size);
+
+	sigused = true;
+}
+
+static void handle_sigalrm(int sig, siginfo_t *info, void *ctx_void)
+{
+	void *xsave = ((ucontext_t *)ctx_void)->uc_mcontext.fpregs;
+	char d = SIGFRAME_TILEDATA_SIGNATURE;
+	bool written = false;
+	int i;
+
+	for (i = 0; i < xsave_xtiledata_size; i++) {
+		written = memcmp(xsave + xsave_xtiledata_offset + i, &d, 1);
+		if (written)
+			break;
+	}
+
+	if (__xgetbv(1) & XFEATURE_MASK_XTILEDATA)
+		err(1, "tile data state at signal delivery");
+
+	if (init_tiledata_state_before_signal && written) {
+		errs++;
+		printf("[FAIL]\tTile data was %swritten on sigframe.\n", !written ? "not " : "");
+	}
+
+	set_xstatebv(xsave_buffer, XFEATURE_MASK_XTILEDATA);
+	set_tiledata(xsave_buffer + xsave_xtiledata_offset);
+	xrstor(xsave_buffer, -1, -1);
+	sigalarmed = true;
+}
+
+static void test_signal_handling(void)
+{
+	pid_t child;
+
+	sigalarmed = false;
+	sigused = false;
+
+	child = fork();
+	if (child < 0) {
+		err(1, "fork");
+	} else if (child > 0) {
+		do {
+			int status;
+
+			wait(&status);
+			if (WIFSTOPPED(status))
+				kill(child, SIGCONT);
+			else if (WIFEXITED(status) && !WEXITSTATUS(status))
+				break;
+			else
+				err(1, "signal test child");
+		} while (1);
+		return;
+	}
+
+	printf("\tBefore signal, load tile data -- %s, re-initialized -- %s:\n",
+	       load_tiledata_at_first ? "yes" : "no",
+	       init_tiledata_state_before_signal ? "yes" : "no");
+
+	syscall(SYS_arch_prctl, ARCH_GET_XSTATE, XFEATURE_MASK_XTILE);
+
+	raise(SIGUSR1);
+	if (!sigused)
+		err(1, "SIGUSR1");
+
+	if (load_tiledata_at_first) {
+		set_xstatebv(xsave_buffer, XFEATURE_MASK_XTILEDATA);
+		set_tiledata(xsave_buffer + xsave_xtiledata_offset);
+		xrstor(xsave_buffer, -1, -1);
+		memcpy(tiledata, xsave_buffer + xsave_xtiledata_offset, xsave_xtiledata_size);
+	}
+
+	if (init_tiledata_state_before_signal) {
+		set_xstatebv(xsave_buffer, 0);
+		xrstor(xsave_buffer, -1, -1);
+		memset(tiledata, 0, xsave_xtiledata_size);
+	}
+
+	raise(SIGALRM);
+	if (!sigalarmed)
+		err(1, "SIGALRM");
+
+	__xsave(xsave_buffer, XFEATURE_MASK_XTILEDATA, 0);
+	if (memcmp(tiledata, xsave_buffer + xsave_xtiledata_offset, xsave_xtiledata_size)) {
+		errs++;
+		printf("[FAIL]\tTile data was not restored at sigreturn\n");
+	}
+
+	if (errs)
+		nerrs++;
+	else
+		printf("[OK]\tTile data was %swritten on sigframe and restored at sigreturn\n",
+		       init_tiledata_state_before_signal ? "not " : "");
+	_exit(0);
+}
+
+static void test_signal(void)
+{
+	printf("[RUN]\tCheck tile data state in signal path:\n");
+
+	sethandler(SIGALRM, handle_sigalrm, 0);
+	sethandler(SIGUSR1, handle_sigusr1, 0);
+
+	load_tiledata_at_first = false;
+	init_tiledata_state_before_signal = true;
+	errs = 0;
+	test_signal_handling();
+
+	load_tiledata_at_first = true;
+	init_tiledata_state_before_signal = false;
+	errs = 0;
+	test_signal_handling();
+
+	load_tiledata_at_first = true;
+	init_tiledata_state_before_signal = true;
+	errs = 0;
+	test_signal_handling();
+
+	clearhandler(SIGALRM);
+	clearhandler(SIGUSR1);
+}
+
 int main(void)
 {
 	/* Check hardware availability at first */
@@ -592,6 +728,7 @@  int main(void)
 	test_fork();
 	test_context_switch();
 	test_ptrace();
+	test_signal();
 
 	clearhandler(SIGSEGV);