aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c85
1 files changed, 84 insertions, 1 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 07ab8e9733c5..a9ae20579895 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -60,6 +60,7 @@
60#include <asm/fixmap.h> 60#include <asm/fixmap.h>
61#include <asm/mach_traps.h> 61#include <asm/mach_traps.h>
62#include <asm/alternative.h> 62#include <asm/alternative.h>
63#include <asm/mpx.h>
63 64
64#ifdef CONFIG_X86_64 65#ifdef CONFIG_X86_64
65#include <asm/x86_init.h> 66#include <asm/x86_init.h>
@@ -228,7 +229,6 @@ dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
228 229
229DO_ERROR(X86_TRAP_DE, SIGFPE, "divide error", divide_error) 230DO_ERROR(X86_TRAP_DE, SIGFPE, "divide error", divide_error)
230DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow) 231DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow)
231DO_ERROR(X86_TRAP_BR, SIGSEGV, "bounds", bounds)
232DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op) 232DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op)
233DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) 233DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun)
234DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) 234DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
@@ -286,6 +286,89 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
286} 286}
287#endif 287#endif
288 288
289dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
290{
291 struct task_struct *tsk = current;
292 struct xsave_struct *xsave_buf;
293 enum ctx_state prev_state;
294 struct bndcsr *bndcsr;
295 siginfo_t *info;
296
297 prev_state = exception_enter();
298 if (notify_die(DIE_TRAP, "bounds", regs, error_code,
299 X86_TRAP_BR, SIGSEGV) == NOTIFY_STOP)
300 goto exit;
301 conditional_sti(regs);
302
303 if (!user_mode(regs))
304 die("bounds", regs, error_code);
305
306 if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
307 /* The exception is not from Intel MPX */
308 goto exit_trap;
309 }
310
311 /*
312 * We need to look at BNDSTATUS to resolve this exception.
313 * It is not directly accessible, though, so we need to
314 * do an xsave and then pull it out of the xsave buffer.
315 */
316 fpu_save_init(&tsk->thread.fpu);
317 xsave_buf = &(tsk->thread.fpu.state->xsave);
318 bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
319 if (!bndcsr)
320 goto exit_trap;
321
322 /*
323 * The error code field of the BNDSTATUS register communicates status
324 * information of a bound range exception #BR or operation involving
325 * bound directory.
326 */
327 switch (bndcsr->bndstatus & MPX_BNDSTA_ERROR_CODE) {
328 case 2: /* Bound directory has invalid entry. */
329 if (mpx_handle_bd_fault(xsave_buf))
330 goto exit_trap;
331 break; /* Success, it was handled */
332 case 1: /* Bound violation. */
333 info = mpx_generate_siginfo(regs, xsave_buf);
334 if (PTR_ERR(info)) {
335 /*
336 * We failed to decode the MPX instruction. Act as if
337 * the exception was not caused by MPX.
338 */
339 goto exit_trap;
340 }
341 /*
342 * Success, we decoded the instruction and retrieved
343 * an 'info' containing the address being accessed
344 * which caused the exception. This information
345 * allows and application to possibly handle the
346 * #BR exception itself.
347 */
348 do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info);
349 kfree(info);
350 break;
351 case 0: /* No exception caused by Intel MPX operations. */
352 goto exit_trap;
353 default:
354 die("bounds", regs, error_code);
355 }
356
357exit:
358 exception_exit(prev_state);
359 return;
360exit_trap:
361 /*
362 * This path out is for all the cases where we could not
363 * handle the exception in some way (like allocating a
364 * table or telling userspace about it. We will also end
365 * up here if the kernel has MPX turned off at compile
366 * time..
367 */
368 do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL);
369 exception_exit(prev_state);
370}
371
289dotraplinkage void 372dotraplinkage void
290do_general_protection(struct pt_regs *regs, long error_code) 373do_general_protection(struct pt_regs *regs, long error_code)
291{ 374{