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