1/* x86 variant of the amd64-solaris/context_fpu.c test. */
2
3#include <assert.h>
4#include <signal.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <sys/syscall.h>
9#include <sys/ucontext.h>
10
11static siginfo_t si;
12static ucontext_t uc;
13static float inhandler[8];
14
15static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
16{
17   int i;
18
19   si = *sip;
20   uc = *ucp;
21
22   /* Reset the FP stack so it's possible to push other values onto it.  (It
23      is fully filled in main() before triggering the signal handler).  Note
24      that VEX also clears all FP values when the finit instruction is
25      executed.  This provides another level of validation that the restore
26      code is correct. */
27   __asm__ __volatile__(
28      "finit\n");
29
30   /* Convert 80b values in mcontext to 32b values in the inhandler array. */
31   for (i = 0; i < 8; i++) {
32      __asm__ __volatile__(
33         "fldt   %[in]\n"
34         "fstps  %[out]\n"
35         : [out] "=m" (inhandler[i])
36         : [in] "m" (*((char*)&ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state
37                       + 28 + i * 10)));
38   }
39}
40
41int main(void)
42{
43   struct sigaction sa;
44   pid_t pid;
45   float out[8];
46   float x0;
47
48   /* Uninitialised, but we know px[0] is 0x0. */
49   float *px = malloc(sizeof(*px));
50   x0 = px[0];
51
52   sa.sa_handler = sighandler;
53   sa.sa_flags = SA_SIGINFO;
54   if (sigfillset(&sa.sa_mask)) {
55      perror("sigfillset");
56      return 1;
57   }
58   if (sigaction(SIGUSR1, &sa, NULL)) {
59      perror("sigaction");
60      return 1;
61   }
62
63   pid = getpid();
64
65   __asm__ __volatile__(
66      /* Set values in the FP stack. */
67      "flds   %[x0]\n"
68      "fld1\n"
69      "flds   %[x0]\n"
70      "fld1\n"
71      "flds   %[x0]\n"
72      "fld1\n"
73      "flds   %[x0]\n"
74      "fld1\n"
75
76      /* Prepare syscall parameters. */
77      "pushl  %[sig]\n"
78      "pushl  %[pid]\n"
79      "pushl  $0xdeadbeef\n"
80      "movl   %[scall], %%eax\n"
81
82      /* Trigger the signal handler. */
83      "int    $0x91\n"
84      "addl   $12, %%esp\n"
85      "fstps  0x00 + %[out]\n"
86      "fstps  0x04 + %[out]\n"
87      "fstps  0x08 + %[out]\n"
88      "fstps  0x0c + %[out]\n"
89      "fstps  0x10 + %[out]\n"
90      "fstps  0x14 + %[out]\n"
91      "fstps  0x18 + %[out]\n"
92      "fstps  0x1c + %[out]\n"
93      : [out] "=m" (out[0])
94      : [scall] "i" (SYS_kill), [pid] "a" (pid), [sig] "i" (SIGUSR1),
95        [x0] "m" (x0)
96      : "edx", "cc", "memory");
97
98   printf("Values in the signal handler:\n");
99   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
100          inhandler[0], inhandler[2], inhandler[4], inhandler[6]);
101   /* Check that inhandler[1], inhandler[3], inhandler[5] and inhandler[7]
102      contain uninitialised values (origin is px[0]). */
103   if (inhandler[1] || inhandler[3] || inhandler[5] || inhandler[7])
104      assert(0);
105
106   printf("Values after the return from the signal handler:\n");
107   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
108          out[0], out[2], out[4], out[6]);
109   /* Check that out[1], out[3], out[5] and out[7] contain uninitialised
110      values (origin is px[0]). */
111   if (out[1] || out[3] || out[5] || out[7])
112      assert(0);
113
114   return 0;
115}
116
117