|
@@ -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");
|
|
|
+}
|