2 * This file contains a 'gate_init' initialization table
3 * to initialize the x86 processor trap vectors to default entrypoints.
4 * These entrypoints simply push a standard trap_state frame
5 * and jump to the 'trap_handler' routine.
8 #include "config_tcbsize.h"
9 #include "config_gdt.h"
10 #include "globalconfig.h"
12 #include <low_level.h>
14 #include "tcboffset.h"
19 /* We make the trap handler an interrupt gate, because for debugging
20 purposes, we don't want any interrupts to occur until they're
21 explicitly enabled in the base_trap_handler (usually
22 Thread::handle_slow_trap). */
25 * No error code. Clear error code and push trap number.
27 #define EXCEPTION(n,name) \
28 GATE_ENTRY(n,entry_##name,ACC_PL_K | ACC_INTR_GATE) ;\
37 * User-accessible exception. Otherwise, same as above.
39 #define EXCEP_USR(n,name) \
40 GATE_ENTRY(n,entry_##name,ACC_PL_U | ACC_INTR_GATE) ;\
49 * Error code has been pushed. Just push trap number.
51 #define EXCEP_ERR(n,name) \
52 GATE_ENTRY(n,entry_##name,ACC_PL_K | ACC_INTR_GATE) ;\
60 btrl $17, OFS__THREAD__STATE (%ebx) /* Thread_dis_alien */
63 sub $2, 4(%esp) /* Correct EIP to point to insn */
65 pushl $(0x30 << 3 | 2)
70 1: /* do alien IPC and raise a trap afterwards */
71 RESET_THREAD_CANCEL_AT %ebx
75 CHECK_SANITY $3 /* scratches ecx */
76 RESTORE_STATE_AFTER_IPC
78 pushl $(0x30 << 3 | 6)
84 GATE_INITTAB_BEGIN(idt_init_table)
86 EXCEPTION(0x00,vec00_zero_div)
88 EXCEPTION(0x01,vec01_debug)
90 /* IA32 has to handle breakpoint exceptions if occured exactly at
91 entry_sys_fast_ipc -- see ia32/entry-ia32.S */
92 GATE_ENTRY(0x01,entry_vec01_debug,ACC_PL_K | ACC_INTR_GATE)
94 /* XXX IA32 has to handle NMI occured exactly at entry_sys_fast_ipc */
95 EXCEP_USR(0x02,vec02_nmi)
96 EXCEP_USR(0x03,vec03_breakpoint)
97 EXCEP_USR(0x04,vec04_into)
98 EXCEP_USR(0x05,vec05_bounds)
99 EXCEPTION(0x06,vec06_invop)
100 /* EXCEPTION(0x07,nofpu) */
102 EXCEP_ERR(0x08,vec08_dbl_fault)
104 GATE_ENTRY(0x08, GDT_TSS_DBF, ACC_PL_K | ACC_TASK_GATE)
106 EXCEPTION(0x09,vec09_fpu_ovfl)
107 /* EXCEP_ERR(0x0a,vec0a_inv_tss) */
108 EXCEP_ERR(0x0b,vec0b_segnp)
109 EXCEP_ERR(0x0c,vec0c_stack_fault)
110 EXCEP_ERR(0x0d,vec0d_gen_prot)
111 /* EXCEP_ERR(0x0e,vec0e_page_fault) */
112 /* EXCEPTION(0x0f,vec0f_trap_0f) */
113 EXCEPTION(0x10,vec10_fpu_err)
114 EXCEP_ERR(0x11,vec11_align)
115 EXCEPTION(0x12,vec12_mcheck)
116 EXCEPTION(0x13,vec13_simd_err)
120 .type slowtraps,@function
122 /* We have to introduce the label _slowtraps besides the label
123 slowtraps to achive that jmps from exception entry points
124 are optimized to two-byte jmps. The label slowtraps is visible
129 # define REG_GS CPU_GS
130 # define REG_FS CPU_FS
136 pushl REG_FS /* we save the segment regs in the trap */
137 pushl REG_GS /* state, but we do not restore them. We */
138 pushl %ds /* rather reload them using */
139 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
143 /* Load the kernel's segment registers. */
144 RESET_KERNEL_SEGMENTS_FORCE_DS_ES /* scratches ecx, edx */
146 /* Note: we do not use RESET_THREAD_CANCEL_* here as that is
147 needed only when an I/O-page-fault IPC is sent and when the
148 thread is killed. Resetting Thread_cancel here could
149 be harmful when using this trap handler in debugging.
150 Instead, we clear this flag in Thread::handle_slow_trap()
151 just before sending the IPC message or before killing the
152 thread. That's OK, because it is still atomic -- we never
153 enable IRQs (sti) before that point. */
155 movl %esp,%eax /* ARG1: address of trap_state */
156 xorl %edx,%edx /* ARG2: default CPU = 0 */
157 #ifndef CONFIG_NO_FRAME_PTR
158 pushl 56(%esp) /* create artificial stack frame */
160 # ifndef CONFIG_PROFILE
167 /* Call the C handler function if one has been installed. */
168 movl BASE_TRAP_HANDLER, %ecx
170 jz unexpected_trap_pop
174 #ifndef CONFIG_NO_FRAME_PTR
178 /* If the handler function returned zero (success),
179 then resume execution as if the trap never happened.
180 Otherwise, just panic. */
184 CHECK_SANITY 60(%esp) /* scratches ecx */
186 addl $4*2,%esp /* Pop ds, es segment registers */
188 popl REG_FS /* Restore segment registers */
190 addl $4*2,%esp /* Pop trap number and error code */
194 #ifndef CONFIG_NO_FRAME_PTR
205 GATE_ENTRY(0x0e,entry_vec0e_page_fault,ACC_PL_K | ACC_INTR_GATE)
207 /* we must save %cr2 before we can be preempted -- therefore we're an
208 interrupt gate (invoked with interrupts turned off). Also, we
209 don't turn them on again here, but only after checking for
210 page-ins from the global page directory in thread_page_fault().
211 XXX: If you make changes to stack layout here, fix thread_page_fault */
213 /* XXX slow version - sets up nice stack frame for debugger */
216 .type entry_vec0e_page_fault,@function
217 entry_vec0e_page_fault:
220 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
221 movl 12(%esp),%edx /* save error code in ARG2 ... */
222 movl PAGE_FAULT_ADDR,%eax /* save page fault address in ARG1 */
224 /* We must reset the cancel flag here atomically
225 if we are entering fresh from user mode and an IPC might occur.
226 NOTE: We cannot test the user-mode bit in the error code because
227 it will flag "kernel" in case an I/O-bitmap page is not mapped
228 during an I/O access. */
230 movl 20(%esp),%ecx /* get CS from stack */
231 andb $3,%cl /* retrieve current privilege level (CPL) */
232 jz 1f /* CPL == 0 -> kernel, skip resetting state */
234 RESET_THREAD_CANCEL_AT %ecx
235 1: movl %ebp,12(%esp) /* save frame pointer */
236 leal 12(%esp),%ebp /* load new frame pointer */
237 #ifdef CONFIG_PROFILE
240 pushl %eax /* save pf address */
241 pushl %edx /* save error code */
242 leal 24(%esp),%ecx /* ARG5: ptr to Return_frame */
244 pushl 36(%esp) /* ARG4: eflags */
245 movl 32(%esp),%ecx /* ARG3: eip */
246 call thread_page_fault
252 CHECK_SANITY 20(%esp) /* scratches ecx */
257 /* recover from a bad page fault by invoking the slow_trap handler */
261 addl $8,%esp /* pop ARG4 and ARG5 */
262 movl (%ebp),%eax /* old ebp */
263 popl (%ebp) /* error code */
264 popl %edx /* page fault address */
267 /* we have on stack: error code, eax, ecx, edx
268 move registers down to make room for trap number */
276 movl $0x0e,12(%esp) /* error code */
277 pushl %ebx /* rest of trap state */
278 pushl %edx /* page fault address */
285 /* FPU not available in this context. */
286 GATE_ENTRY(0x07,entry_vec07_fpu_unavail, ACC_PL_K | ACC_INTR_GATE)
288 /* do all of this with disabled interrupts */
290 .type entry_vec07_fpu_unavail,@function
291 entry_vec07_fpu_unavail:
294 call thread_handle_fputrap
296 CHECK_SANITY 16(%esp) /* scratches ecx */
298 jz real_fpu_exception
309 /* timer interrupt */
310 #ifdef CONFIG_SCHED_PIT
311 GATE_ENTRY(0x20,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
313 #ifdef CONFIG_SCHED_RTC
314 GATE_ENTRY(0x28,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
316 #ifdef CONFIG_SCHED_APIC
317 GATE_ENTRY(APIC_IRQ_BASE, entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
319 #ifdef CONFIG_SCHED_HPET
320 /* HPET is set at startup */
324 .globl entry_int_timer
326 #ifndef CONFIG_NO_FRAME_PTR
328 #ifndef CONFIG_PROFILE
337 #ifdef CONFIG_NO_FRAME_PTR
338 movl 12(%esp), %eax /* ARG1: eip for logging */
340 movl 16(%esp), %eax /* ARG1: eip for logging */
342 call thread_timer_interrupt /* enter with disabled irqs */
344 #ifndef CONFIG_NO_FRAME_PTR
345 CHECK_SANITY 20(%esp) /* scratches ecx */
347 CHECK_SANITY 16(%esp) /* scratches ecx */
350 #ifndef CONFIG_NO_FRAME_PTR
356 .globl entry_int_timer_slow
357 entry_int_timer_slow:
358 #ifndef CONFIG_NO_FRAME_PTR
360 #ifndef CONFIG_PROFILE
369 call thread_timer_interrupt_slow /* enter with disabled irqs */
370 in_timer_interrupt_slow:
371 jmp do_timer_interrupt
375 .globl entry_int_timer_stop
376 entry_int_timer_stop:
377 #ifndef CONFIG_NO_FRAME_PTR
379 #ifndef CONFIG_PROFILE
387 call thread_timer_interrupt_stop
388 #ifndef CONFIG_NO_FRAME_PTR
389 CHECK_SANITY 20(%esp) /* scratches ecx */
391 CHECK_SANITY 16(%esp) /* scratches ecx */
394 #ifndef CONFIG_NO_FRAME_PTR
400 /* profiling timer interrupt entry point */
401 #ifdef CONFIG_PROFILE
404 .globl profile_interrupt_entry
405 .type profile_interrupt_entry,@function
406 profile_interrupt_entry:
408 #ifndef CONFIG_NO_FRAME_PTR
412 movl 8(%esp),%eax /* %eax = return address */
415 movl 4(%esp),%eax /* %eax = return address */
419 call profile_interrupt /* enter with disabled irqs */
420 #ifndef CONFIG_NO_FRAME_PTR
421 CHECK_SANITY 20(%esp) /* scratches ecx */
423 CHECK_SANITY 16(%esp) /* scratches ecx */
428 #ifndef CONFIG_NO_FRAME_PTR
433 #endif /* CONFIG_PROFILE */
435 /* other interrupts */
437 #define INTERRUPT(int,name) \
438 GATE_ENTRY(int,entry_##name,ACC_PL_K | ACC_INTR_GATE) ;\
442 movl $ (int - 0x20), %eax /* ARG1: irqnum */ ;\
445 #ifndef CONFIG_SCHED_PIT
448 /* spurious IRQ handlers */
449 GATE_ENTRY(0x27,entry_int_pic_ignore,ACC_PL_K | ACC_INTR_GATE)
450 GATE_ENTRY(0x2f,entry_int_pic_ignore,ACC_PL_K | ACC_INTR_GATE)
451 #ifndef CONFIG_SCHED_RTC
456 .type all_irqs,@function
457 .type __generic_irq_entry,@function
458 .global __generic_irq_entry
464 movl 12(%esp), %edx /* ARG2: eip */
465 call irq_interrupt /* enter with disabled irqs */
467 CHECK_SANITY 16(%esp) /* scratches ecx */
472 entry_int_pic_ignore:
475 .global entry_int_pic_ignore
479 /****************************************************************************/
481 /****************************************************************************/
483 #ifdef CONFIG_ASSEMBLER_IPC_SHORTCUT
484 GATE_ENTRY(0x30,entry_sys_ipc,ACC_PL_U | ACC_INTR_GATE);
486 GATE_ENTRY(0x30,entry_sys_ipc_c,ACC_PL_U | ACC_INTR_GATE);
489 #if defined (CONFIG_JDB_LOGGING) || !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT)
491 .globl entry_sys_ipc_c
497 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
499 RESET_THREAD_CANCEL_AT %ebx
500 call sys_ipc_wrapper //ipc_short_cut_wrapper
502 CHECK_SANITY $3 /* scratches ecx */
503 RESTORE_STATE_AFTER_IPC
511 /* The slow variant of sys_ipc_entry is used when logging IPC */
513 .globl entry_sys_ipc_log
519 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
520 jnz alien_sys_ipc_log
521 RESET_THREAD_CANCEL_AT %ebx
524 CHECK_SANITY $3 /* scratches ecx */
525 RESTORE_STATE_AFTER_IPC
532 // these labels help show_tcb to guess the thread state
536 .globl in_handle_fputrap
538 .globl in_timer_interrupt
539 .globl in_timer_interrupt_slow
541 #define SYSTEM_CALL(int,name) \
542 GATE_ENTRY(int,entry_##name,ACC_PL_U | ACC_INTR_GATE) ;\
546 movl $(syscall_table+4*(int-0x30)), %eax ;\
550 .type all_syscalls,@function
555 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
557 RESET_THREAD_CANCEL_AT %ebx
558 call *(%eax) /* interrupts enabled in wrappers */
562 CHECK_SANITY $3 /* scratches ecx */
568 SYSTEM_CALL(0x32,sys_invoke_debug)
571 /* these functions are implemented in entry-native.S */
572 GATE_ENTRY(0x0a,entry_vec0a_invalid_tss,ACC_PL_K | ACC_INTR_GATE)
573 GATE_ENTRY(0x0f,entry_vec0f_apic_spurious_interrupt_bug,ACC_PL_K | ACC_INTR_GATE)
574 GATE_ENTRY(APIC_IRQ_BASE + 3,entry_apic_error_interrupt,ACC_PL_K | ACC_INTR_GATE)
575 GATE_ENTRY(APIC_IRQ_BASE + 0xf,entry_apic_spurious_interrupt,ACC_PL_K | ACC_INTR_GATE)
579 GATE_ENTRY(APIC_IRQ_BASE + 2, entry_ipi, ACC_PL_K | ACC_INTR_GATE)
580 GATE_ENTRY(APIC_IRQ_BASE - 2, entry_debug_ipi, ACC_PL_K | ACC_INTR_GATE)
581 GATE_ENTRY(APIC_IRQ_BASE - 1, entry_ipi_remote_request, ACC_PL_K | ACC_INTR_GATE)
586 .globl alien_sys_ipc_c /* Also used in shortcut */
593 #if defined (CONFIG_JDB)
602 * input: eax: address to syscall function
603 * output: eax: error code
605 .macro SC_ADDR_TO_ERR val
606 sub $syscall_table , %eax /* eax = byte offset to syscall */
607 shr $2, %eax /* convert eax to syscall nr */
608 add $0x30, %eax /* convert eax to syscall int nr */
609 shl $3, %eax /* construct error code */
610 orl $\val, %eax /* -"- */
614 btrl $17, OFS__THREAD__STATE (%ebx) /* Thread_dis_alien */
617 sub $2, 4(%esp) /* Correct EIP to point to insn */
624 1: /* do alien syscall and trap afterwards */
625 RESET_THREAD_CANCEL_AT %ebx
627 call *(%eax) /* call with ENABLED interrupts */
629 CHECK_SANITY $3 /* scratches ecx */
637 .globl leave_by_trigger_exception
638 leave_by_trigger_exception:
640 subl $12,%esp /* clean up stack from previous
643 call thread_restore_exc_state
651 .globl leave_by_vcpu_upcall
652 leave_by_vcpu_upcall:
654 subl $12,%esp /* clean up stack from previous
657 call thread_restore_exc_state
660 mov OFS__THREAD__USER_VCPU(%ecx), %eax /* vcpu state pointer from TCB */
661 mov OFS__THREAD__VCPU_STATE(%ecx), %ecx /* vcpu state pointer from TCB */
662 addl $(VAL__SIZEOF_TRAP_STATE - 20), %ecx /* skip return frame */
663 mov SCRATCH_REGISTER_SIZE(%esp), %edx
664 mov %edx, (%ecx) /* EIP */
665 mov 8 + SCRATCH_REGISTER_SIZE(%esp), %edx
666 mov %edx, 8(%ecx) /* EFLAGS */
667 mov 12 + SCRATCH_REGISTER_SIZE(%esp), %edx
668 mov %edx, 12(%ecx) /* ESP */
669 mov 16 + SCRATCH_REGISTER_SIZE(%esp), %edx
670 mov %edx, 16(%ecx) /* SS */
672 mov 0(%esp), %edx /* EDX */
674 mov 4(%esp), %edx /* ECX */
676 mov 8(%esp), %edx /* EAX */
683 sub $4, %esp /* SKIP PFA */
688 /*add SCRATCH_REGISTER_SIZE, %esp*/
690 pushl REG_FS /* we save the segment regs in the trap */
691 pushl REG_GS /* state, but we do not restore them. We */
692 pushl %ds /* rather reload them using */
693 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
696 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_SP(%ecx), %edx
698 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_IP(%ecx), %edx
700 movl $EFLAGS_IF, 8(%esp)
707 addl $(2*4), %esp // skip es and ds for now
717 .section ".text.debug.stack_profiling"
719 .global __cyg_profile_func_enter
720 .global __cyg_profile_func_exit
725 __cyg_profile_func_enter:
726 __cyg_profile_func_exit:
727 cmp $0xc0000000, %esp
732 // and $0x7ff, %ecx /* 2K TCBs */
733 and $0xfff, %ecx /* 4K TCBs */
741 // fast return from Dirq::hit
743 .globl fast_ret_from_irq
745 CHECK_SANITY $3 // scratches ecx
746 RESTORE_STATE_AFTER_IPC
748 andl $0x7f, 4(%esp) // if entered using sysenter
749 orl $EFLAGS_IF, 8(%esp) // if entered using sysenter