root/tools/testing/selftests/powerpc/mm/wild_bctr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. save_regs
  2. segv_handler
  3. usr2_handler
  4. ok
  5. poison_regs
  6. check_regs
  7. dump_regs
  8. test_wild_bctr
  9. main

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright 2018, Michael Ellerman, IBM Corp.
   4  *
   5  * Test that an out-of-bounds branch to counter behaves as expected.
   6  */
   7 
   8 #include <setjmp.h>
   9 #include <stdio.h>
  10 #include <stdlib.h>
  11 #include <string.h>
  12 #include <sys/mman.h>
  13 #include <sys/types.h>
  14 #include <sys/wait.h>
  15 #include <ucontext.h>
  16 #include <unistd.h>
  17 
  18 #include "utils.h"
  19 
  20 
  21 #define BAD_NIP 0x788c545a18000000ull
  22 
  23 static struct pt_regs signal_regs;
  24 static jmp_buf setjmp_env;
  25 
  26 static void save_regs(ucontext_t *ctxt)
  27 {
  28         struct pt_regs *regs = ctxt->uc_mcontext.regs;
  29 
  30         memcpy(&signal_regs, regs, sizeof(signal_regs));
  31 }
  32 
  33 static void segv_handler(int signum, siginfo_t *info, void *ctxt_v)
  34 {
  35         save_regs(ctxt_v);
  36         longjmp(setjmp_env, 1);
  37 }
  38 
  39 static void usr2_handler(int signum, siginfo_t *info, void *ctxt_v)
  40 {
  41         save_regs(ctxt_v);
  42 }
  43 
  44 static int ok(void)
  45 {
  46         printf("Everything is OK in here.\n");
  47         return 0;
  48 }
  49 
  50 #define REG_POISON      0x5a5a
  51 #define POISONED_REG(n) ((((unsigned long)REG_POISON) << 48) | ((n) << 32) | \
  52                          (((unsigned long)REG_POISON) << 16) | (n))
  53 
  54 static inline void poison_regs(void)
  55 {
  56         #define POISON_REG(n)   \
  57           "lis  " __stringify(n) "," __stringify(REG_POISON) ";" \
  58           "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";" \
  59           "sldi " __stringify(n) "," __stringify(n) ", 32 ;" \
  60           "oris " __stringify(n) "," __stringify(n) "," __stringify(REG_POISON) ";" \
  61           "addi " __stringify(n) "," __stringify(n) "," __stringify(n) ";"
  62 
  63         asm (POISON_REG(15)
  64              POISON_REG(16)
  65              POISON_REG(17)
  66              POISON_REG(18)
  67              POISON_REG(19)
  68              POISON_REG(20)
  69              POISON_REG(21)
  70              POISON_REG(22)
  71              POISON_REG(23)
  72              POISON_REG(24)
  73              POISON_REG(25)
  74              POISON_REG(26)
  75              POISON_REG(27)
  76              POISON_REG(28)
  77              POISON_REG(29)
  78              : // inputs
  79              : // outputs
  80              : "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
  81                "26", "27", "28", "29"
  82         );
  83         #undef POISON_REG
  84 }
  85 
  86 static int check_regs(void)
  87 {
  88         unsigned long i;
  89 
  90         for (i = 15; i <= 29; i++)
  91                 FAIL_IF(signal_regs.gpr[i] != POISONED_REG(i));
  92 
  93         printf("Regs OK\n");
  94         return 0;
  95 }
  96 
  97 static void dump_regs(void)
  98 {
  99         for (int i = 0; i < 32; i += 4) {
 100                 printf("r%02d 0x%016lx  r%02d 0x%016lx  " \
 101                        "r%02d 0x%016lx  r%02d 0x%016lx\n",
 102                        i, signal_regs.gpr[i],
 103                        i+1, signal_regs.gpr[i+1],
 104                        i+2, signal_regs.gpr[i+2],
 105                        i+3, signal_regs.gpr[i+3]);
 106         }
 107 }
 108 
 109 #ifdef _CALL_AIXDESC
 110 struct opd {
 111         unsigned long ip;
 112         unsigned long toc;
 113         unsigned long env;
 114 };
 115 static struct opd bad_opd = {
 116         .ip = BAD_NIP,
 117 };
 118 #define BAD_FUNC (&bad_opd)
 119 #else
 120 #define BAD_FUNC BAD_NIP
 121 #endif
 122 
 123 int test_wild_bctr(void)
 124 {
 125         int (*func_ptr)(void);
 126         struct sigaction segv = {
 127                 .sa_sigaction = segv_handler,
 128                 .sa_flags = SA_SIGINFO
 129         };
 130         struct sigaction usr2 = {
 131                 .sa_sigaction = usr2_handler,
 132                 .sa_flags = SA_SIGINFO
 133         };
 134 
 135         FAIL_IF(sigaction(SIGSEGV, &segv, NULL));
 136         FAIL_IF(sigaction(SIGUSR2, &usr2, NULL));
 137 
 138         bzero(&signal_regs, sizeof(signal_regs));
 139 
 140         if (setjmp(setjmp_env) == 0) {
 141                 func_ptr = ok;
 142                 func_ptr();
 143 
 144                 kill(getpid(), SIGUSR2);
 145                 printf("Regs before:\n");
 146                 dump_regs();
 147                 bzero(&signal_regs, sizeof(signal_regs));
 148 
 149                 poison_regs();
 150 
 151                 func_ptr = (int (*)(void))BAD_FUNC;
 152                 func_ptr();
 153 
 154                 FAIL_IF(1); /* we didn't segv? */
 155         }
 156 
 157         FAIL_IF(signal_regs.nip != BAD_NIP);
 158 
 159         printf("All good - took SEGV as expected branching to 0x%llx\n", BAD_NIP);
 160 
 161         dump_regs();
 162         FAIL_IF(check_regs());
 163 
 164         return 0;
 165 }
 166 
 167 int main(void)
 168 {
 169         return test_harness(test_wild_bctr, "wild_bctr");
 170 }

/* [<][>][^][v][top][bottom][index][help] */