2015-05-18 Steven G. Kargl <kargl@gcc.gnu.org>
[official-gcc.git] / libmpx / mpxrt / mpxrt.c
blob0eff87e7cc6627afff194b46a9d264dd5b177437
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 __attribute__ ((__aligned__ (64))) buffer[4096];
156 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
158 memset (buffer, 0, sizeof (buffer));
159 memcpy (buffer,
160 (uint8_t *)uctxt->uc_mcontext.fpregs + XSAVE_OFFSET_IN_FPMEM,
161 sizeof (struct xsave_struct));
162 return xsave_buf->bndcsr.status_reg;
165 static uint8_t *
166 get_next_inst_ip (uint8_t *addr)
168 uint8_t *ip = addr;
169 uint8_t sib;
171 /* Determine the prefix. */
172 switch (*ip)
174 case 0xf2:
175 case 0xf3:
176 case 0x66:
177 ip++;
178 break;
181 /* Look for rex prefix. */
182 if ((*ip & 0x40) == 0x40)
183 ip++;
185 /* Make sure we have a MPX instruction. */
186 if (*ip++ != 0x0f)
187 return addr;
189 /* Skip the op code byte. */
190 ip++;
192 /* Get the moderm byte. */
193 uint8_t modrm = *ip++;
195 /* Break it down into parts. */
196 uint8_t rm = modrm & 7;
197 uint8_t mod = (modrm >> 6);
199 /* Init the parts of the address mode. */
200 uint8_t base = 8;
202 /* Is it a mem mode? */
203 if (mod != 3)
205 /* Look for scaled indexed addressing. */
206 if (rm == 4)
208 /* SIB addressing. */
209 sib = *ip++;
210 base = sib & 7;
211 switch (mod)
213 case 0:
214 if (base == 5)
215 ip += 4;
216 break;
218 case 1:
219 ip++;
220 break;
222 case 2:
223 ip += 4;
224 break;
227 else
229 /* MODRM addressing. */
230 switch (mod)
232 case 0:
233 if (rm == 5)
234 /* DISP32 addressing, no base. */
235 ip += 4;
236 break;
238 case 1:
239 ip++;
240 break;
242 case 2:
243 ip += 4;
244 break;
248 return ip;
251 static void
252 handler (int sig __attribute__ ((unused)),
253 siginfo_t *info __attribute__ ((unused)),
254 void *vucontext,
255 struct xsave_struct *buf __attribute__ ((unused)))
257 ucontext_t* uctxt;
258 greg_t trapno;
259 greg_t ip;
261 uctxt = vucontext;
262 trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
263 ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
265 if (trapno == 5)
267 uint64_t status = read_mpx_status_sig (uctxt);
268 uint64_t br_reason = status & 0x3;
270 __mpxrt_write (VERB_BR, "Saw a #BR! status ");
271 __mpxrt_write_uint (VERB_BR, status, 10);
272 __mpxrt_write (VERB_BR, " at 0x");
273 __mpxrt_write_uint (VERB_BR, ip, 16);
274 __mpxrt_write (VERB_BR, "\n");
276 switch (br_reason)
278 case 1: /* traditional BR */
279 num_bnd_chk++;
280 uctxt->uc_mcontext.gregs[REG_IP_IDX] =
281 (greg_t)get_next_inst_ip ((uint8_t *)ip);
282 if (__mpxrt_mode () == MPX_RT_STOP)
283 exit (255);
284 return;
286 default:
287 __mpxrt_write (VERB_BR, "Unexpected status with bound exception: ");
288 __mpxrt_write_uint (VERB_BR, status, 10);
289 __mpxrt_write (VERB_BR, "\n");
290 break;
293 else if (trapno == 14)
295 __mpxrt_write (VERB_ERROR, "In signal handler, trapno = ");
296 __mpxrt_write_uint (VERB_ERROR, trapno, 10);
297 __mpxrt_write (VERB_ERROR, ", ip = 0x");
298 __mpxrt_write_uint (VERB_ERROR, ip, 16);
299 __mpxrt_write (VERB_BR, "\n");
300 exit (255);
302 else
304 __mpxrt_write (VERB_ERROR, "Unexpected trap ");
305 __mpxrt_write_uint (VERB_ERROR, trapno, 10);
306 __mpxrt_write (VERB_ERROR, "! at 0x");
307 __mpxrt_write_uint (VERB_ERROR, ip, 16);
308 __mpxrt_write (VERB_BR, "\n");
309 exit (255);
313 /* Using wrapper to the real handler in order to save the bnd regs
314 using xsave before any unprefixed call. an unprefixed call to
315 __i686.get_pc_thunk.bx is added by the linker in 32bit at the
316 beginning of handler function since there are references to
317 global variables. */
318 static void
319 handler_wrap (int signum, siginfo_t* si, void* vucontext)
321 /* Since the OS currently not handling chkptr regs.
322 We need to store them for later use. They might be
323 init due to unprefixed call,Jcc,ret. avoiding calling
324 function since the function will be unprefixed as well. */
325 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
326 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
327 uint64_t mask = 0x18;
328 uint32_t lmask = mask;
329 uint32_t hmask = mask >> 32;
331 asm volatile (".byte " REX_PREFIX "0x0f,0xae,0x27\n\t"
332 : : "D" (xsave_buf), "m" (*xsave_buf),
333 "a" (lmask), "d" (hmask)
334 : "memory");
336 handler (signum, si, vucontext, xsave_buf);
339 static bool
340 check_mpx_support (void)
342 unsigned int eax, ebx, ecx, edx;
343 unsigned int max_level = __get_cpuid_max (0, NULL);
345 if (max_level < 13)
347 __mpxrt_print (VERB_DEBUG, "No required CPUID level support.\n");
348 return false;
351 __cpuid_count (0, 0, eax, ebx, ecx, edx);
352 if (!(ecx & bit_XSAVE))
354 __mpxrt_print (VERB_DEBUG, "No XSAVE support.\n");
355 return false;
358 if (!(ecx & bit_OSXSAVE))
360 __mpxrt_print (VERB_DEBUG, "No OSXSAVE support.\n");
361 return false;
364 __cpuid_count (7, 0, eax, ebx, ecx, edx);
365 if (!(ebx & bit_MPX))
367 __mpxrt_print (VERB_DEBUG, "No MPX support.\n");
368 return false;
371 __cpuid_count (13, 0, eax, ebx, ecx, edx);
372 if (!(eax & bit_BNDREGS))
374 __mpxrt_print (VERB_DEBUG, "No BNDREGS support.\n");
375 return false;
378 if (!(eax & bit_BNDCSR))
380 __mpxrt_print (VERB_DEBUG, "No BNDCSR support.\n");
381 return false;
384 return true;
387 static void
388 enable_mpx (void)
390 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
391 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
393 memset (buffer, 0, sizeof (buffer));
394 xrstor_state (xsave_buf, 0x18);
396 __mpxrt_print (VERB_DEBUG, "Initalizing MPX...\n");
397 __mpxrt_print (VERB_DEBUG, " Enable bit: %d\n", enable);
398 __mpxrt_print (VERB_DEBUG, " BNDPRESERVE bit: %d\n", bndpreserve);
400 /* Enable MPX. */
401 xsave_buf->xsave_hdr.xstate_bv = 0x10;
402 xsave_buf->bndcsr.cfg_reg_u = (unsigned long)l1base;
403 xsave_buf->bndcsr.cfg_reg_u |= enable << MPX_ENABLE_BIT_NO;
404 xsave_buf->bndcsr.cfg_reg_u |= bndpreserve << BNDPRESERVE_BIT_NO;
405 xsave_buf->bndcsr.status_reg = 0;
407 xrstor_state (xsave_buf, 0x10);
410 static void
411 disable_mpx (void)
413 uint8_t __attribute__ ((__aligned__ (64))) buffer[4096];
414 struct xsave_struct *xsave_buf = (struct xsave_struct *)buffer;
416 memset(buffer, 0, sizeof(buffer));
417 xrstor_state(xsave_buf, 0x18);
419 /* Disable MPX. */
420 xsave_buf->xsave_hdr.xstate_bv = 0x10;
421 xsave_buf->bndcsr.cfg_reg_u = 0;
422 xsave_buf->bndcsr.status_reg = 0;
424 xrstor_state(xsave_buf, 0x10);
427 static bool
428 process_specific_init (void)
430 if (!check_mpx_support ())
431 return false;
433 l1base = mmap (NULL, MPX_L1_SIZE, PROT_READ | PROT_WRITE,
434 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
435 if (l1base == MAP_FAILED)
437 perror ("mmap");
438 exit (EXIT_FAILURE);
441 enable_mpx ();
443 if (prctl (43, 0, 0, 0, 0))
445 __mpxrt_print (VERB_ERROR, "No MPX support\n");
446 disable_mpx ();
447 return false;
450 return true;
453 static bool
454 process_specific_finish (void)
456 if (!check_mpx_support ())
457 return false;
459 if (prctl (44, 0, 0, 0, 0))
461 __mpxrt_print (VERB_ERROR, "No MPX support\n");
462 return false;
465 munmap (l1base, MPX_L1_SIZE);
467 return true;
470 static void
471 setup_handler (void)
473 int r,rs;
474 struct sigaction newact;
476 /* #BR is mapped to sigsegv */
477 int signum = SIGSEGV;
479 newact.sa_handler = 0;
480 newact.sa_sigaction = handler_wrap;
482 /* sigset_t - signals to block while in the handler
483 get the old signal mask. */
484 rs = sigprocmask (SIG_SETMASK, 0, &newact.sa_mask);
485 assert (rs == 0);
487 /* Call sa_sigaction, not sa_handler. */
488 newact.sa_flags = SA_SIGINFO;
489 /* In case we call user's handler on SIGSEGV (not bound
490 violation exception) we want to allow bound checking
491 inside the user handler -> nested exception. */
492 newact.sa_flags |= SA_NODEFER;
494 newact.sa_restorer = 0;
495 r = sigaction (signum, &newact, 0);
496 assert (r == 0);
499 /* Set constructor priority to two to make it run after the
500 constructor in sigaction.c. */
501 static void __attribute__ ((constructor (1005)))
502 mpxrt_prepare (void)
504 __mpxrt_init_env_vars (&bndpreserve);
505 setup_handler ();
506 process_specific_init ();
509 static void __attribute__ ((destructor))
510 mpxrt_cleanup (void)
512 __mpxrt_print_summary (num_bnd_chk, MPX_L1_SIZE);
513 __mpxrt_utils_free ();
514 process_specific_finish ();