linux/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2016, Cyril Bur, IBM Corp.
   4 *
   5 * Test the kernel's signal frame code.
   6 *
   7 * The kernel sets up two sets of ucontexts if the signal was to be
   8 * delivered while the thread was in a transaction (referred too as
   9 * first and second contexts).
  10 * Expected behaviour is that the checkpointed state is in the user
  11 * context passed to the signal handler (first context). The speculated
  12 * state can be accessed with the uc_link pointer (second context).
  13 *
  14 * The rationale for this is that if TM unaware code (which linked
  15 * against TM libs) installs a signal handler it will not know of the
  16 * speculative nature of the 'live' registers and may infer the wrong
  17 * thing.
  18 */
  19
  20#include <stdlib.h>
  21#include <stdio.h>
  22#include <signal.h>
  23#include <unistd.h>
  24
  25#include <altivec.h>
  26
  27#include "utils.h"
  28#include "tm.h"
  29
  30#define MAX_ATTEMPT 500000
  31
  32#define NV_FPU_REGS 18 /* Number of non-volatile FP registers */
  33#define FPR14 14 /* First non-volatile FP register to check in f14-31 subset */
  34
  35long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
  36
  37/* Test only non-volatile registers, i.e. 18 fpr registers from f14 to f31 */
  38static double fps[] = {
  39        /* First context will be set with these values, i.e. non-speculative */
  40         1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  41        /* Second context will be set with these values, i.e. speculative */
  42        -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
  43};
  44
  45static sig_atomic_t fail, broken;
  46
  47static void signal_usr1(int signum, siginfo_t *info, void *uc)
  48{
  49        int i;
  50        ucontext_t *ucp = uc;
  51        ucontext_t *tm_ucp = ucp->uc_link;
  52
  53        for (i = 0; i < NV_FPU_REGS; i++) {
  54                /* Check first context. Print all mismatches. */
  55                fail = (ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[i]);
  56                if (fail) {
  57                        broken = 1;
  58                        printf("FPR%d (1st context) == %g instead of %g (expected)\n",
  59                                FPR14 + i, ucp->uc_mcontext.fp_regs[FPR14 + i], fps[i]);
  60                }
  61        }
  62
  63        for (i = 0; i < NV_FPU_REGS; i++) {
  64                /* Check second context. Print all mismatches. */
  65                fail = (tm_ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[NV_FPU_REGS + i]);
  66                if (fail) {
  67                        broken = 1;
  68                        printf("FPR%d (2nd context) == %g instead of %g (expected)\n",
  69                                FPR14 + i, tm_ucp->uc_mcontext.fp_regs[FPR14 + i], fps[NV_FPU_REGS + i]);
  70                }
  71        }
  72}
  73
  74static int tm_signal_context_chk_fpu()
  75{
  76        struct sigaction act;
  77        int i;
  78        long rc;
  79        pid_t pid = getpid();
  80
  81        SKIP_IF(!have_htm());
  82
  83        act.sa_sigaction = signal_usr1;
  84        sigemptyset(&act.sa_mask);
  85        act.sa_flags = SA_SIGINFO;
  86        if (sigaction(SIGUSR1, &act, NULL) < 0) {
  87                perror("sigaction sigusr1");
  88                exit(1);
  89        }
  90
  91        i = 0;
  92        while (i < MAX_ATTEMPT && !broken) {
  93                /*
  94                 * tm_signal_self_context_load will set both first and second
  95                 * contexts accordingly to the values passed through non-NULL
  96                 * array pointers to it, in that case 'fps', and invoke the
  97                 * signal handler installed for SIGUSR1.
  98                 */
  99                rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
 100                FAIL_IF(rc != pid);
 101                i++;
 102        }
 103
 104        return (broken);
 105}
 106
 107int main(void)
 108{
 109        return test_harness(tm_signal_context_chk_fpu, "tm_signal_context_chk_fpu");
 110}
 111