2 * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
61 #include <i386/eflags.h>
62 #include <i386/trap.h>
63 #include <i386/rtclock_asm.h>
64 #define _ARCH_I386_ASM_HELP_H_ /* Prevent inclusion of user header */
65 #include <mach/i386/syscall_sw.h>
66 #include <i386/postcode.h>
67 #include <i386/proc_reg.h>
68 #include <mach/exception_types.h>
71 * Low-memory handlers.
73 #define LO_ALLINTRS EXT(lo_allintrs32)
74 #define LO_ALLTRAPS EXT(lo_alltraps32)
75 #define LO_SYSENTER EXT(lo_sysenter32)
76 #define LO_UNIX_SCALL EXT(lo_unix_scall32)
77 #define LO_MACH_SCALL EXT(lo_mach_scall32)
78 #define LO_MDEP_SCALL EXT(lo_mdep_scall32)
79 #define LO_DIAG_SCALL EXT(lo_diag_scall32)
82 #define HI_DATA(lo_addr) ( (EXT(lo_addr) - EXT(hi_remap_data)) + HIGH_IDT_BASE )
83 #define HI_TEXT(lo_text) ( (EXT(lo_text) - EXT(hi_remap_text)) + HIGH_MEM_BASE )
86 * Interrupt descriptor table and code vectors for it.
88 #define IDT_BASE_ENTRY(vec,seg,type) \
90 .long EXT(vec) - EXT(hi_remap_text) + HIGH_MEM_BASE ; \
96 #define IDT_BASE_ENTRY_INT(vec,seg,type) \
98 .long vec - EXT(hi_remap_text) + HIGH_MEM_BASE ; \
104 #define IDT_BASE_ENTRY_TG(vec,seg,type) \
112 #define IDT_ENTRY(vec,type) IDT_BASE_ENTRY(vec,KERNEL32_CS,type)
113 #define IDT_ENTRY_INT(vec,type) IDT_BASE_ENTRY_INT(vec,KERNEL32_CS,type)
116 * No error code. Clear error code and push trap number.
118 #define EXCEPTION(n,name) \
119 IDT_ENTRY(name,K_INTR_GATE);\
124 movl $(LO_ALLTRAPS),%ebx ;\
129 * Interrupt from user. Clear error code and push trap number.
131 #define EXCEP_USR(n,name) \
132 IDT_ENTRY(name,U_INTR_GATE);\
137 movl $(LO_ALLTRAPS),%ebx ;\
142 * Special interrupt code.
144 #define EXCEP_SPC(n,name) \
145 IDT_ENTRY(name,K_INTR_GATE)
148 * Special interrupt code from user.
150 #define EXCEP_SPC_USR(n,name) \
151 IDT_ENTRY(name,U_INTR_GATE)
155 * Extra-special interrupt code. Note that no offset may be
156 * specified in a task gate descriptor, so name is ignored.
158 #define EXCEP_TASK(n,name) \
159 IDT_BASE_ENTRY_TG(0,DEBUG_TSS,K_TASK_GATE)
161 /* Double-fault fatal handler */
162 #define DF_FATAL_TASK(n,name) \
163 IDT_BASE_ENTRY_TG(0,DF_TSS,K_TASK_GATE)
165 /* machine-check handler */
166 #define MC_FATAL_TASK(n,name) \
167 IDT_BASE_ENTRY_TG(0,MC_TSS,K_TASK_GATE)
170 * Error code has been pushed. Push trap number.
172 #define EXCEP_ERR(n,name) \
173 IDT_ENTRY(name,K_INTR_GATE) ;\
177 movl $(LO_ALLTRAPS),%ebx ;\
184 #define INTERRUPT(n) \
185 IDT_ENTRY_INT(L_ ## n,K_INTR_GATE) ;\
191 movl $(LO_ALLINTRS),%ebx ;\
203 EXCEPTION(0x00,t_zero_div)
204 EXCEP_SPC(0x01,hi_debug)
205 INTERRUPT(0x02) /* NMI */
206 EXCEP_USR(0x03,t_int3)
207 EXCEP_USR(0x04,t_into)
208 EXCEP_USR(0x05,t_bounds)
209 EXCEPTION(0x06,t_invop)
210 EXCEPTION(0x07,t_nofpu)
212 EXCEP_TASK(0x08,db_task_dbl_fault)
214 DF_FATAL_TASK(0x08,df_task_start)
216 EXCEPTION(0x09,a_fpu_over)
217 EXCEPTION(0x0a,a_inv_tss)
218 EXCEP_SPC(0x0b,hi_segnp)
220 EXCEP_TASK(0x0c,db_task_stk_fault)
222 EXCEP_ERR(0x0c,t_stack_fault)
224 EXCEP_SPC(0x0d,hi_gen_prot)
225 EXCEP_SPC(0x0e,hi_page_fault)
226 EXCEPTION(0x0f,t_trap_0f)
227 EXCEPTION(0x10,t_fpu_err)
228 EXCEPTION(0x11,t_trap_11)
229 MC_FATAL_TASK(0x12,mc_task_start)
230 EXCEPTION(0x13,t_sse_err)
231 EXCEPTION(0x14,t_trap_14)
232 EXCEPTION(0x15,t_trap_15)
233 EXCEPTION(0x16,t_trap_16)
234 EXCEPTION(0x17,t_trap_17)
235 EXCEPTION(0x18,t_trap_18)
236 EXCEPTION(0x19,t_trap_19)
237 EXCEPTION(0x1a,t_trap_1a)
238 EXCEPTION(0x1b,t_trap_1b)
239 EXCEPTION(0x1c,t_trap_1c)
240 EXCEPTION(0x1d,t_trap_1d)
241 EXCEPTION(0x1e,t_trap_1e)
242 EXCEPTION(0x1f,t_trap_1f)
344 EXCEP_USR(0x7f, t_dtrace_ret)
346 EXCEP_SPC_USR(0x80,hi_unix_scall)
347 EXCEP_SPC_USR(0x81,hi_mach_scall)
348 EXCEP_SPC_USR(0x82,hi_mdep_scall)
349 EXCEP_SPC_USR(0x83,hi_diag_scall)
481 EXCEPTION(0xff,t_preempt)
493 * Trap/interrupt entry points.
495 * All traps must create the following save area on the PCB "stack":
504 * cr2 if page fault - otherwise unused
514 * user esp - if from user
515 * user ss - if from user
520 1: .long HI_TEXT(hi_ret_to_kernel)
524 1: .long HI_TEXT(hi_ret_to_user)
526 Entry(hi_ret_to_user)
528 movl %gs:CPU_ACTIVE_THREAD,%ecx
529 subl TH_PCB_ISS(%ecx),%ebx
530 movl $(WINDOWS_CLEAN),TH_COPYIO_STATE(%ecx)
532 movl TH_PCB_IDS(%ecx),%eax /* get debug state struct */
533 cmpl $0,%eax /* is there a debug state */
534 je 1f /* branch if not */
535 movl DS_DR0(%eax), %ecx /* Load the 32 bit debug registers */
537 movl DS_DR1(%eax), %ecx
539 movl DS_DR2(%eax), %ecx
541 movl DS_DR3(%eax), %ecx
543 movl DS_DR7(%eax), %eax
545 addl %gs:CPU_HI_ISS,%ebx /* rebase PCB save area to high addr */
546 movl %gs:CPU_TASK_CR3,%ecx
547 movl %ecx,%gs:CPU_ACTIVE_CR3
548 movl %ebx,%esp /* switch to hi based PCB stack */
549 movl %ecx,%cr3 /* switch to user's address space */
551 cmpl $0,%eax /* is dr7 set to something? */
552 je 2f /* branch if not */
553 movl %eax,%db7 /* Set dr7 */
556 Entry(hi_ret_to_kernel)
558 popl %eax /* ignore flavor of saved state */
560 popl %gs /* restore segment registers */
568 popa /* restore general registers */
569 addl $8,%esp /* discard trap number and error code */
571 cmpl $(SYSENTER_CS),4(%esp) /* test for fast entry/exit */
574 iret /* return from interrupt */
576 popl %edx /* user return eip */
577 popl %ecx /* pop and toss cs */
578 andl $(~EFL_IF),(%esp) /* clear intrs enabled, see sti below */
579 popf /* flags - carry denotes failure */
580 popl %ecx /* user return esp */
581 sti /* interrupts enabled after sysexit */
586 pushl %eax /* save system call number */
587 pushl $0 /* clear trap number slot */
588 pusha /* save the general registers */
589 movl $(LO_UNIX_SCALL),%ebx
594 pushl %eax /* save system call number */
595 pushl $0 /* clear trap number slot */
596 pusha /* save the general registers */
597 movl $(LO_MACH_SCALL),%ebx
602 pushl %eax /* save system call number */
603 pushl $0 /* clear trap number slot */
604 pusha /* save the general registers */
605 movl $(LO_MDEP_SCALL),%ebx
610 pushl %eax // Save sselector
611 pushl $0 // Clear trap number slot
612 pusha // save the general registers
613 movl $(LO_DIAG_SCALL),%ebx // Get the function down low to transfer to
614 jmp enter_lohandler // Leap to it...
618 * sysenter entry point
619 * Requires user code to set up:
620 * edx: user instruction pointer (return address)
621 * ecx: user stack pointer
622 * on which is pushed stub ret addr and saved ebx
623 * Return to user-space is made using sysexit.
624 * Note: sysenter/sysexit cannot be used for calls returning a value in edx,
625 * or requiring ecx to be preserved.
628 movl (%esp), %esp /* switch from intr stack to pcb */
630 * Push values on to the PCB stack
631 * to cons up the saved state.
633 pushl $(USER_DS) /* ss */
634 pushl %ecx /* uesp */
637 * Clear, among others, the Nested Task (NT) flags bit;
638 * This is cleared by INT, but not by SYSENTER.
642 pushl $(SYSENTER_CS) /* cs */
645 pushl %eax /* err/eax - syscall code */
646 pushl $0 /* clear trap number slot */
647 pusha /* save the general registers */
648 orl $(EFL_IF),R32_EFLAGS-R32_EDI(%esp) /* (edi was last reg pushed) */
649 movl $(LO_SYSENTER),%ebx
655 pushl $(SS_32) /* 32-bit state flavor */
660 mov %eax,%es /* switch to kernel data seg */
661 mov $(CPU_DATA_GS),%eax
663 cld /* clear direction flag */
665 * Switch to kernel's address space if necessary
667 movl HI_DATA(lo_kernel_cr3),%ecx
672 movl %ecx,%gs:CPU_ACTIVE_CR3
674 testb $3,R32_CS(%esp)
676 movl %esp,%edx /* came from user mode */
678 subl %gs:CPU_HI_ISS,%edx
679 movl %gs:CPU_ACTIVE_THREAD,%ecx
680 addl TH_PCB_ISS(%ecx),%edx /* rebase the high stack to a low address */
682 cmpl $0, TH_PCB_IDS(%ecx) /* Is there a debug register state? */
684 movl $0, %ecx /* If so, reset DR7 (the control) */
687 movl R32_TRAPNO(%esp),%ecx // Get the interrupt vector
688 addl $1,%gs:hwIntCnt(,%ecx,4) // Bump the count
693 * Page fault traps save cr2.
696 pushl $(T_PAGE_FAULT) /* mark a page fault trap */
697 pusha /* save the general registers */
698 movl %cr2,%eax /* get the faulting address */
699 movl %eax,R32_CR2-R32_EDI(%esp)/* save in esp save slot */
701 movl $(LO_ALLTRAPS),%ebx
707 * Debug trap. Check for single-stepping across system call into
708 * kernel. If this is the case, taking the debug trap has turned
709 * off single-stepping - save the flags register with the trace
715 /* trap came from kernel mode */
716 cmpl $(HI_TEXT(hi_mach_scall)),(%esp)
718 addl $12,%esp /* remove eip/cs/eflags from debug_trap */
719 jmp EXT(hi_mach_scall) /* continue system call entry */
721 cmpl $(HI_TEXT(hi_mdep_scall)),(%esp)
723 addl $12,%esp /* remove eip/cs/eflags from debug_trap */
724 jmp EXT(hi_mdep_scall) /* continue system call entry */
726 cmpl $(HI_TEXT(hi_unix_scall)),(%esp)
728 addl $12,%esp /* remove eip/cs/eflags from debug_trap */
729 jmp EXT(hi_unix_scall) /* continue system call entry */
731 cmpl $(HI_TEXT(hi_sysenter)),(%esp)
734 * eip/cs/flags have been pushed on intr stack
735 * We have to switch to pcb stack and copy eflags.
736 * Note: setting the cs selector to SYSENTER_TF_CS
737 * will cause the return to user path to take the iret path so
738 * that eflags (containing the trap bit) is set atomically.
739 * In unix_syscall this is tested so that we'll rewind the pc
740 * to account for with sysenter or int entry.
742 addl $8,%esp /* remove eip/cs */
743 pushl %ecx /* save %ecx */
744 movl 8(%esp),%ecx /* top of intr stack -> pcb stack */
745 xchgl %ecx,%esp /* switch to pcb stack */
746 pushl $(USER_DS) /* ss */
747 pushl %ss:(%ecx) /* %ecx into uesp slot */
748 pushl %ss:4(%ecx) /* eflags */
749 movl %ss:(%ecx),%ecx /* restore %ecx */
750 pushl $(SYSENTER_TF_CS) /* cs - not SYSENTER_CS for iret path */
751 jmp hi_sysenter_2 /* continue sysenter entry */
754 pushl $(T_DEBUG) /* handle as user trap */
755 pusha /* save the general registers */
756 movl $(LO_ALLTRAPS),%ebx
762 * General protection or segment-not-present fault.
763 * Check for a GP/NP fault in the kernel_return
764 * sequence; if there, report it as a GP/NP fault on the user's instruction.
766 * esp-> 0: trap code (NP or GP)
767 * 4: segment number in error
771 * 20 old registers (trap is from kernel)
774 pushl $(T_GENERAL_PROTECTION) /* indicate fault type */
775 jmp trap_check_kernel_exit /* check for kernel exit sequence */
778 pushl $(T_SEGMENT_NOT_PRESENT)
779 /* indicate fault type */
780 trap_check_kernel_exit:
783 /* trap was from kernel mode, so */
784 /* check for the kernel exit sequence */
785 cmpl $(HI_TEXT(ret_iret)),8(%esp) /* on IRET? */
787 cmpl $(HI_TEXT(ret_popl_ds)),8(%esp) /* popping DS? */
789 cmpl $(HI_TEXT(ret_popl_es)),8(%esp) /* popping ES? */
791 cmpl $(HI_TEXT(ret_popl_fs)),8(%esp) /* popping FS? */
793 cmpl $(HI_TEXT(ret_popl_gs)),8(%esp) /* popping GS? */
796 pusha /* save the general registers */
797 movl $(LO_ALLTRAPS),%ebx
802 * GP/NP fault on IRET: CS or SS is in error.
803 * All registers contain the user's values.
818 movl %eax,8(%esp) /* save eax (we don`t need saved eip) */
819 popl %eax /* get trap number */
820 movl %eax,12-4(%esp) /* put in user trap number */
821 popl %eax /* get error code */
822 movl %eax,16-8(%esp) /* put in user errcode */
823 popl %eax /* restore eax */
824 /* now treat as fault from user */
825 pusha /* save the general registers */
826 movl $(LO_ALLTRAPS),%ebx
830 * Fault restoring a segment register. The user's registers are still
831 * saved on the stack. The offending segment register has not been
835 popl %eax /* get trap number */
836 popl %edx /* get error code */
837 addl $12,%esp /* pop stack to user regs */
838 jmp push_es /* (DS on top of stack) */
840 popl %eax /* get trap number */
841 popl %edx /* get error code */
842 addl $12,%esp /* pop stack to user regs */
843 jmp push_fs /* (ES on top of stack) */
845 popl %eax /* get trap number */
846 popl %edx /* get error code */
847 addl $12,%esp /* pop stack to user regs */
848 jmp push_gs /* (FS on top of stack) */
850 popl %eax /* get trap number */
851 popl %edx /* get error code */
852 addl $12,%esp /* pop stack to user regs */
853 jmp push_none /* (GS on top of stack) */
856 pushl %es /* restore es, */
858 pushl %fs /* restore fs, */
860 pushl %gs /* restore gs. */
862 pushl $(SS_32) /* 32-bit state flavor */
863 movl %eax,R32_TRAPNO(%esp) /* set trap number */
864 movl %edx,R32_ERR(%esp) /* set error code */
865 /* now treat as fault from user */
866 /* except that segment registers are */
868 movl $(LO_ALLTRAPS),%ebx
875 Entry(hi_remap_etext)
879 * All 32 bit task 'exceptions' enter lo_alltraps:
880 * esp -> x86_saved_state_t
882 * The rest of the state is set up as:
883 * cr3 -> kernel directory
884 * esp -> low based stack
887 * ss/ds/es -> KERNEL_DS
889 * interrupts disabled
890 * direction flag cleared
893 movl R32_CS(%esp),%eax /* assume 32-bit state */
894 cmpl $(SS_64),SS_FLAVOR(%esp)/* 64-bit? */
896 movl R64_CS(%esp),%eax /* 64-bit user mode */
903 movl %gs:CPU_ACTIVE_THREAD,%ecx
904 movl TH_TASK(%ecx),%ebx
906 /* Check for active vtimers in the current task */
907 TASK_VTIMER_CHECK(%ebx, %ecx)
909 movl %gs:CPU_KERNEL_STACK,%ebx
910 xchgl %ebx,%esp /* switch to kernel stack */
912 CCALL1(user_trap, %ebx) /* call user trap routine */
913 /* user_trap() unmasks interrupts */
914 cli /* hold off intrs - critical section */
915 xorl %ecx,%ecx /* don't check if we're in the PFZ */
918 * Return from trap or system call, checking for ASTs.
919 * On lowbase PCB stack with intrs disabled
921 Entry(return_from_trap32)
922 movl %gs:CPU_ACTIVE_THREAD, %esp
923 movl TH_PCB_ISS(%esp), %esp /* switch back to PCB stack */
924 movl %gs:CPU_PENDING_AST, %eax
926 je EXT(return_to_user) /* branch if no AST */
927 LEXT(return_from_trap_with_ast)
928 movl %gs:CPU_KERNEL_STACK, %ebx
929 xchgl %ebx, %esp /* switch to kernel stack */
931 testl %ecx, %ecx /* see if we need to check for an EIP in the PFZ */
932 je 2f /* no, go handle the AST */
933 cmpl $(SS_64), SS_FLAVOR(%ebx) /* are we a 64-bit task? */
935 /* no... 32-bit user mode */
936 movl R32_EIP(%ebx), %eax
937 pushl %ebx /* save PCB stack */
938 xorl %ebp, %ebp /* clear frame pointer */
939 CCALL1(commpage_is_in_pfz32, %eax)
940 popl %ebx /* retrieve pointer to PCB stack */
942 je 2f /* not in the PFZ... go service AST */
943 movl %eax, R32_EBX(%ebx) /* let the PFZ know we've pended an AST */
944 xchgl %ebx, %esp /* switch back to PCB stack */
945 jmp EXT(return_to_user)
946 1: /* 64-bit user mode */
947 movl R64_RIP(%ebx), %ecx
948 movl R64_RIP+4(%ebx), %eax
949 pushl %ebx /* save PCB stack */
950 xorl %ebp, %ebp /* clear frame pointer */
951 CCALL2(commpage_is_in_pfz64, %ecx, %eax)
952 popl %ebx /* retrieve pointer to PCB stack */
954 je 2f /* not in the PFZ... go service AST */
955 movl %eax, R64_RBX(%ebx) /* let the PFZ know we've pended an AST */
956 xchgl %ebx, %esp /* switch back to PCB stack */
957 jmp EXT(return_to_user)
959 sti /* interrupts always enabled on return to user mode */
960 xorl %ebp, %ebp /* Clear framepointer */
961 CCALL1(i386_astintr, $0) /* take the AST */
963 xorl %ecx, %ecx /* don't check if we're in the PFZ */
964 jmp EXT(return_from_trap32) /* and check again (rare) */
968 * Trap from kernel mode. No need to switch stacks.
969 * Interrupts must be off here - we will set them to state at time of trap
970 * as soon as it's safe for us to do so and not recurse doing preemption
973 movl %esp, %eax /* saved state addr */
974 pushl R32_EIP(%esp) /* Simulate a CALL from fault point */
975 pushl %ebp /* Extend framepointer chain */
977 CCALL1WITHSP(kernel_trap, %eax) /* Call kernel trap handler */
982 movl %gs:CPU_PENDING_AST,%eax /* get pending asts */
983 testl $ AST_URGENT,%eax /* any urgent preemption? */
984 je ret_to_kernel /* no, nothing to do */
985 cmpl $ T_PREEMPT,R32_TRAPNO(%esp)
986 je ret_to_kernel /* T_PREEMPT handled in kernel_trap() */
987 testl $ EFL_IF,R32_EFLAGS(%esp) /* interrupts disabled? */
989 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption disabled? */
991 movl %gs:CPU_KERNEL_STACK,%eax
994 and EXT(kernel_stack_mask),%ecx
995 testl %ecx,%ecx /* are we on the kernel stack? */
996 jne ret_to_kernel /* no, skip it */
998 CCALL1(i386_astintr, $1) /* take the AST */
1004 * All interrupts on all tasks enter here with:
1005 * esp-> -> x86_saved_state_t
1007 * cr3 -> kernel directory
1008 * esp -> low based stack
1011 * ss/ds/es -> KERNEL_DS
1013 * interrupts disabled
1014 * direction flag cleared
1016 Entry(lo_allintrs32)
1018 * test whether already on interrupt stack
1020 movl %gs:CPU_INT_STACK_TOP,%ecx
1023 leal -INTSTACK_SIZE(%ecx),%edx
1025 jb int_from_intstack
1027 xchgl %ecx,%esp /* switch to interrupt stack */
1029 movl %cr0,%eax /* get cr0 */
1030 orl $(CR0_TS),%eax /* or in TS bit */
1031 movl %eax,%cr0 /* set cr0 */
1033 subl $8, %esp /* for 16-byte stack alignment */
1034 pushl %ecx /* save pointer to old stack */
1035 movl %ecx,%gs:CPU_INT_STATE /* save intr state */
1037 TIME_INT_ENTRY /* do timing */
1039 movl %gs:CPU_ACTIVE_THREAD,%ecx
1040 movl TH_TASK(%ecx),%ebx
1042 /* Check for active vtimers in the current task */
1043 TASK_VTIMER_CHECK(%ebx, %ecx)
1045 incl %gs:CPU_PREEMPTION_LEVEL
1046 incl %gs:CPU_INTERRUPT_LEVEL
1048 movl %gs:CPU_INT_STATE, %eax
1049 CCALL1(interrupt, %eax) /* call generic interrupt routine */
1051 cli /* just in case we returned with intrs enabled */
1053 movl %eax,%gs:CPU_INT_STATE /* clear intr state pointer */
1055 decl %gs:CPU_INTERRUPT_LEVEL
1056 decl %gs:CPU_PREEMPTION_LEVEL
1058 TIME_INT_EXIT /* do timing */
1060 movl %gs:CPU_ACTIVE_THREAD,%eax
1061 movl TH_PCB_FPS(%eax),%eax /* get pcb's ifps */
1062 testl %eax, %eax /* Is there a context */
1063 je 1f /* Branch if not */
1064 cmpl $0, FP_VALID(%eax) /* Check fp_valid */
1065 jne 1f /* Branch if valid */
1069 movl %cr0,%eax /* get cr0 */
1070 orl $(CR0_TS),%eax /* or in TS bit */
1071 movl %eax,%cr0 /* set cr0 */
1073 popl %esp /* switch back to old stack */
1075 /* Load interrupted code segment into %eax */
1076 movl R32_CS(%esp),%eax /* assume 32-bit state */
1077 cmpl $(SS_64),SS_FLAVOR(%esp)/* 64-bit? */
1079 movl R64_CS(%esp),%eax /* 64-bit user mode */
1081 testb $3,%al /* user mode, */
1082 jnz ast_from_interrupt_user /* go handle potential ASTs */
1084 * we only want to handle preemption requests if
1085 * the interrupt fell in the kernel context
1086 * and preemption isn't disabled
1088 movl %gs:CPU_PENDING_AST,%eax
1089 testl $ AST_URGENT,%eax /* any urgent requests? */
1090 je ret_to_kernel /* no, nothing to do */
1092 cmpl $0,%gs:CPU_PREEMPTION_LEVEL /* preemption disabled? */
1093 jne ret_to_kernel /* yes, skip it */
1095 movl %gs:CPU_KERNEL_STACK,%eax
1098 and EXT(kernel_stack_mask),%ecx
1099 testl %ecx,%ecx /* are we on the kernel stack? */
1100 jne ret_to_kernel /* no, skip it */
1103 * Take an AST from kernel space. We don't need (and don't want)
1104 * to do as much as the case where the interrupt came from user
1107 CCALL1(i386_astintr, $1)
1113 * nested int - simple path, can't preempt etc on way out
1116 incl %gs:CPU_PREEMPTION_LEVEL
1117 incl %gs:CPU_INTERRUPT_LEVEL
1119 movl %esp, %edx /* x86_saved_state */
1120 CCALL1(interrupt, %edx)
1122 decl %gs:CPU_INTERRUPT_LEVEL
1123 decl %gs:CPU_PREEMPTION_LEVEL
1128 * Take an AST from an interrupted user
1130 ast_from_interrupt_user:
1131 movl %gs:CPU_PENDING_AST,%eax
1132 testl %eax,%eax /* pending ASTs? */
1133 je ret_to_user /* no, nothing to do */
1137 movl $1, %ecx /* check if we're in the PFZ */
1138 jmp EXT(return_from_trap_with_ast) /* return */
1143 * System call entries via INTR_GATE or sysenter:
1145 * esp -> x86_saved_state32_t
1146 * cr3 -> kernel directory
1147 * esp -> low based stack
1150 * ss/ds/es -> KERNEL_DS
1152 * interrupts disabled
1153 * direction flag cleared
1156 Entry(lo_sysenter32)
1158 * We can be here either for a mach syscall or a unix syscall,
1159 * as indicated by the sign of the code:
1161 movl R32_EAX(%esp),%eax
1163 js EXT(lo_mach_scall32) /* < 0 => mach */
1166 Entry(lo_unix_scall32)
1169 movl %gs:CPU_KERNEL_STACK,%edi
1170 xchgl %edi,%esp /* switch to kernel stack */
1171 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1172 movl TH_TASK(%ecx),%ebx /* point to current task */
1173 incl TH_SYSCALLS_UNIX(%ecx) /* increment call count */
1175 /* Check for active vtimers in the current task */
1176 TASK_VTIMER_CHECK(%ebx, %ecx)
1180 CCALL1(unix_syscall, %edi)
1182 * always returns through thread_exception_return
1186 Entry(lo_mach_scall32)
1189 movl %gs:CPU_KERNEL_STACK,%edi
1190 xchgl %edi,%esp /* switch to kernel stack */
1191 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1192 movl TH_TASK(%ecx),%ebx /* point to current task */
1193 incl TH_SYSCALLS_MACH(%ecx) /* increment call count */
1195 /* Check for active vtimers in the current task */
1196 TASK_VTIMER_CHECK(%ebx, %ecx)
1200 CCALL1(mach_call_munger, %edi)
1202 * always returns through thread_exception_return
1206 Entry(lo_mdep_scall32)
1209 movl %gs:CPU_KERNEL_STACK,%edi
1210 xchgl %edi,%esp /* switch to kernel stack */
1211 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1212 movl TH_TASK(%ecx),%ebx /* point to current task */
1214 /* Check for active vtimers in the current task */
1215 TASK_VTIMER_CHECK(%ebx, %ecx)
1219 CCALL1(machdep_syscall, %edi)
1221 * always returns through thread_exception_return
1225 Entry(lo_diag_scall32)
1228 movl %gs:CPU_KERNEL_STACK,%edi
1229 xchgl %edi,%esp /* switch to kernel stack */
1230 movl %gs:CPU_ACTIVE_THREAD,%ecx /* get current thread */
1231 movl TH_TASK(%ecx),%ebx /* point to current task */
1233 /* Check for active vtimers in the current task */
1234 TASK_VTIMER_CHECK(%ebx, %ecx)
1236 pushl %edi /* push pbc stack for later */
1238 CCALL1(diagCall, %edi) // Call diagnostics
1240 cli // Disable interruptions just in case
1241 popl %esp // Get back the original stack
1242 cmpl $0,%eax // What kind of return is this?
1243 jne EXT(return_to_user) // Normal return, do not check asts...
1245 CCALL5(i386_exception, $EXC_SYSCALL, $0x6000, $0, $1, $0)
1246 // pass what would be the diag syscall
1247 // error return - cause an exception
1251 LEXT(return_to_user)
1257 * Double-fault exception handler task. The last gasp...
1259 Entry(df_task_start)
1260 CCALL1(panic_double_fault32, $(T_DOUBLE_FAULT))
1265 * machine-check handler task. The last gasp...
1267 Entry(mc_task_start)
1268 CCALL1(panic_machine_check32, $(T_MACHINE_CHECK))
1272 #include <i386/lapic.h>
1273 #define CX(addr,reg) addr(,reg,4)
1276 * Note that the per-fault entry points are not currently
1277 * functional. The only way to make them work would be to
1278 * set up separate TSS's for each fault type, which doesn't
1279 * currently seem worthwhile. (The offset part of a task
1280 * gate is always ignored.) So all faults that task switch
1281 * currently resume at db_task_start.
1284 * Double fault (Murphy's point) - error code (0) on stack
1286 Entry(db_task_dbl_fault)
1288 movl $(T_DOUBLE_FAULT),%ebx
1291 * Segment not present - error code on stack
1293 Entry(db_task_seg_np)
1295 movl $(T_SEGMENT_NOT_PRESENT),%ebx
1298 * Stack fault - error code on (current) stack
1300 Entry(db_task_stk_fault)
1302 movl $(T_STACK_FAULT),%ebx
1305 * General protection fault - error code on stack
1307 Entry(db_task_gen_prot)
1309 movl $(T_GENERAL_PROTECTION),%ebx
1313 * The entry point where execution resumes after last-ditch debugger task
1316 Entry(db_task_start)
1318 subl $(ISS32_SIZE),%edx
1319 movl %edx,%esp /* allocate x86_saved_state on stack */
1320 movl %eax,R32_ERR(%esp)
1321 movl %ebx,R32_TRAPNO(%esp)
1324 movl CX(EXT(master_dbtss),%edx),%edx
1325 movl TSS_LINK(%edx),%eax
1326 pushl %eax /* pass along selector of previous TSS */
1327 call EXT(db_tss_to_frame)
1328 popl %eax /* get rid of TSS selector */
1329 call EXT(db_trap_from_asm)
1334 iret /* ha, ha, ha... */
1335 #endif /* MACH_KDB */