18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2016, Cyril Bur, IBM Corp.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Test the kernel's signal frame code.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * The kernel sets up two sets of ucontexts if the signal was to be
88c2ecf20Sopenharmony_ci * delivered while the thread was in a transaction (referred too as
98c2ecf20Sopenharmony_ci * first and second contexts).
108c2ecf20Sopenharmony_ci * Expected behaviour is that the checkpointed state is in the user
118c2ecf20Sopenharmony_ci * context passed to the signal handler (first context). The speculated
128c2ecf20Sopenharmony_ci * state can be accessed with the uc_link pointer (second context).
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * The rationale for this is that if TM unaware code (which linked
158c2ecf20Sopenharmony_ci * against TM libs) installs a signal handler it will not know of the
168c2ecf20Sopenharmony_ci * speculative nature of the 'live' registers and may infer the wrong
178c2ecf20Sopenharmony_ci * thing.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <stdlib.h>
218c2ecf20Sopenharmony_ci#include <stdio.h>
228c2ecf20Sopenharmony_ci#include <string.h>
238c2ecf20Sopenharmony_ci#include <signal.h>
248c2ecf20Sopenharmony_ci#include <unistd.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <altivec.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "utils.h"
298c2ecf20Sopenharmony_ci#include "tm.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define MAX_ATTEMPT 500000
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define NV_VMX_REGS 12 /* Number of non-volatile VMX registers */
348c2ecf20Sopenharmony_ci#define VMX20 20 /* First non-volatile register to check in vr20-31 subset */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cilong tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic sig_atomic_t fail, broken;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Test only non-volatile registers, i.e. 12 vmx registers from vr20 to vr31 */
418c2ecf20Sopenharmony_civector int vms[] = {
428c2ecf20Sopenharmony_ci	/* First context will be set with these values, i.e. non-speculative */
438c2ecf20Sopenharmony_ci	/* VMX20     ,  VMX21      , ... */
448c2ecf20Sopenharmony_ci	{ 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12},
458c2ecf20Sopenharmony_ci	{13,14,15,16},{17,18,19,20},{21,22,23,24},
468c2ecf20Sopenharmony_ci	{25,26,27,28},{29,30,31,32},{33,34,35,36},
478c2ecf20Sopenharmony_ci	{37,38,39,40},{41,42,43,44},{45,46,47,48},
488c2ecf20Sopenharmony_ci	/* Second context will be set with these values, i.e. speculative */
498c2ecf20Sopenharmony_ci	/* VMX20        , VMX21            , ... */
508c2ecf20Sopenharmony_ci	{ -1, -2, -3, -4},{ -5, -6, -7, -8},{ -9,-10,-11,-12},
518c2ecf20Sopenharmony_ci	{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
528c2ecf20Sopenharmony_ci	{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
538c2ecf20Sopenharmony_ci	{-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void signal_usr1(int signum, siginfo_t *info, void *uc)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	int i, j;
598c2ecf20Sopenharmony_ci	ucontext_t *ucp = uc;
608c2ecf20Sopenharmony_ci	ucontext_t *tm_ucp = ucp->uc_link;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	for (i = 0; i < NV_VMX_REGS; i++) {
638c2ecf20Sopenharmony_ci		/* Check first context. Print all mismatches. */
648c2ecf20Sopenharmony_ci		fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[VMX20 + i],
658c2ecf20Sopenharmony_ci				&vms[i], sizeof(vector int));
668c2ecf20Sopenharmony_ci		if (fail) {
678c2ecf20Sopenharmony_ci			broken = 1;
688c2ecf20Sopenharmony_ci			printf("VMX%d (1st context) == 0x", VMX20 + i);
698c2ecf20Sopenharmony_ci			/* Print actual value in first context. */
708c2ecf20Sopenharmony_ci			for (j = 0; j < 4; j++)
718c2ecf20Sopenharmony_ci				printf("%08x", ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]);
728c2ecf20Sopenharmony_ci			printf(" instead of 0x");
738c2ecf20Sopenharmony_ci			/* Print expected value. */
748c2ecf20Sopenharmony_ci			for (j = 0; j < 4; j++)
758c2ecf20Sopenharmony_ci				printf("%08x", vms[i][j]);
768c2ecf20Sopenharmony_ci			printf(" (expected)\n");
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	for (i = 0; i < NV_VMX_REGS; i++)  {
818c2ecf20Sopenharmony_ci		/* Check second context. Print all mismatches. */
828c2ecf20Sopenharmony_ci		fail = memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i],
838c2ecf20Sopenharmony_ci				&vms[NV_VMX_REGS + i], sizeof (vector int));
848c2ecf20Sopenharmony_ci		if (fail) {
858c2ecf20Sopenharmony_ci			broken = 1;
868c2ecf20Sopenharmony_ci			printf("VMX%d (2nd context) == 0x", NV_VMX_REGS + i);
878c2ecf20Sopenharmony_ci			/* Print actual value in second context. */
888c2ecf20Sopenharmony_ci			for (j = 0; j < 4; j++)
898c2ecf20Sopenharmony_ci				printf("%08x", tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]);
908c2ecf20Sopenharmony_ci			printf(" instead of 0x");
918c2ecf20Sopenharmony_ci			/* Print expected value. */
928c2ecf20Sopenharmony_ci			for (j = 0; j < 4; j++)
938c2ecf20Sopenharmony_ci				printf("%08x", vms[NV_VMX_REGS + i][j]);
948c2ecf20Sopenharmony_ci			printf(" (expected)\n");
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic int tm_signal_context_chk()
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct sigaction act;
1028c2ecf20Sopenharmony_ci	int i;
1038c2ecf20Sopenharmony_ci	long rc;
1048c2ecf20Sopenharmony_ci	pid_t pid = getpid();
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	SKIP_IF(!have_htm());
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	act.sa_sigaction = signal_usr1;
1098c2ecf20Sopenharmony_ci	sigemptyset(&act.sa_mask);
1108c2ecf20Sopenharmony_ci	act.sa_flags = SA_SIGINFO;
1118c2ecf20Sopenharmony_ci	if (sigaction(SIGUSR1, &act, NULL) < 0) {
1128c2ecf20Sopenharmony_ci		perror("sigaction sigusr1");
1138c2ecf20Sopenharmony_ci		exit(1);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	i = 0;
1178c2ecf20Sopenharmony_ci	while (i < MAX_ATTEMPT && !broken) {
1188c2ecf20Sopenharmony_ci		/*
1198c2ecf20Sopenharmony_ci		 * tm_signal_self_context_load will set both first and second
1208c2ecf20Sopenharmony_ci		 * contexts accordingly to the values passed through non-NULL
1218c2ecf20Sopenharmony_ci		 * array pointers to it, in that case 'vms', and invoke the
1228c2ecf20Sopenharmony_ci		 * signal handler installed for SIGUSR1.
1238c2ecf20Sopenharmony_ci		 */
1248c2ecf20Sopenharmony_ci		rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL);
1258c2ecf20Sopenharmony_ci		FAIL_IF(rc != pid);
1268c2ecf20Sopenharmony_ci		i++;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return (broken);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ciint main(void)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vmx");
1358c2ecf20Sopenharmony_ci}
136