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 * Tests if the control register is updated correctly
692dd8dd4SShuah Khan * at context switches
792dd8dd4SShuah Khan *
892dd8dd4SShuah Khan * Warning: this test will cause a very high load for a few seconds
992dd8dd4SShuah Khan *
1092dd8dd4SShuah Khan */
1192dd8dd4SShuah Khan
1292dd8dd4SShuah Khan #include <stdio.h>
1392dd8dd4SShuah Khan #include <stdlib.h>
1492dd8dd4SShuah Khan #include <unistd.h>
1592dd8dd4SShuah Khan #include <signal.h>
1692dd8dd4SShuah Khan #include <inttypes.h>
1792dd8dd4SShuah Khan #include <wait.h>
1892dd8dd4SShuah Khan
1992dd8dd4SShuah Khan
2092dd8dd4SShuah Khan #include <sys/prctl.h>
2192dd8dd4SShuah Khan #include <linux/prctl.h>
2292dd8dd4SShuah Khan
2392dd8dd4SShuah Khan /* Get/set the process' ability to use the timestamp counter instruction */
2492dd8dd4SShuah Khan #ifndef PR_GET_TSC
2592dd8dd4SShuah Khan #define PR_GET_TSC 25
2692dd8dd4SShuah Khan #define PR_SET_TSC 26
2792dd8dd4SShuah Khan # define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
2892dd8dd4SShuah Khan # define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
2992dd8dd4SShuah Khan #endif
3092dd8dd4SShuah Khan
rdtsc(void)3192dd8dd4SShuah Khan static uint64_t rdtsc(void)
3292dd8dd4SShuah Khan {
3392dd8dd4SShuah Khan uint32_t lo, hi;
3492dd8dd4SShuah Khan /* We cannot use "=A", since this would use %rax on x86_64 */
3592dd8dd4SShuah Khan __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
3692dd8dd4SShuah Khan return (uint64_t)hi << 32 | lo;
3792dd8dd4SShuah Khan }
3892dd8dd4SShuah Khan
sigsegv_expect(int sig)3992dd8dd4SShuah Khan static void sigsegv_expect(int sig)
4092dd8dd4SShuah Khan {
4192dd8dd4SShuah Khan /* */
4292dd8dd4SShuah Khan }
4392dd8dd4SShuah Khan
segvtask(void)4492dd8dd4SShuah Khan static void segvtask(void)
4592dd8dd4SShuah Khan {
4692dd8dd4SShuah Khan if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV) < 0)
4792dd8dd4SShuah Khan {
4892dd8dd4SShuah Khan perror("prctl");
4992dd8dd4SShuah Khan exit(0);
5092dd8dd4SShuah Khan }
5192dd8dd4SShuah Khan signal(SIGSEGV, sigsegv_expect);
5292dd8dd4SShuah Khan alarm(10);
5392dd8dd4SShuah Khan rdtsc();
5492dd8dd4SShuah Khan fprintf(stderr, "FATAL ERROR, rdtsc() succeeded while disabled\n");
5592dd8dd4SShuah Khan exit(0);
5692dd8dd4SShuah Khan }
5792dd8dd4SShuah Khan
5892dd8dd4SShuah Khan
sigsegv_fail(int sig)5992dd8dd4SShuah Khan static void sigsegv_fail(int sig)
6092dd8dd4SShuah Khan {
6192dd8dd4SShuah Khan fprintf(stderr, "FATAL ERROR, rdtsc() failed while enabled\n");
6292dd8dd4SShuah Khan exit(0);
6392dd8dd4SShuah Khan }
6492dd8dd4SShuah Khan
rdtsctask(void)6592dd8dd4SShuah Khan static void rdtsctask(void)
6692dd8dd4SShuah Khan {
6792dd8dd4SShuah Khan if (prctl(PR_SET_TSC, PR_TSC_ENABLE) < 0)
6892dd8dd4SShuah Khan {
6992dd8dd4SShuah Khan perror("prctl");
7092dd8dd4SShuah Khan exit(0);
7192dd8dd4SShuah Khan }
7292dd8dd4SShuah Khan signal(SIGSEGV, sigsegv_fail);
7392dd8dd4SShuah Khan alarm(10);
7492dd8dd4SShuah Khan for(;;) rdtsc();
7592dd8dd4SShuah Khan }
7692dd8dd4SShuah Khan
7792dd8dd4SShuah Khan
main(void)7892dd8dd4SShuah Khan int main(void)
7992dd8dd4SShuah Khan {
8092dd8dd4SShuah Khan int n_tasks = 100, i;
8192dd8dd4SShuah Khan
8292dd8dd4SShuah Khan fprintf(stderr, "[No further output means we're all right]\n");
8392dd8dd4SShuah Khan
8492dd8dd4SShuah Khan for (i=0; i<n_tasks; i++)
8592dd8dd4SShuah Khan if (fork() == 0)
8692dd8dd4SShuah Khan {
8792dd8dd4SShuah Khan if (i & 1)
8892dd8dd4SShuah Khan segvtask();
8992dd8dd4SShuah Khan else
9092dd8dd4SShuah Khan rdtsctask();
9192dd8dd4SShuah Khan }
9292dd8dd4SShuah Khan
9392dd8dd4SShuah Khan for (i=0; i<n_tasks; i++)
9492dd8dd4SShuah Khan wait(NULL);
9592dd8dd4SShuah Khan
9692dd8dd4SShuah Khan exit(0);
9792dd8dd4SShuah Khan }
9892dd8dd4SShuah Khan
99