1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2015, Sam Bobroff, IBM Corp. |
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 <sys/time.h> |
17 | #include <stdlib.h> |
18 | |
19 | #include "utils.h" |
20 | #include "tm.h" |
21 | |
22 | #ifndef PPC_FEATURE2_SCV |
23 | #define PPC_FEATURE2_SCV 0x00100000 /* scv syscall */ |
24 | #endif |
25 | |
26 | extern int getppid_tm_active(void); |
27 | extern int getppid_tm_suspended(void); |
28 | extern int getppid_scv_tm_active(void); |
29 | extern int getppid_scv_tm_suspended(void); |
30 | |
31 | unsigned retries = 0; |
32 | |
33 | #define TEST_DURATION 10 /* seconds */ |
34 | |
35 | pid_t getppid_tm(bool scv, bool suspend) |
36 | { |
37 | int i; |
38 | pid_t pid; |
39 | |
40 | for (i = 0; i < TM_RETRIES; i++) { |
41 | if (suspend) { |
42 | if (scv) |
43 | pid = getppid_scv_tm_suspended(); |
44 | else |
45 | pid = getppid_tm_suspended(); |
46 | } else { |
47 | if (scv) |
48 | pid = getppid_scv_tm_active(); |
49 | else |
50 | pid = getppid_tm_active(); |
51 | } |
52 | |
53 | if (pid >= 0) |
54 | return pid; |
55 | |
56 | if (failure_is_persistent()) { |
57 | if (failure_is_syscall()) |
58 | return -1; |
59 | |
60 | printf("Unexpected persistent transaction failure.\n" ); |
61 | printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n" , |
62 | __builtin_get_texasr(), __builtin_get_tfiar()); |
63 | exit(-1); |
64 | } |
65 | |
66 | retries++; |
67 | } |
68 | |
69 | printf("Exceeded limit of %d temporary transaction failures.\n" , TM_RETRIES); |
70 | printf("TEXASR 0x%016lx, TFIAR 0x%016lx.\n" , |
71 | __builtin_get_texasr(), __builtin_get_tfiar()); |
72 | |
73 | exit(-1); |
74 | } |
75 | |
76 | int tm_syscall(void) |
77 | { |
78 | unsigned count = 0; |
79 | struct timeval end, now; |
80 | |
81 | SKIP_IF(!have_htm_nosc()); |
82 | SKIP_IF(htm_is_synthetic()); |
83 | |
84 | setbuf(stdout, NULL); |
85 | |
86 | printf("Testing transactional syscalls for %d seconds...\n" , TEST_DURATION); |
87 | |
88 | gettimeofday(&end, NULL); |
89 | now.tv_sec = TEST_DURATION; |
90 | now.tv_usec = 0; |
91 | timeradd(&end, &now, &end); |
92 | |
93 | for (count = 0; timercmp(&now, &end, <); count++) { |
94 | /* |
95 | * Test a syscall within a suspended transaction and verify |
96 | * that it succeeds. |
97 | */ |
98 | FAIL_IF(getppid_tm(false, true) == -1); /* Should succeed. */ |
99 | |
100 | /* |
101 | * Test a syscall within an active transaction and verify that |
102 | * it fails with the correct failure code. |
103 | */ |
104 | FAIL_IF(getppid_tm(false, false) != -1); /* Should fail... */ |
105 | FAIL_IF(!failure_is_persistent()); /* ...persistently... */ |
106 | FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ |
107 | |
108 | /* Now do it all again with scv if it is available. */ |
109 | if (have_hwcap2(PPC_FEATURE2_SCV)) { |
110 | FAIL_IF(getppid_tm(true, true) == -1); /* Should succeed. */ |
111 | FAIL_IF(getppid_tm(true, false) != -1); /* Should fail... */ |
112 | FAIL_IF(!failure_is_persistent()); /* ...persistently... */ |
113 | FAIL_IF(!failure_is_syscall()); /* ...with code syscall. */ |
114 | } |
115 | |
116 | gettimeofday(&now, 0); |
117 | } |
118 | |
119 | printf("%d active and suspended transactions behaved correctly.\n" , count); |
120 | printf("(There were %d transaction retries.)\n" , retries); |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | int main(void) |
126 | { |
127 | return test_harness(tm_syscall, "tm_syscall" ); |
128 | } |
129 | |