3 *************************************************************************
6 * Copyright (C) 2014, Intel Corporation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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.
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
51 #include <sys/prctl.h>
53 #include "mpxrt-utils.h"
57 /* i386 directory size is 4MB */
58 #define NUM_L1_BITS 20
60 #define REG_IP_IDX REG_EIP
63 #define XSAVE_OFFSET_IN_FPMEM sizeof (struct _libc_fpstate)
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
85 uint64_t reserved1
[2];
86 uint64_t reserved2
[5];
87 } __attribute__ ((packed
));
92 } __attribute__ ((packed
));
94 struct bndcsr_struct
{
97 } __attribute__((packed
));
101 uint8_t fpu_sse
[512];
102 struct xsave_hdr_struct xsave_hdr
;
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;
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
)
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
)
141 static inline uint64_t
142 xgetbv (uint32_t index
)
146 asm volatile (".byte 0x0f,0x01,0xd0" /* xgetbv */
147 : "=a" (eax
), "=d" (edx
)
149 return eax
+ ((uint64_t)edx
<< 32);
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
));
160 (uint8_t *)uctxt
->uc_mcontext
.fpregs
+ XSAVE_OFFSET_IN_FPMEM
,
161 sizeof (struct xsave_struct
));
162 return xsave_buf
->bndcsr
.status_reg
;
166 get_next_inst_ip (uint8_t *addr
)
171 /* Determine the prefix. */
181 /* Look for rex prefix. */
182 if ((*ip
& 0x40) == 0x40)
185 /* Make sure we have a MPX instruction. */
189 /* Skip the op code byte. */
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. */
202 /* Is it a mem mode? */
205 /* Look for scaled indexed addressing. */
208 /* SIB addressing. */
229 /* MODRM addressing. */
234 /* DISP32 addressing, no base. */
252 handler (int sig
__attribute__ ((unused
)),
253 siginfo_t
*info
__attribute__ ((unused
)),
255 struct xsave_struct
*buf
__attribute__ ((unused
)))
262 trapno
= uctxt
->uc_mcontext
.gregs
[REG_TRAPNO
];
263 ip
= uctxt
->uc_mcontext
.gregs
[REG_IP_IDX
];
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");
278 case 1: /* traditional BR */
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
)
287 __mpxrt_write (VERB_BR
, "Unexpected status with bound exception: ");
288 __mpxrt_write_uint (VERB_BR
, status
, 10);
289 __mpxrt_write (VERB_BR
, "\n");
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");
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");
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
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
)
336 handler (signum
, si
, vucontext
, xsave_buf
);
340 check_mpx_support (void)
342 unsigned int eax
, ebx
, ecx
, edx
;
343 unsigned int max_level
= __get_cpuid_max (0, NULL
);
347 __mpxrt_print (VERB_DEBUG
, "No required CPUID level support.\n");
351 __cpuid_count (0, 0, eax
, ebx
, ecx
, edx
);
352 if (!(ecx
& bit_XSAVE
))
354 __mpxrt_print (VERB_DEBUG
, "No XSAVE support.\n");
358 if (!(ecx
& bit_OSXSAVE
))
360 __mpxrt_print (VERB_DEBUG
, "No OSXSAVE support.\n");
364 __cpuid_count (7, 0, eax
, ebx
, ecx
, edx
);
365 if (!(ebx
& bit_MPX
))
367 __mpxrt_print (VERB_DEBUG
, "No MPX support.\n");
371 __cpuid_count (13, 0, eax
, ebx
, ecx
, edx
);
372 if (!(eax
& bit_BNDREGS
))
374 __mpxrt_print (VERB_DEBUG
, "No BNDREGS support.\n");
378 if (!(eax
& bit_BNDCSR
))
380 __mpxrt_print (VERB_DEBUG
, "No BNDCSR support.\n");
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
);
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);
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);
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);
428 process_specific_init (void)
430 if (!check_mpx_support ())
433 l1base
= mmap (NULL
, MPX_L1_SIZE
, PROT_READ
| PROT_WRITE
,
434 MAP_ANONYMOUS
| MAP_PRIVATE
, -1, 0);
435 if (l1base
== MAP_FAILED
)
443 if (prctl (43, 0, 0, 0, 0))
445 __mpxrt_print (VERB_ERROR
, "No MPX support\n");
454 process_specific_finish (void)
456 if (!check_mpx_support ())
459 if (prctl (44, 0, 0, 0, 0))
461 __mpxrt_print (VERB_ERROR
, "No MPX support\n");
465 munmap (l1base
, MPX_L1_SIZE
);
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
);
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);
499 /* Set constructor priority to two to make it run after the
500 constructor in sigaction.c. */
501 static void __attribute__ ((constructor (1005)))
504 __mpxrt_init_env_vars (&bndpreserve
);
506 process_specific_init ();
509 static void __attribute__ ((destructor
))
512 __mpxrt_print_summary (num_bnd_chk
, MPX_L1_SIZE
);
513 __mpxrt_utils_free ();
514 process_specific_finish ();