162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2015, Michael Neuling, IBM Corp.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Test the kernel's signal delievery code to ensure that we don't
662306a36Sopenharmony_ci * trelaim twice in the kernel signal delivery code.  This can happen
762306a36Sopenharmony_ci * if we trigger a signal when in a transaction and the stack pointer
862306a36Sopenharmony_ci * is bogus.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This test case registers a SEGV handler, sets the stack pointer
1162306a36Sopenharmony_ci * (r1) to NULL, starts a transaction and then generates a SEGV.  The
1262306a36Sopenharmony_ci * SEGV should be handled but we exit here as the stack pointer is
1362306a36Sopenharmony_ci * invalid and hance we can't sigreturn.  We only need to check that
1462306a36Sopenharmony_ci * this flow doesn't crash the kernel.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <unistd.h>
1862306a36Sopenharmony_ci#include <sys/types.h>
1962306a36Sopenharmony_ci#include <sys/wait.h>
2062306a36Sopenharmony_ci#include <stdlib.h>
2162306a36Sopenharmony_ci#include <stdio.h>
2262306a36Sopenharmony_ci#include <signal.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "utils.h"
2562306a36Sopenharmony_ci#include "tm.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_civoid signal_segv(int signum)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	/* This should never actually run since stack is foobar */
3062306a36Sopenharmony_ci	exit(1);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciint tm_signal_stack()
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	int pid;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	SKIP_IF(!have_htm());
3862306a36Sopenharmony_ci	SKIP_IF(htm_is_synthetic());
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	pid = fork();
4162306a36Sopenharmony_ci	if (pid < 0)
4262306a36Sopenharmony_ci		exit(1);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (pid) { /* Parent */
4562306a36Sopenharmony_ci		/*
4662306a36Sopenharmony_ci		 * It's likely the whole machine will crash here so if
4762306a36Sopenharmony_ci		 * the child ever exits, we are good.
4862306a36Sopenharmony_ci		 */
4962306a36Sopenharmony_ci		wait(NULL);
5062306a36Sopenharmony_ci		return 0;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	/*
5462306a36Sopenharmony_ci	 * The flow here is:
5562306a36Sopenharmony_ci	 * 1) register a signal handler (so signal delievery occurs)
5662306a36Sopenharmony_ci	 * 2) make stack pointer (r1) = NULL
5762306a36Sopenharmony_ci	 * 3) start transaction
5862306a36Sopenharmony_ci	 * 4) cause segv
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	if (signal(SIGSEGV, signal_segv) == SIG_ERR)
6162306a36Sopenharmony_ci		exit(1);
6262306a36Sopenharmony_ci	asm volatile("li 1, 0 ;"		/* stack ptr == NULL */
6362306a36Sopenharmony_ci		     "1:"
6462306a36Sopenharmony_ci		     "tbegin.;"
6562306a36Sopenharmony_ci		     "beq 1b ;"			/* retry forever */
6662306a36Sopenharmony_ci		     "tsuspend.;"
6762306a36Sopenharmony_ci		     "ld 2, 0(1) ;"		/* trigger segv" */
6862306a36Sopenharmony_ci		     : : : "memory");
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* This should never get here due to above segv */
7162306a36Sopenharmony_ci	return 1;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciint main(void)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	return test_harness(tm_signal_stack, "tm_signal_stack");
7762306a36Sopenharmony_ci}
78