Home | History | Annotate | Download | only in prctl
      1 // SPDX-License-Identifier: GPL-2.0
      2 /*
      3  * Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
      4  *
      5  * Tests if the control register is updated correctly
      6  * when set with prctl()
      7  *
      8  * Warning: this test will cause a very high load for a few seconds
      9  *
     10  */
     11 
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <unistd.h>
     15 #include <signal.h>
     16 #include <inttypes.h>
     17 #include <wait.h>
     18 
     19 
     20 #include <sys/prctl.h>
     21 #include <linux/prctl.h>
     22 
     23 /* Get/set the process' ability to use the timestamp counter instruction */
     24 #ifndef PR_GET_TSC
     25 #define PR_GET_TSC 25
     26 #define PR_SET_TSC 26
     27 # define PR_TSC_ENABLE		1   /* allow the use of the timestamp counter */
     28 # define PR_TSC_SIGSEGV		2   /* throw a SIGSEGV instead of reading the TSC */
     29 #endif
     30 
     31 /* snippet from wikipedia :-) */
     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 int should_segv = 0;
     42 
     43 static void sigsegv_cb(int sig)
     44 {
     45 	if (!should_segv)
     46 	{
     47 		fprintf(stderr, "FATAL ERROR, rdtsc() failed while enabled\n");
     48 		exit(0);
     49 	}
     50 	if (prctl(PR_SET_TSC, PR_TSC_ENABLE) < 0)
     51 	{
     52 		perror("prctl");
     53 		exit(0);
     54 	}
     55 	should_segv = 0;
     56 
     57 	rdtsc();
     58 }
     59 
     60 static void task(void)
     61 {
     62 	signal(SIGSEGV, sigsegv_cb);
     63 	alarm(10);
     64 	for(;;)
     65 	{
     66 		rdtsc();
     67 		if (should_segv)
     68 		{
     69 			fprintf(stderr, "FATAL ERROR, rdtsc() succeeded while disabled\n");
     70 			exit(0);
     71 		}
     72 		if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV) < 0)
     73 		{
     74 			perror("prctl");
     75 			exit(0);
     76 		}
     77 		should_segv = 1;
     78 	}
     79 }
     80 
     81 
     82 int main(void)
     83 {
     84 	int n_tasks = 100, i;
     85 
     86 	fprintf(stderr, "[No further output means we're allright]\n");
     87 
     88 	for (i=0; i<n_tasks; i++)
     89 		if (fork() == 0)
     90 			task();
     91 
     92 	for (i=0; i<n_tasks; i++)
     93 		wait(NULL);
     94 
     95 	exit(0);
     96 }
     97 
     98