18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2015, Michael Neuling, IBM Corp.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Test the kernel's signal return code to ensure that it doesn't
68c2ecf20Sopenharmony_ci * crash when both the transactional and suspend MSR bits are set in
78c2ecf20Sopenharmony_ci * the signal context.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * For this test, we send ourselves a SIGUSR1.  In the SIGUSR1 handler
108c2ecf20Sopenharmony_ci * we modify the signal context to set both MSR TM S and T bits (which
118c2ecf20Sopenharmony_ci * is "reserved" by the PowerISA). When we return from the signal
128c2ecf20Sopenharmony_ci * handler (implicit sigreturn), the kernel should detect reserved MSR
138c2ecf20Sopenharmony_ci * value and send us with a SIGSEGV.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <stdlib.h>
178c2ecf20Sopenharmony_ci#include <stdio.h>
188c2ecf20Sopenharmony_ci#include <signal.h>
198c2ecf20Sopenharmony_ci#include <unistd.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "utils.h"
228c2ecf20Sopenharmony_ci#include "tm.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ciint segv_expected = 0;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid signal_segv(int signum)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	if (segv_expected && (signum == SIGSEGV))
298c2ecf20Sopenharmony_ci		_exit(0);
308c2ecf20Sopenharmony_ci	_exit(1);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_civoid signal_usr1(int signum, siginfo_t *info, void *uc)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	ucontext_t *ucp = uc;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Link tm checkpointed context to normal context */
388c2ecf20Sopenharmony_ci	ucp->uc_link = ucp;
398c2ecf20Sopenharmony_ci	/* Set all TM bits so that the context is now invalid */
408c2ecf20Sopenharmony_ci#ifdef __powerpc64__
418c2ecf20Sopenharmony_ci	ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32);
428c2ecf20Sopenharmony_ci#else
438c2ecf20Sopenharmony_ci	ucp->uc_mcontext.uc_regs->gregs[PT_MSR] |= (7ULL);
448c2ecf20Sopenharmony_ci#endif
458c2ecf20Sopenharmony_ci	/* Should segv on return becuase of invalid context */
468c2ecf20Sopenharmony_ci	segv_expected = 1;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciint tm_signal_msr_resv()
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct sigaction act;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	SKIP_IF(!have_htm());
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	act.sa_sigaction = signal_usr1;
568c2ecf20Sopenharmony_ci	sigemptyset(&act.sa_mask);
578c2ecf20Sopenharmony_ci	act.sa_flags = SA_SIGINFO;
588c2ecf20Sopenharmony_ci	if (sigaction(SIGUSR1, &act, NULL) < 0) {
598c2ecf20Sopenharmony_ci		perror("sigaction sigusr1");
608c2ecf20Sopenharmony_ci		exit(1);
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	if (signal(SIGSEGV, signal_segv) == SIG_ERR)
638c2ecf20Sopenharmony_ci		exit(1);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	raise(SIGUSR1);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* We shouldn't get here as we exit in the segv handler */
688c2ecf20Sopenharmony_ci	return 1;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciint main(void)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv");
748c2ecf20Sopenharmony_ci}
75