Clean up some minor white space issues in trans-decl.c and trans-expr.c
[official-gcc.git] / libmpx / mpxrt / mpxrt.c
blobbcdd3a63bd248cb02d5f6007523fda4f8c34dcf8
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"
54 #include "mpxrt.h"
56 #define MPX_ENABLE_BIT_NO 0
57 #define BNDPRESERVE_BIT_NO 1
59 struct xsave_hdr_struct
61 uint64_t xstate_bv;
62 uint64_t reserved1[2];
63 uint64_t reserved2[5];
64 } __attribute__ ((packed));
66 struct bndregs_struct
68 uint64_t bndregs[8];
69 } __attribute__ ((packed));
71 struct bndcsr_struct {
72 uint64_t cfg_reg_u;
73 uint64_t status_reg;
74 } __attribute__((packed));
76 struct xsave_struct
78 uint8_t fpu_sse[512];
79 struct xsave_hdr_struct xsave_hdr;
80 uint8_t ymm[256];
81 uint8_t lwp[128];
82 struct bndregs_struct bndregs;
83 struct bndcsr_struct bndcsr;
84 } __attribute__ ((packed));
86 /* Following vars are initialized at process startup only
87 and thus are considered to be thread safe. */
88 static void *l1base = NULL;
89 static int bndpreserve;
90 static int enable = 1;
92 /* Var holding number of occured BRs. It is modified from
93 signal handler only and thus it should be thread safe. */
94 static uint64_t num_bnd_chk = 0;
96 static inline void
97 xrstor_state (struct xsave_struct *fx, uint64_t mask)
99 uint32_t lmask = mask;
100 uint32_t hmask = mask >> 32;
102 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
103 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
104 : "memory");
107 static inline void
108 xsave_state (struct xsave_struct *fx, uint64_t mask)
110 uint32_t lmask = mask;
111 uint32_t hmask = mask >> 32;
113 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
114 : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
115 : "memory");
118 static inline uint64_t
119 xgetbv (uint32_t index)
121 uint32_t eax, edx;
123 asm volatile (".byte 0x0f,0x01,0xd0" /* xgetbv */
124 : "=a" (eax), "=d" (edx)
125 : "c" (index));
126 return eax + ((uint64_t)edx << 32);
129 static uint64_t
130 read_mpx_status_sig (ucontext_t *uctxt)
132 uint8_t *regs = (uint8_t *)uctxt->uc_mcontext.fpregs + XSAVE_OFFSET_IN_FPMEM;
133 struct xsave_struct *xsave_buf = (struct xsave_struct *)regs;
134 return xsave_buf->bndcsr.status_reg;
137 static uint8_t *
138 get_next_inst_ip (uint8_t *addr)
140 uint8_t *ip = addr;
141 uint8_t sib;
143 /* Determine the prefix. */
144 switch (*ip)
146 case 0xf2:
147 case 0xf3:
148 case 0x66:
149 ip++;
150 break;
153 /* Look for rex prefix. */
154 if ((*ip & 0x40) == 0x40)
155 ip++;
157 /* Make sure we have a MPX instruction. */
158 if (*ip++ != 0x0f)
159 return addr;
161 /* Skip the op code byte. */
162 ip++;
164 /* Get the moderm byte. */
165 uint8_t modrm = *ip++;
167 /* Break it down into parts. */
168 uint8_t rm = modrm & 7;
169 uint8_t mod = (modrm >> 6);
171 /* Init the parts of the address mode. */
172 uint8_t base = 8;
174 /* Is it a mem mode? */
175 if (mod != 3)
177 /* Look for scaled indexed addressing. */
178 if (rm == 4)
180 /* SIB addressing. */
181 sib = *ip++;
182 base = sib & 7;
183 switch (mod)
185 case 0:
186 if (base == 5)
187 ip += 4;
188 break;
190 case 1:
191 ip++;
192 break;
194 case 2:
195 ip += 4;
196 break;
199 else
201 /* MODRM addressing. */
202 switch (mod)
204 case 0:
205 if (rm == 5)
206 /* DISP32 addressing, no base. */
207 ip += 4;
208 break;
210 case 1:
211 ip++;
212 break;
214 case 2:
215 ip += 4;
216 break;
220 return ip;
223 static void
224 handler (int sig __attribute__ ((unused)),
225 siginfo_t *info __attribute__ ((unused)),
226 void *vucontext,
227 struct xsave_struct *buf __attribute__ ((unused)))
229 ucontext_t* uctxt;
230 greg_t trapno;
231 greg_t ip;
233 uctxt = vucontext;
234 trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
235 ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
237 if (trapno == 5)
239 uint64_t status = read_mpx_status_sig (uctxt);
240 uint64_t br_reason = status & 0x3;
242 __mpxrt_write (VERB_BR, "Saw a #BR! status ");
243 __mpxrt_write_uint (VERB_BR, status, 10);
244 __mpxrt_write (VERB_BR, " at 0x");
245 __mpxrt_write_uint (VERB_BR, ip, 16);
246 __mpxrt_write (VERB_BR, "\n");
248 switch (br_reason)
250 case 1: /* traditional BR */
251 num_bnd_chk++;
252 uctxt->uc_mcontext.gregs[REG_IP_IDX] =
253 (greg_t)get_next_inst_ip ((uint8_t *)ip);
254 if (__mpxrt_mode () == MPX_RT_STOP)
255 exit (255);
256 return;
258 default:
259 __mpxrt_write (VERB_BR, "Unexpected status with bound exception: ");
260 __mpxrt_write_uint (VERB_BR, status, 10);
261 __mpxrt_write (VERB_BR, "\n");
262 break;
265 else if (trapno == 14)
267 __mpxrt_write (VERB_ERROR, "In signal handler, trapno = ");
268 __mpxrt_write_uint (VERB_ERROR, trapno, 10);
269 __mpxrt_write (VERB_ERROR, ", ip = 0x");
270 __mpxrt_write_uint (VERB_ERROR, ip, 16);
271 __mpxrt_write (VERB_BR, "\n");
272 exit (255);
274 else
276 __mpxrt_write (VERB_ERROR, "Unexpected trap ");
277 __mpxrt_write_uint (VERB_ERROR, trapno, 10);
278 __mpxrt_write (VERB_ERROR, "! at 0x");
279 __mpxrt_write_uint (VERB_ERROR, ip, 16);
280 __mpxrt_write (VERB_BR, "\n");
281 exit (255);
285 /* Using wrapper to the real handler in order to save the bnd regs
286 using xsave before any unprefixed call. an unprefixed call to
287 __i686.get_pc_thunk.bx is added by the linker in 32bit at the
288 beginning of handler function since there are references to
289 global variables. */
290 static void
291 handler_wrap (int signum, siginfo_t* si, void* vucontext)
293 /* Since the OS currently not handling chkptr regs.
294 We need to store them for later use. They might be
295 init due to unprefixed call,Jcc,ret. avoiding calling
296 function since the function will be unprefixed as well. */
297 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
298 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
299 uint64_t mask = 0x18;
300 uint32_t lmask = mask;
301 uint32_t hmask = mask >> 32;
303 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
304 : : "D" (xsave_buf), "m" (*xsave_buf),
305 "a" (lmask), "d" (hmask)
306 : "memory");
308 handler (signum, si, vucontext, xsave_buf);
311 static bool
312 check_mpx_support (void)
314 unsigned int eax, ebx, ecx, edx;
315 unsigned int max_level = __get_cpuid_max (0, NULL);
317 if (max_level < 13)
319 __mpxrt_print (VERB_DEBUG, "No required CPUID level support.\n");
320 return false;
323 __cpuid_count (0, 0, eax, ebx, ecx, edx);
324 if (!(ecx & bit_XSAVE))
326 __mpxrt_print (VERB_DEBUG, "No XSAVE support.\n");
327 return false;
330 if (!(ecx & bit_OSXSAVE))
332 __mpxrt_print (VERB_DEBUG, "No OSXSAVE support.\n");
333 return false;
336 __cpuid_count (7, 0, eax, ebx, ecx, edx);
337 if (!(ebx & bit_MPX))
339 __mpxrt_print (VERB_DEBUG, "No MPX support.\n");
340 return false;
343 __cpuid_count (13, 0, eax, ebx, ecx, edx);
344 if (!(eax & bit_BNDREGS))
346 __mpxrt_print (VERB_DEBUG, "No BNDREGS support.\n");
347 return false;
350 if (!(eax & bit_BNDCSR))
352 __mpxrt_print (VERB_DEBUG, "No BNDCSR support.\n");
353 return false;
356 return true;
359 static void
360 enable_mpx (void)
362 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
363 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
365 memset (buffer, 0, sizeof (buffer));
366 xrstor_state (xsave_buf, 0x18);
368 __mpxrt_print (VERB_DEBUG, "Initalizing MPX...\n");
369 __mpxrt_print (VERB_DEBUG, " Enable bit: %d\n", enable);
370 __mpxrt_print (VERB_DEBUG, " BNDPRESERVE bit: %d\n", bndpreserve);
372 /* Enable MPX. */
373 xsave_buf->xsave_hdr.xstate_bv = 0x10;
374 xsave_buf->bndcsr.cfg_reg_u = (unsigned long)l1base;
375 xsave_buf->bndcsr.cfg_reg_u |= enable << MPX_ENABLE_BIT_NO;
376 xsave_buf->bndcsr.cfg_reg_u |= bndpreserve << BNDPRESERVE_BIT_NO;
377 xsave_buf->bndcsr.status_reg = 0;
379 xrstor_state (xsave_buf, 0x10);
382 static void
383 disable_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 /* Disable MPX. */
392 xsave_buf->xsave_hdr.xstate_bv = 0x10;
393 xsave_buf->bndcsr.cfg_reg_u = 0;
394 xsave_buf->bndcsr.status_reg = 0;
396 xrstor_state(xsave_buf, 0x10);
399 static bool
400 process_specific_init (void)
402 if (!check_mpx_support ())
403 return false;
405 l1base = mmap (NULL, MPX_L1_SIZE, PROT_READ | PROT_WRITE,
406 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
407 if (l1base == MAP_FAILED)
409 perror ("mmap");
410 exit (EXIT_FAILURE);
413 enable_mpx ();
415 if (prctl (43, 0, 0, 0, 0))
417 __mpxrt_print (VERB_ERROR, "No MPX support\n");
418 disable_mpx ();
419 return false;
422 return true;
425 static bool
426 process_specific_finish (void)
428 if (!check_mpx_support ())
429 return false;
431 if (prctl (44, 0, 0, 0, 0))
433 __mpxrt_print (VERB_ERROR, "No MPX support\n");
434 return false;
437 munmap (l1base, MPX_L1_SIZE);
439 return true;
442 static void
443 setup_handler (void)
445 int r,rs;
446 struct sigaction newact;
448 /* #BR is mapped to sigsegv */
449 int signum = SIGSEGV;
451 newact.sa_handler = 0;
452 newact.sa_sigaction = handler_wrap;
454 /* sigset_t - signals to block while in the handler
455 get the old signal mask. */
456 rs = sigprocmask (SIG_SETMASK, 0, &newact.sa_mask);
457 assert (rs == 0);
459 /* Call sa_sigaction, not sa_handler. */
460 newact.sa_flags = SA_SIGINFO;
461 /* In case we call user's handler on SIGSEGV (not bound
462 violation exception) we want to allow bound checking
463 inside the user handler -> nested exception. */
464 newact.sa_flags |= SA_NODEFER;
466 newact.sa_restorer = 0;
467 r = sigaction (signum, &newact, 0);
468 assert (r == 0);
471 /* Set constructor priority to two to make it run after the
472 constructor in sigaction.c. */
473 static void __attribute__ ((constructor (1005)))
474 mpxrt_prepare (void)
476 __mpxrt_init_env_vars (&bndpreserve);
477 setup_handler ();
478 process_specific_init ();
481 static void __attribute__ ((destructor))
482 mpxrt_cleanup (void)
484 __mpxrt_print_summary (num_bnd_chk, MPX_L1_SIZE);
485 __mpxrt_utils_free ();
486 process_specific_finish ();
489 /* Get address of bounds directory. */
490 void *
491 get_bd ()
493 return l1base;