]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/i386/exception.s
Mitigations for Microarchitectural Data Sampling.
[FreeBSD/FreeBSD.git] / sys / i386 / i386 / exception.s
1 /*-
2  * Copyright (c) 1989, 1990 William F. Jolitz.
3  * Copyright (c) 1990 The Regents of the University of California.
4  * Copyright (c) 2007 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * Portions of this software were developed by A. Joseph Koshy under
8  * sponsorship from the FreeBSD Foundation and Google, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD$
35  */
36
37 #include "opt_apic.h"
38 #include "opt_atpic.h"
39 #include "opt_hwpmc_hooks.h"
40
41 #include <machine/asmacros.h>
42 #include <machine/psl.h>
43 #include <machine/trap.h>
44
45 #include "assym.s"
46
47 #define SEL_RPL_MASK    0x0003
48 #define GSEL_KPL        0x0020  /* GSEL(GCODE_SEL, SEL_KPL) */
49
50 #ifdef KDTRACE_HOOKS
51         .bss
52         .globl  dtrace_invop_jump_addr
53         .align  4
54         .type   dtrace_invop_jump_addr, @object
55         .size   dtrace_invop_jump_addr, 4
56 dtrace_invop_jump_addr:
57         .zero   4
58         .globl  dtrace_invop_calltrap_addr
59         .align  4
60         .type   dtrace_invop_calltrap_addr, @object
61         .size   dtrace_invop_calltrap_addr, 4
62 dtrace_invop_calltrap_addr:
63         .zero   8
64 #endif
65         .text
66 #ifdef HWPMC_HOOKS
67         ENTRY(start_exceptions)
68 #endif
69 /*****************************************************************************/
70 /* Trap handling                                                             */
71 /*****************************************************************************/
72 /*
73  * Trap and fault vector routines.
74  *
75  * Most traps are 'trap gates', SDT_SYS386TGT.  A trap gate pushes state on
76  * the stack that mostly looks like an interrupt, but does not disable
77  * interrupts.  A few of the traps we are use are interrupt gates,
78  * SDT_SYS386IGT, which are nearly the same thing except interrupts are
79  * disabled on entry.
80  *
81  * The cpu will push a certain amount of state onto the kernel stack for
82  * the current process.  The amount of state depends on the type of trap
83  * and whether the trap crossed rings or not.  See i386/include/frame.h.
84  * At the very least the current EFLAGS (status register, which includes
85  * the interrupt disable state prior to the trap), the code segment register,
86  * and the return instruction pointer are pushed by the cpu.  The cpu
87  * will also push an 'error' code for certain traps.  We push a dummy
88  * error code for those traps where the cpu doesn't in order to maintain
89  * a consistent frame.  We also push a contrived 'trap number'.
90  *
91  * The cpu does not push the general registers, we must do that, and we
92  * must restore them prior to calling 'iret'.  The cpu adjusts the %cs and
93  * %ss segment registers, but does not mess with %ds, %es, or %fs.  Thus we
94  * must load them with appropriate values for supervisor mode operation.
95  */
96
97 MCOUNT_LABEL(user)
98 MCOUNT_LABEL(btrap)
99
100 #define TRAP(a)         pushl $(a) ; jmp alltraps
101
102 IDTVEC(div)
103         pushl $0; TRAP(T_DIVIDE)
104 IDTVEC(dbg)
105         pushl $0; TRAP(T_TRCTRAP)
106 IDTVEC(nmi)
107         pushl $0; TRAP(T_NMI)
108 IDTVEC(bpt)
109         pushl $0; TRAP(T_BPTFLT)
110 IDTVEC(dtrace_ret)
111         pushl $0; TRAP(T_DTRACE_RET)
112 IDTVEC(ofl)
113         pushl $0; TRAP(T_OFLOW)
114 IDTVEC(bnd)
115         pushl $0; TRAP(T_BOUND)
116 #ifndef KDTRACE_HOOKS
117 IDTVEC(ill)
118         pushl $0; TRAP(T_PRIVINFLT)
119 #endif
120 IDTVEC(dna)
121         pushl $0; TRAP(T_DNA)
122 IDTVEC(fpusegm)
123         pushl $0; TRAP(T_FPOPFLT)
124 IDTVEC(tss)
125         TRAP(T_TSSFLT)
126 IDTVEC(missing)
127         TRAP(T_SEGNPFLT)
128 IDTVEC(stk)
129         TRAP(T_STKFLT)
130 IDTVEC(prot)
131         TRAP(T_PROTFLT)
132 IDTVEC(page)
133         TRAP(T_PAGEFLT)
134 IDTVEC(mchk)
135         pushl $0; TRAP(T_MCHK)
136 IDTVEC(rsvd_pti)
137 IDTVEC(rsvd)
138         pushl $0; TRAP(T_RESERVED)
139 IDTVEC(fpu)
140         pushl $0; TRAP(T_ARITHTRAP)
141 IDTVEC(align)
142         TRAP(T_ALIGNFLT)
143 IDTVEC(xmm)
144         pushl $0; TRAP(T_XMMFLT)
145
146         /*
147          * All traps except ones for syscalls jump to alltraps.  If
148          * interrupts were enabled when the trap occurred, then interrupts
149          * are enabled now if the trap was through a trap gate, else
150          * disabled if the trap was through an interrupt gate.  Note that
151          * int0x80_syscall is a trap gate.   Interrupt gates are used by
152          * page faults, non-maskable interrupts, debug and breakpoint
153          * exceptions.
154          */
155         SUPERALIGN_TEXT
156         .globl  alltraps
157         .type   alltraps,@function
158 alltraps:
159         pushal
160         pushl   $0
161         movw    %ds,(%esp)
162         pushl   $0
163         movw    %es,(%esp)
164         pushl   $0
165         movw    %fs,(%esp)
166 alltraps_with_regs_pushed:
167         SET_KERNEL_SREGS
168         cld
169         FAKE_MCOUNT(TF_EIP(%esp))
170 calltrap:
171         pushl   %esp
172         call    trap
173         add     $4, %esp
174
175         /*
176          * Return via doreti to handle ASTs.
177          */
178         MEXITCOUNT
179         jmp     doreti
180
181 /*
182  * Privileged instruction fault.
183  */
184 #ifdef KDTRACE_HOOKS
185         SUPERALIGN_TEXT
186 IDTVEC(ill)
187         /*
188          * Check if a DTrace hook is registered.  The default (data) segment
189          * cannot be used for this since %ds is not known good until we
190          * verify that the entry was from kernel mode.
191          */
192         cmpl    $0,%ss:dtrace_invop_jump_addr
193         je      norm_ill
194
195         /*
196          * Check if this is a user fault.  If so, just handle it as a normal
197          * trap.
198          */
199         cmpl    $GSEL_KPL, 4(%esp)      /* Check the code segment */
200         jne     norm_ill
201         testl   $PSL_VM, 8(%esp)        /* and vm86 mode. */
202         jnz     norm_ill
203
204         /*
205          * This is a kernel instruction fault that might have been caused
206          * by a DTrace provider.
207          */
208         pushal
209         cld
210
211         /*
212          * Set our jump address for the jump back in the event that
213          * the exception wasn't caused by DTrace at all.
214          */
215         movl    $norm_ill, dtrace_invop_calltrap_addr
216
217         /* Jump to the code hooked in by DTrace. */
218         jmpl    *dtrace_invop_jump_addr
219
220         /*
221          * Process the instruction fault in the normal way.
222          */
223 norm_ill:
224         pushl $0
225         TRAP(T_PRIVINFLT)
226 #endif
227
228 /*
229  * Call gate entry for syscalls (lcall 7,0).
230  * This is used by FreeBSD 1.x a.out executables and "old" NetBSD executables.
231  *
232  * The intersegment call has been set up to specify one dummy parameter.
233  * This leaves a place to put eflags so that the call frame can be
234  * converted to a trap frame. Note that the eflags is (semi-)bogusly
235  * pushed into (what will be) tf_err and then copied later into the
236  * final spot. It has to be done this way because esp can't be just
237  * temporarily altered for the pushfl - an interrupt might come in
238  * and clobber the saved cs/eip.
239  */
240         SUPERALIGN_TEXT
241 IDTVEC(lcall_syscall)
242         pushfl                          /* save eflags */
243         popl    8(%esp)                 /* shuffle into tf_eflags */
244         pushl   $7                      /* sizeof "lcall 7,0" */
245         pushl   $0                      /* tf_trapno */
246         pushal
247         pushl   $0
248         movw    %ds,(%esp)
249         pushl   $0
250         movw    %es,(%esp)
251         pushl   $0
252         movw    %fs,(%esp)
253         SET_KERNEL_SREGS
254         cld
255         FAKE_MCOUNT(TF_EIP(%esp))
256         pushl   %esp
257         call    syscall
258         add     $4, %esp
259         MEXITCOUNT
260         jmp     doreti
261
262 /*
263  * Trap gate entry for syscalls (int 0x80).
264  * This is used by FreeBSD ELF executables, "new" NetBSD executables, and all
265  * Linux executables.
266  *
267  * Even though the name says 'int0x80', this is actually a trap gate, not an
268  * interrupt gate.  Thus interrupts are enabled on entry just as they are for
269  * a normal syscall.
270  */
271         SUPERALIGN_TEXT
272 IDTVEC(int0x80_syscall)
273         pushl   $2                      /* sizeof "int 0x80" */
274         pushl   $0                      /* tf_trapno */
275         pushal
276         pushl   $0
277         movw    %ds,(%esp)
278         pushl   $0
279         movw    %es,(%esp)
280         pushl   $0
281         movw    %fs,(%esp)
282         SET_KERNEL_SREGS
283         cld
284         FAKE_MCOUNT(TF_EIP(%esp))
285         pushl   %esp
286         call    syscall
287         add     $4, %esp
288         MEXITCOUNT
289         jmp     doreti
290
291 ENTRY(fork_trampoline)
292         pushl   %esp                    /* trapframe pointer */
293         pushl   %ebx                    /* arg1 */
294         pushl   %esi                    /* function */
295         call    fork_exit
296         addl    $12,%esp
297         /* cut from syscall */
298
299         /*
300          * Return via doreti to handle ASTs.
301          */
302         MEXITCOUNT
303         jmp     doreti
304
305
306 /*
307  * To efficiently implement classification of trap and interrupt handlers
308  * for profiling, there must be only trap handlers between the labels btrap
309  * and bintr, and only interrupt handlers between the labels bintr and
310  * eintr.  This is implemented (partly) by including files that contain
311  * some of the handlers.  Before including the files, set up a normal asm
312  * environment so that the included files doen't need to know that they are
313  * included.
314  */
315
316         .data
317         .p2align 4
318         .text
319         SUPERALIGN_TEXT
320 MCOUNT_LABEL(bintr)
321
322 #ifdef DEV_ATPIC
323 #include <i386/i386/atpic_vector.s>
324 #endif
325
326 #if defined(DEV_APIC) && defined(DEV_ATPIC)
327         .data
328         .p2align 4
329         .text
330         SUPERALIGN_TEXT
331 #endif
332
333 #ifdef DEV_APIC
334 #include <i386/i386/apic_vector.s>
335 #endif
336
337         .data
338         .p2align 4
339         .text
340         SUPERALIGN_TEXT
341 #include <i386/i386/vm86bios.s>
342
343         .text
344 MCOUNT_LABEL(eintr)
345
346 /*
347  * void doreti(struct trapframe)
348  *
349  * Handle return from interrupts, traps and syscalls.
350  */
351         .text
352         SUPERALIGN_TEXT
353         .type   doreti,@function
354         .globl  doreti
355 doreti:
356         FAKE_MCOUNT($bintr)             /* init "from" bintr -> doreti */
357 doreti_next:
358         /*
359          * Check if ASTs can be handled now.  ASTs cannot be safely
360          * processed when returning from an NMI.
361          */
362         cmpb    $T_NMI,TF_TRAPNO(%esp)
363 #ifdef HWPMC_HOOKS
364         je      doreti_nmi
365 #else
366         je      doreti_exit
367 #endif
368         /*
369          * PSL_VM must be checked first since segment registers only
370          * have an RPL in non-VM86 mode.
371          * ASTs can not be handled now if we are in a vm86 call.
372          */
373         testl   $PSL_VM,TF_EFLAGS(%esp)
374         jz      doreti_notvm86
375         movl    PCPU(CURPCB),%ecx
376         testl   $PCB_VM86CALL,PCB_FLAGS(%ecx)
377         jz      doreti_ast
378         jmp     doreti_exit
379
380 doreti_notvm86:
381         testb   $SEL_RPL_MASK,TF_CS(%esp) /* are we returning to user mode? */
382         jz      doreti_exit             /* can't handle ASTs now if not */
383
384 doreti_ast:
385         /*
386          * Check for ASTs atomically with returning.  Disabling CPU
387          * interrupts provides sufficient locking even in the SMP case,
388          * since we will be informed of any new ASTs by an IPI.
389          */
390         cli
391         movl    PCPU(CURTHREAD),%eax
392         testl   $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%eax)
393         je      doreti_exit
394         sti
395         pushl   %esp                    /* pass a pointer to the trapframe */
396         call    ast
397         add     $4,%esp
398         jmp     doreti_ast
399
400         /*
401          * doreti_exit: pop registers, iret.
402          *
403          *      The segment register pop is a special case, since it may
404          *      fault if (for example) a sigreturn specifies bad segment
405          *      registers.  The fault is handled in trap.c.
406          */
407 doreti_exit:
408         MEXITCOUNT
409         call    *mds_handler
410
411         .globl  doreti_popl_fs
412 doreti_popl_fs:
413         popl    %fs
414         .globl  doreti_popl_es
415 doreti_popl_es:
416         popl    %es
417         .globl  doreti_popl_ds
418 doreti_popl_ds:
419         popl    %ds
420         popal
421         addl    $8,%esp
422         .globl  doreti_iret
423 doreti_iret:
424         iret
425
426         /*
427          * doreti_iret_fault and friends.  Alternative return code for
428          * the case where we get a fault in the doreti_exit code
429          * above.  trap() (i386/i386/trap.c) catches this specific
430          * case, and continues in the corresponding place in the code
431          * below.
432          *
433          * If the fault occured during return to usermode, we recreate
434          * the trap frame and call trap() to send a signal.  Otherwise
435          * the kernel was tricked into fault by attempt to restore invalid
436          * usermode segment selectors on return from nested fault or
437          * interrupt, where interrupted kernel entry code not yet loaded
438          * kernel selectors.  In the latter case, emulate iret and zero
439          * the invalid selector.
440          */
441         ALIGN_TEXT
442         .globl  doreti_iret_fault
443 doreti_iret_fault:
444         subl    $8,%esp
445         pushal
446         pushl   $0
447         movw    %ds,(%esp)
448         .globl  doreti_popl_ds_fault
449 doreti_popl_ds_fault:
450         testb   $SEL_RPL_MASK,TF_CS-TF_DS(%esp)
451         jz      doreti_popl_ds_kfault
452         pushl   $0
453         movw    %es,(%esp)
454         .globl  doreti_popl_es_fault
455 doreti_popl_es_fault:
456         testb   $SEL_RPL_MASK,TF_CS-TF_ES(%esp)
457         jz      doreti_popl_es_kfault
458         pushl   $0
459         movw    %fs,(%esp)
460         .globl  doreti_popl_fs_fault
461 doreti_popl_fs_fault:
462         testb   $SEL_RPL_MASK,TF_CS-TF_FS(%esp)
463         jz      doreti_popl_fs_kfault
464         sti
465         movl    $0,TF_ERR(%esp) /* XXX should be the error code */
466         movl    $T_PROTFLT,TF_TRAPNO(%esp)
467         jmp     alltraps_with_regs_pushed
468
469 doreti_popl_ds_kfault:
470         movl    $0,(%esp)
471         jmp     doreti_popl_ds
472 doreti_popl_es_kfault:
473         movl    $0,(%esp)
474         jmp     doreti_popl_es
475 doreti_popl_fs_kfault:
476         movl    $0,(%esp)
477         jmp     doreti_popl_fs
478         
479 #ifdef HWPMC_HOOKS
480 doreti_nmi:
481         /*
482          * Since we are returning from an NMI, check if the current trap
483          * was from user mode and if so whether the current thread
484          * needs a user call chain capture.
485          */
486         testb   $SEL_RPL_MASK,TF_CS(%esp)
487         jz      doreti_exit
488         movl    PCPU(CURTHREAD),%eax    /* curthread present? */
489         orl     %eax,%eax
490         jz      doreti_exit
491         testl   $TDP_CALLCHAIN,TD_PFLAGS(%eax) /* flagged for capture? */
492         jz      doreti_exit
493         /*
494          * Take the processor out of NMI mode by executing a fake "iret".
495          */
496         pushfl
497         pushl   %cs
498         pushl   $outofnmi
499         iret
500 outofnmi:
501         /*
502          * Call the callchain capture hook after turning interrupts back on.
503          */
504         movl    pmc_hook,%ecx
505         orl     %ecx,%ecx
506         jz      doreti_exit
507         pushl   %esp                    /* frame pointer */
508         pushl   $PMC_FN_USER_CALLCHAIN  /* command */
509         movl    PCPU(CURTHREAD),%eax
510         pushl   %eax                    /* curthread */
511         sti
512         call    *%ecx
513         addl    $12,%esp
514         jmp     doreti_ast
515         ENTRY(end_exceptions)
516 #endif