18eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/* x86 variant of the amd64-solaris/context_fpu.c test. */
28eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
38eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <assert.h>
48eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <signal.h>
58eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <stdio.h>
68eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <stdlib.h>
78eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <unistd.h>
88eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <sys/syscall.h>
98eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <sys/ucontext.h>
108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
118eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic siginfo_t si;
128eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic ucontext_t uc;
138eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic float inhandler[8];
148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
158eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
178eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   int i;
188eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
198eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   si = *sip;
208eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   uc = *ucp;
218eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
228eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Reset the FP stack so it's possible to push other values onto it.  (It
238eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      is fully filled in main() before triggering the signal handler).  Note
248eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      that VEX also clears all FP values when the finit instruction is
258eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      executed.  This provides another level of validation that the restore
268eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      code is correct. */
278eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   __asm__ __volatile__(
288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "finit\n");
298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Convert 80b values in mcontext to 32b values in the inhandler array. */
318eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   for (i = 0; i < 8; i++) {
328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      __asm__ __volatile__(
338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         "fldt   %[in]\n"
348eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         "fstps  %[out]\n"
358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         : [out] "=m" (inhandler[i])
368eb8bab992e3998c33770b0cdb16059a8b918a06sewardj         : [in] "m" (*((char*)&ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state
378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj                       + 28 + i * 10)));
388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
418eb8bab992e3998c33770b0cdb16059a8b918a06sewardjint main(void)
428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   struct sigaction sa;
448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   pid_t pid;
458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   float out[8];
468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   float x0;
478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
488eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Uninitialised, but we know px[0] is 0x0. */
498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   float *px = malloc(sizeof(*px));
508eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   x0 = px[0];
518eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
528eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   sa.sa_handler = sighandler;
538eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   sa.sa_flags = SA_SIGINFO;
548eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (sigfillset(&sa.sa_mask)) {
558eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      perror("sigfillset");
568eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return 1;
578eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
588eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (sigaction(SIGUSR1, &sa, NULL)) {
598eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      perror("sigaction");
608eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return 1;
618eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
628eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
638eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   pid = getpid();
648eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
658eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   __asm__ __volatile__(
668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Set values in the FP stack. */
678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "flds   %[x0]\n"
688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fld1\n"
698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "flds   %[x0]\n"
708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fld1\n"
718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "flds   %[x0]\n"
728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fld1\n"
738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "flds   %[x0]\n"
748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fld1\n"
758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
768eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Prepare syscall parameters. */
778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "pushl  %[sig]\n"
788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "pushl  %[pid]\n"
798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "pushl  $0xdeadbeef\n"
808eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movl   %[scall], %%eax\n"
818eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
828eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Trigger the signal handler. */
838eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "int    $0x91\n"
848eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "addl   $12, %%esp\n"
858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x00 + %[out]\n"
868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x04 + %[out]\n"
878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x08 + %[out]\n"
888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x0c + %[out]\n"
898eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x10 + %[out]\n"
908eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x14 + %[out]\n"
918eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x18 + %[out]\n"
928eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "fstps  0x1c + %[out]\n"
938eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      : [out] "=m" (out[0])
948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      : [scall] "i" (SYS_kill), [pid] "a" (pid), [sig] "i" (SIGUSR1),
958eb8bab992e3998c33770b0cdb16059a8b918a06sewardj        [x0] "m" (x0)
968eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      : "edx", "cc", "memory");
978eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
988eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("Values in the signal handler:\n");
998eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
1008eb8bab992e3998c33770b0cdb16059a8b918a06sewardj          inhandler[0], inhandler[2], inhandler[4], inhandler[6]);
1018eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Check that inhandler[1], inhandler[3], inhandler[5] and inhandler[7]
1028eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      contain uninitialised values (origin is px[0]). */
1038eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (inhandler[1] || inhandler[3] || inhandler[5] || inhandler[7])
1048eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      assert(0);
1058eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
1068eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("Values after the return from the signal handler:\n");
1078eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
1088eb8bab992e3998c33770b0cdb16059a8b918a06sewardj          out[0], out[2], out[4], out[6]);
1098eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Check that out[1], out[3], out[5] and out[7] contain uninitialised
1108eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      values (origin is px[0]). */
1118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (out[1] || out[3] || out[5] || out[7])
1128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      assert(0);
1138eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
1148eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return 0;
1158eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
1168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
117