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 delievery code to ensure that we don't
68c2ecf20Sopenharmony_ci * trelaim twice in the kernel signal delivery code.  This can happen
78c2ecf20Sopenharmony_ci * if we trigger a signal when in a transaction and the stack pointer
88c2ecf20Sopenharmony_ci * is bogus.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This test case registers a SEGV handler, sets the stack pointer
118c2ecf20Sopenharmony_ci * (r1) to NULL, starts a transaction and then generates a SEGV.  The
128c2ecf20Sopenharmony_ci * SEGV should be handled but we exit here as the stack pointer is
138c2ecf20Sopenharmony_ci * invalid and hance we can't sigreturn.  We only need to check that
148c2ecf20Sopenharmony_ci * this flow doesn't crash the kernel.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <unistd.h>
188c2ecf20Sopenharmony_ci#include <sys/types.h>
198c2ecf20Sopenharmony_ci#include <sys/wait.h>
208c2ecf20Sopenharmony_ci#include <stdlib.h>
218c2ecf20Sopenharmony_ci#include <stdio.h>
228c2ecf20Sopenharmony_ci#include <signal.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "utils.h"
258c2ecf20Sopenharmony_ci#include "tm.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_civoid signal_segv(int signum)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	/* This should never actually run since stack is foobar */
308c2ecf20Sopenharmony_ci	exit(1);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciint tm_signal_stack()
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	int pid;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	SKIP_IF(!have_htm());
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	pid = fork();
408c2ecf20Sopenharmony_ci	if (pid < 0)
418c2ecf20Sopenharmony_ci		exit(1);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (pid) { /* Parent */
448c2ecf20Sopenharmony_ci		/*
458c2ecf20Sopenharmony_ci		 * It's likely the whole machine will crash here so if
468c2ecf20Sopenharmony_ci		 * the child ever exits, we are good.
478c2ecf20Sopenharmony_ci		 */
488c2ecf20Sopenharmony_ci		wait(NULL);
498c2ecf20Sopenharmony_ci		return 0;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/*
538c2ecf20Sopenharmony_ci	 * The flow here is:
548c2ecf20Sopenharmony_ci	 * 1) register a signal handler (so signal delievery occurs)
558c2ecf20Sopenharmony_ci	 * 2) make stack pointer (r1) = NULL
568c2ecf20Sopenharmony_ci	 * 3) start transaction
578c2ecf20Sopenharmony_ci	 * 4) cause segv
588c2ecf20Sopenharmony_ci	 */
598c2ecf20Sopenharmony_ci	if (signal(SIGSEGV, signal_segv) == SIG_ERR)
608c2ecf20Sopenharmony_ci		exit(1);
618c2ecf20Sopenharmony_ci	asm volatile("li 1, 0 ;"		/* stack ptr == NULL */
628c2ecf20Sopenharmony_ci		     "1:"
638c2ecf20Sopenharmony_ci		     "tbegin.;"
648c2ecf20Sopenharmony_ci		     "beq 1b ;"			/* retry forever */
658c2ecf20Sopenharmony_ci		     "tsuspend.;"
668c2ecf20Sopenharmony_ci		     "ld 2, 0(1) ;"		/* trigger segv" */
678c2ecf20Sopenharmony_ci		     : : : "memory");
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* This should never get here due to above segv */
708c2ecf20Sopenharmony_ci	return 1;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ciint main(void)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	return test_harness(tm_signal_stack, "tm_signal_stack");
768c2ecf20Sopenharmony_ci}
77