18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2016, Cyril Bur, IBM Corp. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Test the kernel's signal frame code. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The kernel sets up two sets of ucontexts if the signal was to be 88c2ecf20Sopenharmony_ci * delivered while the thread was in a transaction (referred too as 98c2ecf20Sopenharmony_ci * first and second contexts). 108c2ecf20Sopenharmony_ci * Expected behaviour is that the checkpointed state is in the user 118c2ecf20Sopenharmony_ci * context passed to the signal handler (first context). The speculated 128c2ecf20Sopenharmony_ci * state can be accessed with the uc_link pointer (second context). 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The rationale for this is that if TM unaware code (which linked 158c2ecf20Sopenharmony_ci * against TM libs) installs a signal handler it will not know of the 168c2ecf20Sopenharmony_ci * speculative nature of the 'live' registers and may infer the wrong 178c2ecf20Sopenharmony_ci * thing. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <stdlib.h> 218c2ecf20Sopenharmony_ci#include <stdio.h> 228c2ecf20Sopenharmony_ci#include <signal.h> 238c2ecf20Sopenharmony_ci#include <unistd.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <altivec.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "utils.h" 288c2ecf20Sopenharmony_ci#include "tm.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define MAX_ATTEMPT 500000 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define NV_GPR_REGS 18 /* Number of non-volatile GPR registers */ 338c2ecf20Sopenharmony_ci#define R14 14 /* First non-volatile register to check in r14-r31 subset */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cilong tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic sig_atomic_t fail, broken; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Test only non-volatile general purpose registers, i.e. r14-r31 */ 408c2ecf20Sopenharmony_cistatic long gprs[] = { 418c2ecf20Sopenharmony_ci /* First context will be set with these values, i.e. non-speculative */ 428c2ecf20Sopenharmony_ci /* R14, R15, ... */ 438c2ecf20Sopenharmony_ci 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 448c2ecf20Sopenharmony_ci /* Second context will be set with these values, i.e. speculative */ 458c2ecf20Sopenharmony_ci /* R14, R15, ... */ 468c2ecf20Sopenharmony_ci -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void signal_usr1(int signum, siginfo_t *info, void *uc) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci int i; 528c2ecf20Sopenharmony_ci ucontext_t *ucp = uc; 538c2ecf20Sopenharmony_ci ucontext_t *tm_ucp = ucp->uc_link; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Check first context. Print all mismatches. */ 568c2ecf20Sopenharmony_ci for (i = 0; i < NV_GPR_REGS; i++) { 578c2ecf20Sopenharmony_ci fail = (ucp->uc_mcontext.gp_regs[R14 + i] != gprs[i]); 588c2ecf20Sopenharmony_ci if (fail) { 598c2ecf20Sopenharmony_ci broken = 1; 608c2ecf20Sopenharmony_ci printf("GPR%d (1st context) == %lu instead of %lu (expected)\n", 618c2ecf20Sopenharmony_ci R14 + i, ucp->uc_mcontext.gp_regs[R14 + i], gprs[i]); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Check second context. Print all mismatches. */ 668c2ecf20Sopenharmony_ci for (i = 0; i < NV_GPR_REGS; i++) { 678c2ecf20Sopenharmony_ci fail = (tm_ucp->uc_mcontext.gp_regs[R14 + i] != gprs[NV_GPR_REGS + i]); 688c2ecf20Sopenharmony_ci if (fail) { 698c2ecf20Sopenharmony_ci broken = 1; 708c2ecf20Sopenharmony_ci printf("GPR%d (2nd context) == %lu instead of %lu (expected)\n", 718c2ecf20Sopenharmony_ci R14 + i, tm_ucp->uc_mcontext.gp_regs[R14 + i], gprs[NV_GPR_REGS + i]); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int tm_signal_context_chk_gpr() 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct sigaction act; 798c2ecf20Sopenharmony_ci int i; 808c2ecf20Sopenharmony_ci long rc; 818c2ecf20Sopenharmony_ci pid_t pid = getpid(); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci SKIP_IF(!have_htm()); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci act.sa_sigaction = signal_usr1; 868c2ecf20Sopenharmony_ci sigemptyset(&act.sa_mask); 878c2ecf20Sopenharmony_ci act.sa_flags = SA_SIGINFO; 888c2ecf20Sopenharmony_ci if (sigaction(SIGUSR1, &act, NULL) < 0) { 898c2ecf20Sopenharmony_ci perror("sigaction sigusr1"); 908c2ecf20Sopenharmony_ci exit(1); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci i = 0; 948c2ecf20Sopenharmony_ci while (i < MAX_ATTEMPT && !broken) { 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * tm_signal_self_context_load will set both first and second 978c2ecf20Sopenharmony_ci * contexts accordingly to the values passed through non-NULL 988c2ecf20Sopenharmony_ci * array pointers to it, in that case 'gprs', and invoke the 998c2ecf20Sopenharmony_ci * signal handler installed for SIGUSR1. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci rc = tm_signal_self_context_load(pid, gprs, NULL, NULL, NULL); 1028c2ecf20Sopenharmony_ci FAIL_IF(rc != pid); 1038c2ecf20Sopenharmony_ci i++; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return broken; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint main(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci return test_harness(tm_signal_context_chk_gpr, "tm_signal_context_chk_gpr"); 1128c2ecf20Sopenharmony_ci} 113