18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2018, Breno Leitao, Gustavo Romero, IBM Corp. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This test raises a SIGUSR1 signal, and toggle the MSR[TS] 68c2ecf20Sopenharmony_ci * fields at the signal handler. With MSR[TS] being set, the kernel will 78c2ecf20Sopenharmony_ci * force a recheckpoint, which may cause a segfault when returning to 88c2ecf20Sopenharmony_ci * user space. Since the test needs to re-run, the segfault needs to be 98c2ecf20Sopenharmony_ci * caught and handled. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * In order to continue the test even after a segfault, the context is 128c2ecf20Sopenharmony_ci * saved prior to the signal being raised, and it is restored when there is 138c2ecf20Sopenharmony_ci * a segmentation fault. This happens for COUNT_MAX times. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This test never fails (as returning EXIT_FAILURE). It either succeeds, 168c2ecf20Sopenharmony_ci * or crash the kernel (on a buggy kernel). 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define _GNU_SOURCE 208c2ecf20Sopenharmony_ci#include <stdio.h> 218c2ecf20Sopenharmony_ci#include <stdlib.h> 228c2ecf20Sopenharmony_ci#include <signal.h> 238c2ecf20Sopenharmony_ci#include <string.h> 248c2ecf20Sopenharmony_ci#include <ucontext.h> 258c2ecf20Sopenharmony_ci#include <unistd.h> 268c2ecf20Sopenharmony_ci#include <sys/mman.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "tm.h" 298c2ecf20Sopenharmony_ci#include "utils.h" 308c2ecf20Sopenharmony_ci#include "reg.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define COUNT_MAX 5000 /* Number of interactions */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * This test only runs on 64 bits system. Unsetting MSR_TS_S to avoid 368c2ecf20Sopenharmony_ci * compilation issue on 32 bits system. There is no side effect, since the 378c2ecf20Sopenharmony_ci * whole test will be skipped if it is not running on 64 bits system. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci#ifndef __powerpc64__ 408c2ecf20Sopenharmony_ci#undef MSR_TS_S 418c2ecf20Sopenharmony_ci#define MSR_TS_S 0 428c2ecf20Sopenharmony_ci#endif 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Setting contexts because the test will crash and we want to recover */ 458c2ecf20Sopenharmony_ciucontext_t init_context; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* count is changed in the signal handler, so it must be volatile */ 488c2ecf20Sopenharmony_cistatic volatile int count; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid usr_signal_handler(int signo, siginfo_t *si, void *uc) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci ucontext_t *ucp = uc; 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* 568c2ecf20Sopenharmony_ci * Allocating memory in a signal handler, and never freeing it on 578c2ecf20Sopenharmony_ci * purpose, forcing the heap increase, so, the memory leak is what 588c2ecf20Sopenharmony_ci * we want here. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci ucp->uc_link = mmap(NULL, sizeof(ucontext_t), 618c2ecf20Sopenharmony_ci PROT_READ | PROT_WRITE, 628c2ecf20Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 638c2ecf20Sopenharmony_ci if (ucp->uc_link == (void *)-1) { 648c2ecf20Sopenharmony_ci perror("Mmap failed"); 658c2ecf20Sopenharmony_ci exit(-1); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Forcing the page to be allocated in a page fault */ 698c2ecf20Sopenharmony_ci ret = madvise(ucp->uc_link, sizeof(ucontext_t), MADV_DONTNEED); 708c2ecf20Sopenharmony_ci if (ret) { 718c2ecf20Sopenharmony_ci perror("madvise failed"); 728c2ecf20Sopenharmony_ci exit(-1); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci memcpy(&ucp->uc_link->uc_mcontext, &ucp->uc_mcontext, 768c2ecf20Sopenharmony_ci sizeof(ucp->uc_mcontext)); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Forcing to enable MSR[TM] */ 798c2ecf20Sopenharmony_ci UCONTEXT_MSR(ucp) |= MSR_TS_S; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * A fork inside a signal handler seems to be more efficient than a 838c2ecf20Sopenharmony_ci * fork() prior to the signal being raised. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci if (fork() == 0) { 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * Both child and parent will return, but, child returns 888c2ecf20Sopenharmony_ci * with count set so it will exit in the next segfault. 898c2ecf20Sopenharmony_ci * Parent will continue to loop. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci count = COUNT_MAX; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * If the change above does not hit the bug, it will cause a 968c2ecf20Sopenharmony_ci * segmentation fault, since the ck structures are NULL. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_civoid seg_signal_handler(int signo, siginfo_t *si, void *uc) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci count++; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Reexecute the test */ 1058c2ecf20Sopenharmony_ci setcontext(&init_context); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_civoid tm_trap_test(void) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct sigaction usr_sa, seg_sa; 1118c2ecf20Sopenharmony_ci stack_t ss; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci usr_sa.sa_flags = SA_SIGINFO | SA_ONSTACK; 1148c2ecf20Sopenharmony_ci usr_sa.sa_sigaction = usr_signal_handler; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci seg_sa.sa_flags = SA_SIGINFO; 1178c2ecf20Sopenharmony_ci seg_sa.sa_sigaction = seg_signal_handler; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Set initial context. Will get back here from 1218c2ecf20Sopenharmony_ci * seg_signal_handler() 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci getcontext(&init_context); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci while (count < COUNT_MAX) { 1268c2ecf20Sopenharmony_ci /* Allocated an alternative signal stack area */ 1278c2ecf20Sopenharmony_ci ss.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, 1288c2ecf20Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 1298c2ecf20Sopenharmony_ci ss.ss_size = SIGSTKSZ; 1308c2ecf20Sopenharmony_ci ss.ss_flags = 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (ss.ss_sp == (void *)-1) { 1338c2ecf20Sopenharmony_ci perror("mmap error\n"); 1348c2ecf20Sopenharmony_ci exit(-1); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Force the allocation through a page fault */ 1388c2ecf20Sopenharmony_ci if (madvise(ss.ss_sp, SIGSTKSZ, MADV_DONTNEED)) { 1398c2ecf20Sopenharmony_ci perror("madvise\n"); 1408c2ecf20Sopenharmony_ci exit(-1); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * Setting an alternative stack to generate a page fault when 1458c2ecf20Sopenharmony_ci * the signal is raised. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (sigaltstack(&ss, NULL)) { 1488c2ecf20Sopenharmony_ci perror("sigaltstack\n"); 1498c2ecf20Sopenharmony_ci exit(-1); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* The signal handler will enable MSR_TS */ 1538c2ecf20Sopenharmony_ci sigaction(SIGUSR1, &usr_sa, NULL); 1548c2ecf20Sopenharmony_ci /* If it does not crash, it might segfault, avoid it to retest */ 1558c2ecf20Sopenharmony_ci sigaction(SIGSEGV, &seg_sa, NULL); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci raise(SIGUSR1); 1588c2ecf20Sopenharmony_ci count++; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciint tm_signal_context_force_tm(void) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci SKIP_IF(!have_htm()); 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * Skipping if not running on 64 bits system, since I think it is 1678c2ecf20Sopenharmony_ci * not possible to set mcontext's [MSR] with TS, due to it being 32 1688c2ecf20Sopenharmony_ci * bits. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci SKIP_IF(!is_ppc64le()); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci tm_trap_test(); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return EXIT_SUCCESS; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciint main(int argc, char **argv) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci test_harness(tm_signal_context_force_tm, "tm_signal_context_force_tm"); 1808c2ecf20Sopenharmony_ci} 181