diff options
Diffstat (limited to 'tools/testing/selftests/powerpc/tm/tm-signal-stack.c')
| -rw-r--r-- | tools/testing/selftests/powerpc/tm/tm-signal-stack.c | 76 | 
1 files changed, 76 insertions, 0 deletions
diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c new file mode 100644 index 000000000000..e44a238c1d77 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c @@ -0,0 +1,76 @@ +/* + * Copyright 2015, Michael Neuling, IBM Corp. + * Licensed under GPLv2. + * + * Test the kernel's signal delievery code to ensure that we don't + * trelaim twice in the kernel signal delivery code.  This can happen + * if we trigger a signal when in a transaction and the stack pointer + * is bogus. + * + * This test case registers a SEGV handler, sets the stack pointer + * (r1) to NULL, starts a transaction and then generates a SEGV.  The + * SEGV should be handled but we exit here as the stack pointer is + * invalid and hance we can't sigreturn.  We only need to check that + * this flow doesn't crash the kernel. + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> + +#include "utils.h" +#include "tm.h" + +void signal_segv(int signum) +{ +	/* This should never actually run since stack is foobar */ +	exit(1); +} + +int tm_signal_stack() +{ +	int pid; + +	SKIP_IF(!have_htm()); + +	pid = fork(); +	if (pid < 0) +		exit(1); + +	if (pid) { /* Parent */ +		/* +		 * It's likely the whole machine will crash here so if +		 * the child ever exits, we are good. +		 */ +		wait(NULL); +		return 0; +	} + +	/* +	 * The flow here is: +	 * 1) register a signal handler (so signal delievery occurs) +	 * 2) make stack pointer (r1) = NULL +	 * 3) start transaction +	 * 4) cause segv +	 */ +	if (signal(SIGSEGV, signal_segv) == SIG_ERR) +		exit(1); +	asm volatile("li 1, 0 ;"		/* stack ptr == NULL */ +		     "1:" +		     ".long 0x7C00051D ;"	/* tbegin */ +		     "beq 1b ;"			/* retry forever */ +		     ".long 0x7C0005DD ; ;"	/* tsuspend */ +		     "ld 2, 0(1) ;"		/* trigger segv" */ +		     : : : "memory"); + +	/* This should never get here due to above segv */ +	return 1; +} + +int main(void) +{ +	return test_harness(tm_signal_stack, "tm_signal_stack"); +}  | 
