1 /* 2 * Copyright 2015, Sam Bobroff, IBM Corp. 3 * Licensed under GPLv2. 4 * 5 * Test the kernel's system call code to ensure that a system call 6 * made from within an active HTM transaction is aborted with the 7 * correct failure code. 8 * Conversely, ensure that a system call made from within a 9 * suspended transaction can succeed. 10 */ 11 12 #include <stdio.h> 13 #include <unistd.h> 14 #include <sys/syscall.h> 15 #include <asm/tm.h> 16 #include <asm/cputable.h> 17 #include <linux/auxvec.h> 18 #include <sys/time.h> 19 #include <stdlib.h> 20 21 #include "utils.h" 22 23 extern int getppid_tm_active(void); 24 extern int getppid_tm_suspended(void); 25 26 unsigned retries = 0; 27 28 #define TEST_DURATION 10 /* seconds */ 29 #define TM_RETRIES 100 30 31 long failure_code(void) 32 { 33 return __builtin_get_texasru() >> 24; 34 } 35 36 bool failure_is_persistent(void) 37 { 38 return (failure_code() & TM_CAUSE_PERSISTENT) == TM_CAUSE_PERSISTENT; 39 } 40 41 bool failure_is_syscall(void) 42 { 43 return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL; 44 } 45 46 pid_t getppid_tm(bool suspend) 47 { 48 int i; 49 pid_t pid; 50 51 for (i = 0; i < TM_RETRIES; i++) { 52 if (suspend) 53 pid = getppid_tm_suspended(); 54 else 55 pid = getppid_tm_active(); 56 57 if (pid >= 0) 58 return pid; 59 60 if (failure_is_persistent()) { 61 if (failure_is_syscall()) 62 return -1; 63 64 printf("Unexpected persistent transaction failure.\n"); 65 printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 66 __builtin_get_texasr(), __builtin_get_tfiar()); 67 exit(-1); 68 } 69 70 retries++; 71 } 72 73 printf("Exceeded limit of %d temporary transaction failures.\n", TM_RETRIES); 74 printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n", 75 __builtin_get_texasr(), __builtin_get_tfiar()); 76 77 exit(-1); 78 } 79 80 static inline bool have_htm_nosc(void) 81 { 82 #ifdef PPC_FEATURE2_HTM_NOSC 83 return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM_NOSC); 84 #else 85 printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n"); 86 return false; 87 #endif 88 } 89 90 int tm_syscall(void) 91 { 92 unsigned count = 0; 93 struct timeval end, now; 94 95 SKIP_IF(!have_htm_nosc()); 96 97 setbuf(stdout, NULL); 98 99 printf("Testing transactional syscalls for %d seconds...\n", TEST_DURATION); 100 101 gettimeofday(&end, NULL); 102 now.tv_sec = TEST_DURATION; 103 now.tv_usec = 0; 104 timeradd(&end, &now, &end); 105 106 for (count = 0; timercmp(&now, &end, <); count++) { 107 /* 108 * Test a syscall within a suspended transaction and verify 109 * that it succeeds. 110 */ 111 FAIL_IF(getppid_tm(true) == -1); /* Should succeed. */ 112 113 /* 114 * Test a syscall within an active transaction and verify that 115 * it fails with the correct failure code. 116 */ 117 FAIL_IF(getppid_tm(false) != -1); /* Should fail... */ 118 FAIL_IF(!failure_is_persistent()); /* ...persistently... */ 119 FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ 120 gettimeofday(&now, 0); 121 } 122 123 printf("%d active and suspended transactions behaved correctly.\n", count); 124 printf("(There were %d transaction retries.)\n", retries); 125 126 return 0; 127 } 128 129 int main(void) 130 { 131 return test_harness(tm_syscall, "tm_syscall"); 132 } 133