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