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_ppc64) 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_ppc64) 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_ppc64) 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