power_insn_available.c revision 436e89c602e787e7a27dd6624b09beed41a0da8a
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 8typedef 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. */ 29static jmp_buf unsup_insn_env; 30static void unsup_insn_handler(int signal_number) 31{ 32 if (signal_number == SIGILL) 33 longjmp(unsup_insn_env, 1); 34 return; 35} 36static struct sigaction unsup_insn_action = (struct sigaction) { 37 .sa_handler = &unsup_insn_handler, 38}; 39 40/* Instruction existence tests. */ 41static 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() */ 71int 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