xref: /openbmc/linux/tools/testing/selftests/prctl/disable-tsc-test.c (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
292dd8dd4SShuah Khan /*
392dd8dd4SShuah Khan  * Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
492dd8dd4SShuah Khan  *
592dd8dd4SShuah Khan  * Basic test to test behaviour of PR_GET_TSC and PR_SET_TSC
692dd8dd4SShuah Khan  */
792dd8dd4SShuah Khan 
892dd8dd4SShuah Khan #include <stdio.h>
992dd8dd4SShuah Khan #include <stdlib.h>
1092dd8dd4SShuah Khan #include <unistd.h>
1192dd8dd4SShuah Khan #include <signal.h>
1292dd8dd4SShuah Khan #include <inttypes.h>
1392dd8dd4SShuah Khan 
1492dd8dd4SShuah Khan 
1592dd8dd4SShuah Khan #include <sys/prctl.h>
1692dd8dd4SShuah Khan #include <linux/prctl.h>
1792dd8dd4SShuah Khan 
1892dd8dd4SShuah Khan /* Get/set the process' ability to use the timestamp counter instruction */
1992dd8dd4SShuah Khan #ifndef PR_GET_TSC
2092dd8dd4SShuah Khan #define PR_GET_TSC 25
2192dd8dd4SShuah Khan #define PR_SET_TSC 26
2292dd8dd4SShuah Khan # define PR_TSC_ENABLE		1   /* allow the use of the timestamp counter */
2392dd8dd4SShuah Khan # define PR_TSC_SIGSEGV		2   /* throw a SIGSEGV instead of reading the TSC */
2492dd8dd4SShuah Khan #endif
2592dd8dd4SShuah Khan 
2692dd8dd4SShuah Khan const char *tsc_names[] =
2792dd8dd4SShuah Khan {
2892dd8dd4SShuah Khan 	[0] = "[not set]",
2992dd8dd4SShuah Khan 	[PR_TSC_ENABLE] = "PR_TSC_ENABLE",
3092dd8dd4SShuah Khan 	[PR_TSC_SIGSEGV] = "PR_TSC_SIGSEGV",
3192dd8dd4SShuah Khan };
3292dd8dd4SShuah Khan 
rdtsc(void)3392dd8dd4SShuah Khan static uint64_t rdtsc(void)
3492dd8dd4SShuah Khan {
3592dd8dd4SShuah Khan uint32_t lo, hi;
3692dd8dd4SShuah Khan /* We cannot use "=A", since this would use %rax on x86_64 */
3792dd8dd4SShuah Khan __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
3892dd8dd4SShuah Khan return (uint64_t)hi << 32 | lo;
3992dd8dd4SShuah Khan }
4092dd8dd4SShuah Khan 
sigsegv_cb(int sig)4192dd8dd4SShuah Khan static void sigsegv_cb(int sig)
4292dd8dd4SShuah Khan {
4392dd8dd4SShuah Khan 	int tsc_val = 0;
4492dd8dd4SShuah Khan 
4592dd8dd4SShuah Khan 	printf("[ SIG_SEGV ]\n");
4692dd8dd4SShuah Khan 	printf("prctl(PR_GET_TSC, &tsc_val); ");
4792dd8dd4SShuah Khan 	fflush(stdout);
4892dd8dd4SShuah Khan 
4992dd8dd4SShuah Khan 	if ( prctl(PR_GET_TSC, &tsc_val) == -1)
5092dd8dd4SShuah Khan 		perror("prctl");
5192dd8dd4SShuah Khan 
5292dd8dd4SShuah Khan 	printf("tsc_val == %s\n", tsc_names[tsc_val]);
5392dd8dd4SShuah Khan 	printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n");
5492dd8dd4SShuah Khan 	fflush(stdout);
5592dd8dd4SShuah Khan 	if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1)
5692dd8dd4SShuah Khan 		perror("prctl");
5792dd8dd4SShuah Khan 
5892dd8dd4SShuah Khan 	printf("rdtsc() == ");
5992dd8dd4SShuah Khan }
6092dd8dd4SShuah Khan 
main(void)6192dd8dd4SShuah Khan int main(void)
6292dd8dd4SShuah Khan {
6392dd8dd4SShuah Khan 	int tsc_val = 0;
6492dd8dd4SShuah Khan 
6592dd8dd4SShuah Khan 	signal(SIGSEGV, sigsegv_cb);
6692dd8dd4SShuah Khan 
6792dd8dd4SShuah Khan 	printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
6892dd8dd4SShuah Khan 	printf("prctl(PR_GET_TSC, &tsc_val); ");
6992dd8dd4SShuah Khan 	fflush(stdout);
7092dd8dd4SShuah Khan 
7192dd8dd4SShuah Khan 	if ( prctl(PR_GET_TSC, &tsc_val) == -1)
7292dd8dd4SShuah Khan 		perror("prctl");
7392dd8dd4SShuah Khan 
7492dd8dd4SShuah Khan 	printf("tsc_val == %s\n", tsc_names[tsc_val]);
7592dd8dd4SShuah Khan 	printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
7692dd8dd4SShuah Khan 	printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n");
7792dd8dd4SShuah Khan 	fflush(stdout);
7892dd8dd4SShuah Khan 
7992dd8dd4SShuah Khan 	if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1)
8092dd8dd4SShuah Khan 		perror("prctl");
8192dd8dd4SShuah Khan 
8292dd8dd4SShuah Khan 	printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
8392dd8dd4SShuah Khan 	printf("prctl(PR_SET_TSC, PR_TSC_SIGSEGV)\n");
8492dd8dd4SShuah Khan 	fflush(stdout);
8592dd8dd4SShuah Khan 
8692dd8dd4SShuah Khan 	if ( prctl(PR_SET_TSC, PR_TSC_SIGSEGV) == -1)
8792dd8dd4SShuah Khan 		perror("prctl");
8892dd8dd4SShuah Khan 
8992dd8dd4SShuah Khan 	printf("rdtsc() == ");
9092dd8dd4SShuah Khan 	fflush(stdout);
9192dd8dd4SShuah Khan 	printf("%llu\n", (unsigned long long)rdtsc());
9292dd8dd4SShuah Khan 	fflush(stdout);
9392dd8dd4SShuah Khan 
9492dd8dd4SShuah Khan 	exit(EXIT_SUCCESS);
9592dd8dd4SShuah Khan }
9692dd8dd4SShuah Khan 
97