xref: /openbmc/linux/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
225007a69SMichael Neuling /*
325007a69SMichael Neuling  * Copyright 2015, Michael Neuling, IBM Corp.
425007a69SMichael Neuling  *
525007a69SMichael Neuling  * Test the kernel's signal return code to ensure that it doesn't
625007a69SMichael Neuling  * crash when both the transactional and suspend MSR bits are set in
725007a69SMichael Neuling  * the signal context.
825007a69SMichael Neuling  *
925007a69SMichael Neuling  * For this test, we send ourselves a SIGUSR1.  In the SIGUSR1 handler
1025007a69SMichael Neuling  * we modify the signal context to set both MSR TM S and T bits (which
1125007a69SMichael Neuling  * is "reserved" by the PowerISA). When we return from the signal
1225007a69SMichael Neuling  * handler (implicit sigreturn), the kernel should detect reserved MSR
1325007a69SMichael Neuling  * value and send us with a SIGSEGV.
1425007a69SMichael Neuling  */
1525007a69SMichael Neuling 
1625007a69SMichael Neuling #include <stdlib.h>
1725007a69SMichael Neuling #include <stdio.h>
1825007a69SMichael Neuling #include <signal.h>
1925007a69SMichael Neuling #include <unistd.h>
2025007a69SMichael Neuling 
2125007a69SMichael Neuling #include "utils.h"
2225007a69SMichael Neuling #include "tm.h"
2325007a69SMichael Neuling 
2425007a69SMichael Neuling int segv_expected = 0;
2525007a69SMichael Neuling 
signal_segv(int signum)2625007a69SMichael Neuling void signal_segv(int signum)
2725007a69SMichael Neuling {
2825007a69SMichael Neuling 	if (segv_expected && (signum == SIGSEGV))
2925007a69SMichael Neuling 		_exit(0);
3025007a69SMichael Neuling 	_exit(1);
3125007a69SMichael Neuling }
3225007a69SMichael Neuling 
signal_usr1(int signum,siginfo_t * info,void * uc)3325007a69SMichael Neuling void signal_usr1(int signum, siginfo_t *info, void *uc)
3425007a69SMichael Neuling {
3525007a69SMichael Neuling 	ucontext_t *ucp = uc;
3625007a69SMichael Neuling 
3725007a69SMichael Neuling 	/* Link tm checkpointed context to normal context */
3825007a69SMichael Neuling 	ucp->uc_link = ucp;
3925007a69SMichael Neuling 	/* Set all TM bits so that the context is now invalid */
4025007a69SMichael Neuling #ifdef __powerpc64__
4125007a69SMichael Neuling 	ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32);
4225007a69SMichael Neuling #else
43501e279cSMichael Ellerman 	ucp->uc_mcontext.uc_regs->gregs[PT_MSR] |= (7ULL);
4425007a69SMichael Neuling #endif
4525007a69SMichael Neuling 	/* Should segv on return becuase of invalid context */
4625007a69SMichael Neuling 	segv_expected = 1;
4725007a69SMichael Neuling }
4825007a69SMichael Neuling 
tm_signal_msr_resv()4925007a69SMichael Neuling int tm_signal_msr_resv()
5025007a69SMichael Neuling {
5125007a69SMichael Neuling 	struct sigaction act;
5225007a69SMichael Neuling 
5325007a69SMichael Neuling 	SKIP_IF(!have_htm());
5425007a69SMichael Neuling 
5525007a69SMichael Neuling 	act.sa_sigaction = signal_usr1;
5625007a69SMichael Neuling 	sigemptyset(&act.sa_mask);
5725007a69SMichael Neuling 	act.sa_flags = SA_SIGINFO;
5825007a69SMichael Neuling 	if (sigaction(SIGUSR1, &act, NULL) < 0) {
5925007a69SMichael Neuling 		perror("sigaction sigusr1");
6025007a69SMichael Neuling 		exit(1);
6125007a69SMichael Neuling 	}
6225007a69SMichael Neuling 	if (signal(SIGSEGV, signal_segv) == SIG_ERR)
6325007a69SMichael Neuling 		exit(1);
6425007a69SMichael Neuling 
6525007a69SMichael Neuling 	raise(SIGUSR1);
6625007a69SMichael Neuling 
6725007a69SMichael Neuling 	/* We shouldn't get here as we exit in the segv handler */
6825007a69SMichael Neuling 	return 1;
6925007a69SMichael Neuling }
7025007a69SMichael Neuling 
main(void)7125007a69SMichael Neuling int main(void)
7225007a69SMichael Neuling {
7325007a69SMichael Neuling 	return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv");
7425007a69SMichael Neuling }
75