1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...) |
4 | * |
5 | * Basic test to test behaviour of PR_GET_TSC and PR_SET_TSC |
6 | */ |
7 | |
8 | #include <stdio.h> |
9 | #include <stdlib.h> |
10 | #include <unistd.h> |
11 | #include <signal.h> |
12 | #include <inttypes.h> |
13 | |
14 | |
15 | #include <sys/prctl.h> |
16 | #include <linux/prctl.h> |
17 | |
18 | /* Get/set the process' ability to use the timestamp counter instruction */ |
19 | #ifndef PR_GET_TSC |
20 | #define PR_GET_TSC 25 |
21 | #define PR_SET_TSC 26 |
22 | # define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ |
23 | # define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ |
24 | #endif |
25 | |
26 | const char *tsc_names[] = |
27 | { |
28 | [0] = "[not set]" , |
29 | [PR_TSC_ENABLE] = "PR_TSC_ENABLE" , |
30 | [PR_TSC_SIGSEGV] = "PR_TSC_SIGSEGV" , |
31 | }; |
32 | |
33 | static uint64_t rdtsc(void) |
34 | { |
35 | uint32_t lo, hi; |
36 | /* We cannot use "=A", since this would use %rax on x86_64 */ |
37 | __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
38 | return (uint64_t)hi << 32 | lo; |
39 | } |
40 | |
41 | static void sigsegv_cb(int sig) |
42 | { |
43 | int tsc_val = 0; |
44 | |
45 | printf("[ SIG_SEGV ]\n" ); |
46 | printf("prctl(PR_GET_TSC, &tsc_val); " ); |
47 | fflush(stdout); |
48 | |
49 | if ( prctl(PR_GET_TSC, &tsc_val) == -1) |
50 | perror("prctl" ); |
51 | |
52 | printf("tsc_val == %s\n" , tsc_names[tsc_val]); |
53 | printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n" ); |
54 | fflush(stdout); |
55 | if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1) |
56 | perror("prctl" ); |
57 | |
58 | printf("rdtsc() == " ); |
59 | } |
60 | |
61 | int main(void) |
62 | { |
63 | int tsc_val = 0; |
64 | |
65 | signal(SIGSEGV, sigsegv_cb); |
66 | |
67 | printf("rdtsc() == %llu\n" , (unsigned long long)rdtsc()); |
68 | printf("prctl(PR_GET_TSC, &tsc_val); " ); |
69 | fflush(stdout); |
70 | |
71 | if ( prctl(PR_GET_TSC, &tsc_val) == -1) |
72 | perror("prctl" ); |
73 | |
74 | printf("tsc_val == %s\n" , tsc_names[tsc_val]); |
75 | printf("rdtsc() == %llu\n" , (unsigned long long)rdtsc()); |
76 | printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n" ); |
77 | fflush(stdout); |
78 | |
79 | if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1) |
80 | perror("prctl" ); |
81 | |
82 | printf("rdtsc() == %llu\n" , (unsigned long long)rdtsc()); |
83 | printf("prctl(PR_SET_TSC, PR_TSC_SIGSEGV)\n" ); |
84 | fflush(stdout); |
85 | |
86 | if ( prctl(PR_SET_TSC, PR_TSC_SIGSEGV) == -1) |
87 | perror("prctl" ); |
88 | |
89 | printf("rdtsc() == " ); |
90 | fflush(stdout); |
91 | printf("%llu\n" , (unsigned long long)rdtsc()); |
92 | fflush(stdout); |
93 | |
94 | exit(EXIT_SUCCESS); |
95 | } |
96 | |
97 | |