Home | History | Annotate | Download | only in tests
      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;
     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 = (struct sigaction) {
     37   .sa_handler = &unsup_insn_handler,
     38 };
     39 
     40 /* Instruction existence tests. */
     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() */
     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