clang-format: Enhance list of FOR_EACH macros
[official-gcc.git] / libmpx / mpxrt / mpxrt.c
blobc29c5d9a50100f1518d153dcc627e03cb77a3cfb
1 /* mpxrt.c -*-C++-*-
3 *************************************************************************
5 * @copyright
6 * Copyright (C) 2014, Intel Corporation
7 * All rights reserved.
9 * @copyright
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 * * Neither the name of Intel Corporation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * @copyright
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
32 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
33 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
35 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
38 **************************************************************************/
40 #define __STDC_FORMAT_MACROS
41 #include "config.h"
42 #include <inttypes.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdint.h>
46 #include <stdbool.h>
47 #include <signal.h>
48 #include <assert.h>
49 #include <stdlib.h>
50 #include <sys/mman.h>
51 #include <sys/prctl.h>
52 #include <cpuid.h>
53 #include "mpxrt-utils.h"
55 #ifdef __i386__
57 /* i386 directory size is 4MB */
58 #define NUM_L1_BITS 20
60 #define REG_IP_IDX REG_EIP
61 #define REX_PREFIX
63 #define XSAVE_OFFSET_IN_FPMEM sizeof (struct _libc_fpstate)
65 #else /* __i386__ */
67 /* x86_64 directory size is 2GB */
68 #define NUM_L1_BITS 28
70 #define REG_IP_IDX REG_RIP
71 #define REX_PREFIX "0x48, "
73 #define XSAVE_OFFSET_IN_FPMEM 0
75 #endif /* !__i386__ */
77 #define MPX_ENABLE_BIT_NO 0
78 #define BNDPRESERVE_BIT_NO 1
80 const size_t MPX_L1_SIZE = (1UL << NUM_L1_BITS) * sizeof (void *);
82 struct xsave_hdr_struct
84 uint64_t xstate_bv;
85 uint64_t reserved1[2];
86 uint64_t reserved2[5];
87 } __attribute__ ((packed));
89 struct bndregs_struct
91 uint64_t bndregs[8];
92 } __attribute__ ((packed));
94 struct bndcsr_struct {
95 uint64_t cfg_reg_u;
96 uint64_t status_reg;
97 } __attribute__((packed));
99 struct xsave_struct
101 uint8_t fpu_sse[512];
102 struct xsave_hdr_struct xsave_hdr;
103 uint8_t ymm[256];
104 uint8_t lwp[128];
105 struct bndregs_struct bndregs;
106 struct bndcsr_struct bndcsr;
107 } __attribute__ ((packed));
109 /* Following vars are initialized at process startup only
110 and thus are considered to be thread safe. */
111 static void *l1base = NULL;
112 static int bndpreserve;
113 static int enable = 1;
115 /* Var holding number of occured BRs. It is modified from
116 signal handler only and thus it should be thread safe. */
117 static uint64_t num_bnd_chk = 0;
119 static inline void
120 xrstor_state (struct xsave_struct *fx, uint64_t mask)
122 uint32_t lmask = mask;
123 uint32_t hmask = mask >> 32;
125 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
126 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
127 : "memory");
130 static inline void
131 xsave_state (struct xsave_struct *fx, uint64_t mask)
133 uint32_t lmask = mask;
134 uint32_t hmask = mask >> 32;
136 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
137 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
138 : "memory");
141 static inline uint64_t
142 xgetbv (uint32_t index)
144 uint32_t eax, edx;
146 asm volatile (".byte 0x0f,0x01,0xd0" /* xgetbv */
147 : "=a" (eax), "=d" (edx)
148 : "c" (index));
149 return eax + ((uint64_t)edx << 32);
152 static uint64_t
153 read_mpx_status_sig (ucontext_t *uctxt)
155 uint8_t *regs = (uint8_t *)uctxt->uc_mcontext.fpregs + XSAVE_OFFSET_IN_FPMEM;
156 struct xsave_struct *xsave_buf = (struct xsave_struct *)regs;
157 return xsave_buf->bndcsr.status_reg;
160 static uint8_t *
161 get_next_inst_ip (uint8_t *addr)
163 uint8_t *ip = addr;
164 uint8_t sib;
166 /* Determine the prefix. */
167 switch (*ip)
169 case 0xf2:
170 case 0xf3:
171 case 0x66:
172 ip++;
173 break;
176 /* Look for rex prefix. */
177 if ((*ip & 0x40) == 0x40)
178 ip++;
180 /* Make sure we have a MPX instruction. */
181 if (*ip++ != 0x0f)
182 return addr;
184 /* Skip the op code byte. */
185 ip++;
187 /* Get the moderm byte. */
188 uint8_t modrm = *ip++;
190 /* Break it down into parts. */
191 uint8_t rm = modrm & 7;
192 uint8_t mod = (modrm >> 6);
194 /* Init the parts of the address mode. */
195 uint8_t base = 8;
197 /* Is it a mem mode? */
198 if (mod != 3)
200 /* Look for scaled indexed addressing. */
201 if (rm == 4)
203 /* SIB addressing. */
204 sib = *ip++;
205 base = sib & 7;
206 switch (mod)
208 case 0:
209 if (base == 5)
210 ip += 4;
211 break;
213 case 1:
214 ip++;
215 break;
217 case 2:
218 ip += 4;
219 break;
222 else
224 /* MODRM addressing. */
225 switch (mod)
227 case 0:
228 if (rm == 5)
229 /* DISP32 addressing, no base. */
230 ip += 4;
231 break;
233 case 1:
234 ip++;
235 break;
237 case 2:
238 ip += 4;
239 break;
243 return ip;
246 static void
247 handler (int sig __attribute__ ((unused)),
248 siginfo_t *info __attribute__ ((unused)),
249 void *vucontext,
250 struct xsave_struct *buf __attribute__ ((unused)))
252 ucontext_t* uctxt;
253 greg_t trapno;
254 greg_t ip;
256 uctxt = vucontext;
257 trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
258 ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
260 if (trapno == 5)
262 uint64_t status = read_mpx_status_sig (uctxt);
263 uint64_t br_reason = status & 0x3;
265 __mpxrt_write (VERB_BR, "Saw a #BR! status ");
266 __mpxrt_write_uint (VERB_BR, status, 10);
267 __mpxrt_write (VERB_BR, " at 0x");
268 __mpxrt_write_uint (VERB_BR, ip, 16);
269 __mpxrt_write (VERB_BR, "\n");
271 switch (br_reason)
273 case 1: /* traditional BR */
274 num_bnd_chk++;
275 uctxt->uc_mcontext.gregs[REG_IP_IDX] =
276 (greg_t)get_next_inst_ip ((uint8_t *)ip);
277 if (__mpxrt_mode () == MPX_RT_STOP)
278 exit (255);
279 return;
281 default:
282 __mpxrt_write (VERB_BR, "Unexpected status with bound exception: ");
283 __mpxrt_write_uint (VERB_BR, status, 10);
284 __mpxrt_write (VERB_BR, "\n");
285 break;
288 else if (trapno == 14)
290 __mpxrt_write (VERB_ERROR, "In signal handler, trapno = ");
291 __mpxrt_write_uint (VERB_ERROR, trapno, 10);
292 __mpxrt_write (VERB_ERROR, ", ip = 0x");
293 __mpxrt_write_uint (VERB_ERROR, ip, 16);
294 __mpxrt_write (VERB_BR, "\n");
295 exit (255);
297 else
299 __mpxrt_write (VERB_ERROR, "Unexpected trap ");
300 __mpxrt_write_uint (VERB_ERROR, trapno, 10);
301 __mpxrt_write (VERB_ERROR, "! at 0x");
302 __mpxrt_write_uint (VERB_ERROR, ip, 16);
303 __mpxrt_write (VERB_BR, "\n");
304 exit (255);
308 /* Using wrapper to the real handler in order to save the bnd regs
309 using xsave before any unprefixed call. an unprefixed call to
310 __i686.get_pc_thunk.bx is added by the linker in 32bit at the
311 beginning of handler function since there are references to
312 global variables. */
313 static void
314 handler_wrap (int signum, siginfo_t* si, void* vucontext)
316 /* Since the OS currently not handling chkptr regs.
317 We need to store them for later use. They might be
318 init due to unprefixed call,Jcc,ret. avoiding calling
319 function since the function will be unprefixed as well. */
320 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
321 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
322 uint64_t mask = 0x18;
323 uint32_t lmask = mask;
324 uint32_t hmask = mask >> 32;
326 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
327 : : "D" (xsave_buf), "m" (*xsave_buf),
328 "a" (lmask), "d" (hmask)
329 : "memory");
331 handler (signum, si, vucontext, xsave_buf);
334 static bool
335 check_mpx_support (void)
337 unsigned int eax, ebx, ecx, edx;
338 unsigned int max_level = __get_cpuid_max (0, NULL);
340 if (max_level < 13)
342 __mpxrt_print (VERB_DEBUG, "No required CPUID level support.\n");
343 return false;
346 __cpuid_count (0, 0, eax, ebx, ecx, edx);
347 if (!(ecx & bit_XSAVE))
349 __mpxrt_print (VERB_DEBUG, "No XSAVE support.\n");
350 return false;
353 if (!(ecx & bit_OSXSAVE))
355 __mpxrt_print (VERB_DEBUG, "No OSXSAVE support.\n");
356 return false;
359 __cpuid_count (7, 0, eax, ebx, ecx, edx);
360 if (!(ebx & bit_MPX))
362 __mpxrt_print (VERB_DEBUG, "No MPX support.\n");
363 return false;
366 __cpuid_count (13, 0, eax, ebx, ecx, edx);
367 if (!(eax & bit_BNDREGS))
369 __mpxrt_print (VERB_DEBUG, "No BNDREGS support.\n");
370 return false;
373 if (!(eax & bit_BNDCSR))
375 __mpxrt_print (VERB_DEBUG, "No BNDCSR support.\n");
376 return false;
379 return true;
382 static void
383 enable_mpx (void)
385 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
386 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
388 memset (buffer, 0, sizeof (buffer));
389 xrstor_state (xsave_buf, 0x18);
391 __mpxrt_print (VERB_DEBUG, "Initalizing MPX...\n");
392 __mpxrt_print (VERB_DEBUG, " Enable bit: %d\n", enable);
393 __mpxrt_print (VERB_DEBUG, " BNDPRESERVE bit: %d\n", bndpreserve);
395 /* Enable MPX. */
396 xsave_buf->xsave_hdr.xstate_bv = 0x10;
397 xsave_buf->bndcsr.cfg_reg_u = (unsigned long)l1base;
398 xsave_buf->bndcsr.cfg_reg_u |= enable << MPX_ENABLE_BIT_NO;
399 xsave_buf->bndcsr.cfg_reg_u |= bndpreserve << BNDPRESERVE_BIT_NO;
400 xsave_buf->bndcsr.status_reg = 0;
402 xrstor_state (xsave_buf, 0x10);
405 static void
406 disable_mpx (void)
408 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
409 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
411 memset(buffer, 0, sizeof(buffer));
412 xrstor_state(xsave_buf, 0x18);
414 /* Disable MPX. */
415 xsave_buf->xsave_hdr.xstate_bv = 0x10;
416 xsave_buf->bndcsr.cfg_reg_u = 0;
417 xsave_buf->bndcsr.status_reg = 0;
419 xrstor_state(xsave_buf, 0x10);
422 static bool
423 process_specific_init (void)
425 if (!check_mpx_support ())
426 return false;
428 l1base = mmap (NULL, MPX_L1_SIZE, PROT_READ | PROT_WRITE,
429 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
430 if (l1base == MAP_FAILED)
432 perror ("mmap");
433 exit (EXIT_FAILURE);
436 enable_mpx ();
438 if (prctl (43, 0, 0, 0, 0))
440 __mpxrt_print (VERB_ERROR, "No MPX support\n");
441 disable_mpx ();
442 return false;
445 return true;
448 static bool
449 process_specific_finish (void)
451 if (!check_mpx_support ())
452 return false;
454 if (prctl (44, 0, 0, 0, 0))
456 __mpxrt_print (VERB_ERROR, "No MPX support\n");
457 return false;
460 munmap (l1base, MPX_L1_SIZE);
462 return true;
465 static void
466 setup_handler (void)
468 int r,rs;
469 struct sigaction newact;
471 /* #BR is mapped to sigsegv */
472 int signum = SIGSEGV;
474 newact.sa_handler = 0;
475 newact.sa_sigaction = handler_wrap;
477 /* sigset_t - signals to block while in the handler
478 get the old signal mask. */
479 rs = sigprocmask (SIG_SETMASK, 0, &newact.sa_mask);
480 assert (rs == 0);
482 /* Call sa_sigaction, not sa_handler. */
483 newact.sa_flags = SA_SIGINFO;
484 /* In case we call user's handler on SIGSEGV (not bound
485 violation exception) we want to allow bound checking
486 inside the user handler -> nested exception. */
487 newact.sa_flags |= SA_NODEFER;
489 newact.sa_restorer = 0;
490 r = sigaction (signum, &newact, 0);
491 assert (r == 0);
494 /* Set constructor priority to two to make it run after the
495 constructor in sigaction.c. */
496 static void __attribute__ ((constructor (1005)))
497 mpxrt_prepare (void)
499 __mpxrt_init_env_vars (&bndpreserve);
500 setup_handler ();
501 process_specific_init ();
504 static void __attribute__ ((destructor))
505 mpxrt_cleanup (void)
507 __mpxrt_print_summary (num_bnd_chk, MPX_L1_SIZE);
508 __mpxrt_utils_free ();
509 process_specific_finish ();