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 *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
;
161 get_next_inst_ip (uint8_t *addr
)
166 /* Determine the prefix. */
176 /* Look for rex prefix. */
177 if ((*ip
& 0x40) == 0x40)
180 /* Make sure we have a MPX instruction. */
184 /* Skip the op code byte. */
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. */
197 /* Is it a mem mode? */
200 /* Look for scaled indexed addressing. */
203 /* SIB addressing. */
224 /* MODRM addressing. */
229 /* DISP32 addressing, no base. */
247 handler (int sig
__attribute__ ((unused
)),
248 siginfo_t
*info
__attribute__ ((unused
)),
250 struct xsave_struct
*buf
__attribute__ ((unused
)))
257 trapno
= uctxt
->uc_mcontext
.gregs
[REG_TRAPNO
];
258 ip
= uctxt
->uc_mcontext
.gregs
[REG_IP_IDX
];
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");
273 case 1: /* traditional BR */
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
)
282 __mpxrt_write (VERB_BR
, "Unexpected status with bound exception: ");
283 __mpxrt_write_uint (VERB_BR
, status
, 10);
284 __mpxrt_write (VERB_BR
, "\n");
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");
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");
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
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
)
331 handler (signum
, si
, vucontext
, xsave_buf
);
335 check_mpx_support (void)
337 unsigned int eax
, ebx
, ecx
, edx
;
338 unsigned int max_level
= __get_cpuid_max (0, NULL
);
342 __mpxrt_print (VERB_DEBUG
, "No required CPUID level support.\n");
346 __cpuid_count (0, 0, eax
, ebx
, ecx
, edx
);
347 if (!(ecx
& bit_XSAVE
))
349 __mpxrt_print (VERB_DEBUG
, "No XSAVE support.\n");
353 if (!(ecx
& bit_OSXSAVE
))
355 __mpxrt_print (VERB_DEBUG
, "No OSXSAVE support.\n");
359 __cpuid_count (7, 0, eax
, ebx
, ecx
, edx
);
360 if (!(ebx
& bit_MPX
))
362 __mpxrt_print (VERB_DEBUG
, "No MPX support.\n");
366 __cpuid_count (13, 0, eax
, ebx
, ecx
, edx
);
367 if (!(eax
& bit_BNDREGS
))
369 __mpxrt_print (VERB_DEBUG
, "No BNDREGS support.\n");
373 if (!(eax
& bit_BNDCSR
))
375 __mpxrt_print (VERB_DEBUG
, "No BNDCSR support.\n");
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
);
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);
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);
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);
423 process_specific_init (void)
425 if (!check_mpx_support ())
428 l1base
= mmap (NULL
, MPX_L1_SIZE
, PROT_READ
| PROT_WRITE
,
429 MAP_ANONYMOUS
| MAP_PRIVATE
, -1, 0);
430 if (l1base
== MAP_FAILED
)
438 if (prctl (43, 0, 0, 0, 0))
440 __mpxrt_print (VERB_ERROR
, "No MPX support\n");
449 process_specific_finish (void)
451 if (!check_mpx_support ())
454 if (prctl (44, 0, 0, 0, 0))
456 __mpxrt_print (VERB_ERROR
, "No MPX support\n");
460 munmap (l1base
, MPX_L1_SIZE
);
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
);
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);
494 /* Set constructor priority to two to make it run after the
495 constructor in sigaction.c. */
496 static void __attribute__ ((constructor (1005)))
499 __mpxrt_init_env_vars (&bndpreserve
);
501 process_specific_init ();
504 static void __attribute__ ((destructor
))
507 __mpxrt_print_summary (num_bnd_chk
, MPX_L1_SIZE
);
508 __mpxrt_utils_free ();
509 process_specific_finish ();