xref: /openbmc/linux/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f10d4424SCyril Bur /*
3f10d4424SCyril Bur  * Copyright 2016, Cyril Bur, IBM Corp.
4f10d4424SCyril Bur  *
5f10d4424SCyril Bur  * Test the kernel's signal frame code.
6f10d4424SCyril Bur  *
7f10d4424SCyril Bur  * The kernel sets up two sets of ucontexts if the signal was to be
89d535e20SGustavo Romero  * delivered while the thread was in a transaction (referred too as
99d535e20SGustavo Romero  * first and second contexts).
10f10d4424SCyril Bur  * Expected behaviour is that the checkpointed state is in the user
119d535e20SGustavo Romero  * context passed to the signal handler (first context). The speculated
129d535e20SGustavo Romero  * state can be accessed with the uc_link pointer (second context).
13f10d4424SCyril Bur  *
14f10d4424SCyril Bur  * The rationale for this is that if TM unaware code (which linked
15f10d4424SCyril Bur  * against TM libs) installs a signal handler it will not know of the
16f10d4424SCyril Bur  * speculative nature of the 'live' registers and may infer the wrong
17f10d4424SCyril Bur  * thing.
18f10d4424SCyril Bur  */
19f10d4424SCyril Bur 
20f10d4424SCyril Bur #include <stdlib.h>
21f10d4424SCyril Bur #include <stdio.h>
22f10d4424SCyril Bur #include <signal.h>
23f10d4424SCyril Bur #include <unistd.h>
24f10d4424SCyril Bur 
25f10d4424SCyril Bur #include <altivec.h>
26f10d4424SCyril Bur 
27f10d4424SCyril Bur #include "utils.h"
28f10d4424SCyril Bur #include "tm.h"
29f10d4424SCyril Bur 
30f10d4424SCyril Bur #define MAX_ATTEMPT 500000
31f10d4424SCyril Bur 
329d535e20SGustavo Romero #define NV_GPR_REGS 18 /* Number of non-volatile GPR registers */
339d535e20SGustavo Romero #define R14 14 /* First non-volatile register to check in r14-r31 subset */
34f10d4424SCyril Bur 
35f10d4424SCyril Bur long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
36f10d4424SCyril Bur 
379d535e20SGustavo Romero static sig_atomic_t fail, broken;
38f10d4424SCyril Bur 
399d535e20SGustavo Romero /* Test only non-volatile general purpose registers, i.e. r14-r31 */
409d535e20SGustavo Romero static long gprs[] = {
419d535e20SGustavo Romero 	/* First context will be set with these values, i.e. non-speculative */
429d535e20SGustavo Romero 	/* R14, R15, ... */
439d535e20SGustavo Romero 	 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
449d535e20SGustavo Romero 	/* Second context will be set with these values, i.e. speculative */
459d535e20SGustavo Romero 	/* R14, R15, ... */
469d535e20SGustavo Romero 	-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
479d535e20SGustavo Romero };
48f10d4424SCyril Bur 
signal_usr1(int signum,siginfo_t * info,void * uc)49f10d4424SCyril Bur static void signal_usr1(int signum, siginfo_t *info, void *uc)
50f10d4424SCyril Bur {
51f10d4424SCyril Bur 	int i;
52f10d4424SCyril Bur 	ucontext_t *ucp = uc;
53f10d4424SCyril Bur 	ucontext_t *tm_ucp = ucp->uc_link;
54f10d4424SCyril Bur 
559d535e20SGustavo Romero 	/* Check first context. Print all mismatches. */
569d535e20SGustavo Romero 	for (i = 0; i < NV_GPR_REGS; i++) {
579d535e20SGustavo Romero 		fail = (ucp->uc_mcontext.gp_regs[R14 + i] != gprs[i]);
589d535e20SGustavo Romero 		if (fail) {
599d535e20SGustavo Romero 			broken = 1;
609d535e20SGustavo Romero 			printf("GPR%d (1st context) == %lu instead of %lu (expected)\n",
619d535e20SGustavo Romero 				R14 + i, ucp->uc_mcontext.gp_regs[R14 + i], gprs[i]);
629d535e20SGustavo Romero 		}
639d535e20SGustavo Romero 	}
649d535e20SGustavo Romero 
659d535e20SGustavo Romero 	/* Check second context. Print all mismatches. */
669d535e20SGustavo Romero 	for (i = 0; i < NV_GPR_REGS; i++) {
679d535e20SGustavo Romero 		fail = (tm_ucp->uc_mcontext.gp_regs[R14 + i] != gprs[NV_GPR_REGS + i]);
689d535e20SGustavo Romero 		if (fail) {
699d535e20SGustavo Romero 			broken = 1;
709d535e20SGustavo Romero 			printf("GPR%d (2nd context) == %lu instead of %lu (expected)\n",
719d535e20SGustavo Romero 				R14 + i, tm_ucp->uc_mcontext.gp_regs[R14 + i], gprs[NV_GPR_REGS + i]);
729d535e20SGustavo Romero 		}
73f10d4424SCyril Bur 	}
74f10d4424SCyril Bur }
75f10d4424SCyril Bur 
tm_signal_context_chk_gpr()76f10d4424SCyril Bur static int tm_signal_context_chk_gpr()
77f10d4424SCyril Bur {
78f10d4424SCyril Bur 	struct sigaction act;
79f10d4424SCyril Bur 	int i;
80f10d4424SCyril Bur 	long rc;
81f10d4424SCyril Bur 	pid_t pid = getpid();
82f10d4424SCyril Bur 
83f10d4424SCyril Bur 	SKIP_IF(!have_htm());
84*e42edf9bSJordan Niethe 	SKIP_IF(htm_is_synthetic());
85f10d4424SCyril Bur 
86f10d4424SCyril Bur 	act.sa_sigaction = signal_usr1;
87f10d4424SCyril Bur 	sigemptyset(&act.sa_mask);
88f10d4424SCyril Bur 	act.sa_flags = SA_SIGINFO;
89f10d4424SCyril Bur 	if (sigaction(SIGUSR1, &act, NULL) < 0) {
90f10d4424SCyril Bur 		perror("sigaction sigusr1");
91f10d4424SCyril Bur 		exit(1);
92f10d4424SCyril Bur 	}
93f10d4424SCyril Bur 
94f10d4424SCyril Bur 	i = 0;
959d535e20SGustavo Romero 	while (i < MAX_ATTEMPT && !broken) {
969d535e20SGustavo Romero                 /*
979d535e20SGustavo Romero                  * tm_signal_self_context_load will set both first and second
989d535e20SGustavo Romero                  * contexts accordingly to the values passed through non-NULL
999d535e20SGustavo Romero                  * array pointers to it, in that case 'gprs', and invoke the
1009d535e20SGustavo Romero                  * signal handler installed for SIGUSR1.
1019d535e20SGustavo Romero                  */
1029d535e20SGustavo Romero 		rc = tm_signal_self_context_load(pid, gprs, NULL, NULL, NULL);
103f10d4424SCyril Bur 		FAIL_IF(rc != pid);
104f10d4424SCyril Bur 		i++;
105f10d4424SCyril Bur 	}
106f10d4424SCyril Bur 
1079d535e20SGustavo Romero 	return broken;
108f10d4424SCyril Bur }
109f10d4424SCyril Bur 
main(void)110f10d4424SCyril Bur int main(void)
111f10d4424SCyril Bur {
112f10d4424SCyril Bur 	return test_harness(tm_signal_context_chk_gpr, "tm_signal_context_chk_gpr");
113f10d4424SCyril Bur }
114