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