~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/dexcr/dexcr.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 
  3 #include <errno.h>
  4 #include <setjmp.h>
  5 #include <signal.h>
  6 #include <sys/prctl.h>
  7 #include <sys/types.h>
  8 #include <sys/wait.h>
  9 
 10 #include "dexcr.h"
 11 #include "reg.h"
 12 #include "utils.h"
 13 
 14 static jmp_buf generic_signal_jump_buf;
 15 
 16 static void generic_signal_handler(int signum, siginfo_t *info, void *context)
 17 {
 18         longjmp(generic_signal_jump_buf, 0);
 19 }
 20 
 21 bool dexcr_exists(void)
 22 {
 23         struct sigaction old;
 24         volatile bool exists;
 25 
 26         old = push_signal_handler(SIGILL, generic_signal_handler);
 27         if (setjmp(generic_signal_jump_buf))
 28                 goto out;
 29 
 30         /*
 31          * If the SPR is not recognised by the hardware it triggers
 32          * a hypervisor emulation interrupt. If the kernel does not
 33          * recognise/try to emulate it, we receive a SIGILL signal.
 34          *
 35          * If we do not receive a signal, assume we have the SPR or the
 36          * kernel is trying to emulate it correctly.
 37          */
 38         exists = false;
 39         mfspr(SPRN_DEXCR_RO);
 40         exists = true;
 41 
 42 out:
 43         pop_signal_handler(SIGILL, old);
 44         return exists;
 45 }
 46 
 47 unsigned int pr_which_to_aspect(unsigned long which)
 48 {
 49         switch (which) {
 50         case PR_PPC_DEXCR_SBHE:
 51                 return DEXCR_PR_SBHE;
 52         case PR_PPC_DEXCR_IBRTPD:
 53                 return DEXCR_PR_IBRTPD;
 54         case PR_PPC_DEXCR_SRAPD:
 55                 return DEXCR_PR_SRAPD;
 56         case PR_PPC_DEXCR_NPHIE:
 57                 return DEXCR_PR_NPHIE;
 58         default:
 59                 FAIL_IF_EXIT_MSG(true, "unknown PR aspect");
 60         }
 61 }
 62 
 63 int pr_get_dexcr(unsigned long which)
 64 {
 65         return prctl(PR_PPC_GET_DEXCR, which, 0UL, 0UL, 0UL);
 66 }
 67 
 68 int pr_set_dexcr(unsigned long which, unsigned long ctrl)
 69 {
 70         return prctl(PR_PPC_SET_DEXCR, which, ctrl, 0UL, 0UL);
 71 }
 72 
 73 bool pr_dexcr_aspect_supported(unsigned long which)
 74 {
 75         if (pr_get_dexcr(which) == -1)
 76                 return errno == ENODEV;
 77 
 78         return true;
 79 }
 80 
 81 bool pr_dexcr_aspect_editable(unsigned long which)
 82 {
 83         return pr_get_dexcr(which) & PR_PPC_DEXCR_CTRL_EDITABLE;
 84 }
 85 
 86 /*
 87  * Just test if a bad hashchk triggers a signal, without checking
 88  * for support or if the NPHIE aspect is enabled.
 89  */
 90 bool hashchk_triggers(void)
 91 {
 92         struct sigaction old;
 93         volatile bool triggers;
 94 
 95         old = push_signal_handler(SIGILL, generic_signal_handler);
 96         if (setjmp(generic_signal_jump_buf))
 97                 goto out;
 98 
 99         triggers = true;
100         do_bad_hashchk();
101         triggers = false;
102 
103 out:
104         pop_signal_handler(SIGILL, old);
105         return triggers;
106 }
107 
108 unsigned int get_dexcr(enum dexcr_source source)
109 {
110         switch (source) {
111         case DEXCR:
112                 return mfspr(SPRN_DEXCR_RO);
113         case HDEXCR:
114                 return mfspr(SPRN_HDEXCR_RO);
115         case EFFECTIVE:
116                 return mfspr(SPRN_DEXCR_RO) | mfspr(SPRN_HDEXCR_RO);
117         default:
118                 FAIL_IF_EXIT_MSG(true, "bad enum dexcr_source");
119         }
120 }
121 
122 void await_child_success(pid_t pid)
123 {
124         int wstatus;
125 
126         FAIL_IF_EXIT_MSG(pid == -1, "fork failed");
127         FAIL_IF_EXIT_MSG(waitpid(pid, &wstatus, 0) == -1, "wait failed");
128         FAIL_IF_EXIT_MSG(!WIFEXITED(wstatus), "child did not exit cleanly");
129         FAIL_IF_EXIT_MSG(WEXITSTATUS(wstatus) != 0, "child exit error");
130 }
131 
132 /*
133  * Perform a hashst instruction. The following components determine the result
134  *
135  * 1. The LR value (any register technically)
136  * 2. The SP value (also any register, but it must be a valid address)
137  * 3. A secret key managed by the kernel
138  *
139  * The result is stored to the address held in SP.
140  */
141 void hashst(unsigned long lr, void *sp)
142 {
143         asm volatile ("addi 31, %0, 0;"         /* set r31 (pretend LR) to lr */
144                       "addi 30, %1, 8;"         /* set r30 (pretend SP) to sp + 8 */
145                       PPC_RAW_HASHST(31, -8, 30)        /* compute hash into stack location */
146                       : : "r" (lr), "r" (sp) : "r31", "r30", "memory");
147 }
148 
149 /*
150  * Perform a hashchk instruction. A hash is computed as per hashst(),
151  * however the result is not stored to memory. Instead the existing
152  * value is read and compared against the computed hash.
153  *
154  * If they match, execution continues.
155  * If they differ, an interrupt triggers.
156  */
157 void hashchk(unsigned long lr, void *sp)
158 {
159         asm volatile ("addi 31, %0, 0;"         /* set r31 (pretend LR) to lr */
160                       "addi 30, %1, 8;"         /* set r30 (pretend SP) to sp + 8 */
161                       PPC_RAW_HASHCHK(31, -8, 30)       /* check hash at stack location */
162                       : : "r" (lr), "r" (sp) : "r31", "r30", "memory");
163 }
164 
165 void do_bad_hashchk(void)
166 {
167         unsigned long hash = 0;
168 
169         hashst(0, &hash);
170         hash += 1;
171         hashchk(0, &hash);
172 }
173 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php