1 #include <stdio.h>
2 #include <stdbool.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <signal.h>
6 #include <setjmp.h>
7 
8 typedef enum exit_codes_ {
9 
10 #if defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le)
11   /* If the insn that got queried for: exists */
12   POWER_INSN_AVAILABLE    = 0,
13   /* If the insn that got queried for: does not exist on this platform */
14   POWER_INSN_UNAVAILABLE  = 1,
15   /* If the insn that got queried for: does not exist in the vocabulary of this program */
16   POWER_INSN_UNRECOGNIZED = 2,
17 
18   /* Note: Please keep USAGE_ERROR last. */
19   USAGE_ERROR
20 #else
21   /* When not on a POWER system: */
22   NOT_POWER_ARCH          = 255,
23 #endif
24 
25 } exit_code;
26 
27 #if defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le)
28 /* Signal Handling support for unsupported instructions. */
29 static jmp_buf unsup_insn_env;
unsup_insn_handler(int signal_number)30 static void unsup_insn_handler(int signal_number)
31 {
32   if (signal_number == SIGILL)
33     longjmp(unsup_insn_env, 1);
34   return;
35 }
36 static struct sigaction unsup_insn_action = {
37   .sa_handler = &unsup_insn_handler,
38 };
39 
40 /* Instruction existence tests. */
dcbzl_available(void)41 static bool dcbzl_available(void)
42 {
43 #define MAX_DCBZL_SZB (128) /* largest known effect of dcbzl */
44   char *test_block = NULL;
45   register char *rb asm ("r14");
46   int err;
47   bool dcbzl_exists = false;
48 
49   err = posix_memalign ((void **)&test_block, MAX_DCBZL_SZB, 4 * MAX_DCBZL_SZB);
50   if (err) {
51     fprintf(stderr, "posix_memalign() failed (err = %d [%s])\n", err, strerror(err));
52     return err;
53   }
54 
55   rb = test_block;
56 
57   if (setjmp(unsup_insn_env) != 0)
58     dcbzl_exists = false;
59   else {
60     sigaction(SIGILL, &unsup_insn_action, NULL);
61     asm volatile ("dcbzl 0, %[RB]" : : [RB] "r" (rb));
62     dcbzl_exists = true;
63   }
64 
65   free(test_block);
66   return dcbzl_exists;
67 }
68 #endif
69 
70 /* main() */
main(int argc,char ** argv)71 int main(int argc, char **argv)
72 {
73   exit_code status;
74 
75 #if defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le)
76   char *insn;
77   if (argc != 2) {
78     fprintf(stderr, "usage: power_insn_available <insn>\n" );
79     exit(USAGE_ERROR);
80   }
81 
82   insn = argv[1];
83   if (strcmp (insn, "dcbzl") == 0)
84     status = ((dcbzl_available ()) ? POWER_INSN_AVAILABLE : POWER_INSN_UNAVAILABLE);
85   else
86     /* power_insn_available has not been taught anything about this insn yet. */
87     status = POWER_INSN_UNRECOGNIZED;
88 #else
89     status = NOT_POWER_ARCH;
90 #endif
91   return status;
92 }
93