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
134 pushl %fs /* we save the segment regs in the trap */
135 pushl REG_GS /* state, but we do not restore them. We */
136 pushl %ds /* rather reload them using */
137 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
141 /* Load the kernel's segment registers. */
142 RESET_KERNEL_SEGMENTS_FORCE_DS_ES /* scratches ecx, edx */
144 /* Note: we do not use RESET_THREAD_CANCEL_* here as that is
145 needed only when an I/O-page-fault IPC is sent and when the
146 thread is killed. Resetting Thread_cancel here could
147 be harmful when using this trap handler in debugging.
148 Instead, we clear this flag in Thread::handle_slow_trap()
149 just before sending the IPC message or before killing the
150 thread. That's OK, because it is still atomic -- we never
151 enable IRQs (sti) before that point. */
153 movl %esp,%eax /* ARG1: address of trap_state */
154 xorl %edx,%edx /* ARG2: default CPU = 0 */
155 #ifndef CONFIG_NO_FRAME_PTR
156 pushl 56(%esp) /* create artificial stack frame */
158 # ifndef CONFIG_PROFILE
165 /* Call the C handler function if one has been installed. */
166 movl BASE_TRAP_HANDLER, %ecx
168 jz unexpected_trap_pop
172 #ifndef CONFIG_NO_FRAME_PTR
176 /* If the handler function returned zero (success),
177 then resume execution as if the trap never happened.
178 Otherwise, just panic. */
182 CHECK_SANITY 60(%esp) /* scratches ecx */
184 addl $4*2,%esp /* Pop ds, es segment registers */
186 popl %fs /* Restore segment registers */
188 addl $4*2,%esp /* Pop trap number and error code */
192 #ifndef CONFIG_NO_FRAME_PTR
203 GATE_ENTRY(0x0e,entry_vec0e_page_fault,ACC_PL_K | ACC_INTR_GATE)
205 /* we must save %cr2 before we can be preempted -- therefore we're an
206 interrupt gate (invoked with interrupts turned off). Also, we
207 don't turn them on again here, but only after checking for
208 page-ins from the global page directory in thread_page_fault().
209 XXX: If you make changes to stack layout here, fix thread_page_fault */
211 /* XXX slow version - sets up nice stack frame for debugger */
214 .type entry_vec0e_page_fault,@function
215 entry_vec0e_page_fault:
218 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
219 movl 12(%esp),%edx /* save error code in ARG2 ... */
220 movl PAGE_FAULT_ADDR,%eax /* save page fault address in ARG1 */
222 /* We must reset the cancel flag here atomically
223 if we are entering fresh from user mode and an IPC might occur.
224 NOTE: We cannot test the user-mode bit in the error code because
225 it will flag "kernel" in case an I/O-bitmap page is not mapped
226 during an I/O access. */
228 movl 20(%esp),%ecx /* get CS from stack */
229 andb $3,%cl /* retrieve current privilege level (CPL) */
230 jz 1f /* CPL == 0 -> kernel, skip resetting state */
232 RESET_THREAD_CANCEL_AT %ecx
233 1: movl %ebp,12(%esp) /* save frame pointer */
234 leal 12(%esp),%ebp /* load new frame pointer */
235 #ifdef CONFIG_PROFILE
238 pushl %eax /* save pf address */
239 pushl %edx /* save error code */
240 leal 24(%esp),%ecx /* ARG5: ptr to Return_frame */
242 pushl 36(%esp) /* ARG4: eflags */
243 movl 32(%esp),%ecx /* ARG3: eip */
244 call thread_page_fault
250 CHECK_SANITY 20(%esp) /* scratches ecx */
255 /* recover from a bad page fault by invoking the slow_trap handler */
259 addl $8,%esp /* pop ARG4 and ARG5 */
260 movl (%ebp),%eax /* old ebp */
261 popl (%ebp) /* error code */
262 popl %edx /* page fault address */
265 /* we have on stack: error code, eax, ecx, edx
266 move registers down to make room for trap number */
274 movl $0x0e,12(%esp) /* error code */
275 pushl %ebx /* rest of trap state */
276 pushl %edx /* page fault address */
283 /* FPU not available in this context. */
284 GATE_ENTRY(0x07,entry_vec07_fpu_unavail, ACC_PL_K | ACC_INTR_GATE)
286 /* do all of this with disabled interrupts */
288 .type entry_vec07_fpu_unavail,@function
289 entry_vec07_fpu_unavail:
292 call thread_handle_fputrap
294 CHECK_SANITY 16(%esp) /* scratches ecx */
296 jz real_fpu_exception
307 /* timer interrupt */
308 #ifdef CONFIG_SCHED_PIT
309 GATE_ENTRY(0x20,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
311 #ifdef CONFIG_SCHED_RTC
312 GATE_ENTRY(0x28,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
314 #ifdef CONFIG_SCHED_APIC
315 GATE_ENTRY(APIC_IRQ_BASE, entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
317 #ifdef CONFIG_SCHED_HPET
318 /* HPET is set at startup */
322 .globl entry_int_timer
324 #ifndef CONFIG_NO_FRAME_PTR
326 #ifndef CONFIG_PROFILE
335 #ifdef CONFIG_NO_FRAME_PTR
336 movl 12(%esp), %eax /* ARG1: eip for logging */
338 movl 16(%esp), %eax /* ARG1: eip for logging */
340 call thread_timer_interrupt /* enter with disabled irqs */
342 #ifndef CONFIG_NO_FRAME_PTR
343 CHECK_SANITY 20(%esp) /* scratches ecx */
345 CHECK_SANITY 16(%esp) /* scratches ecx */
348 #ifndef CONFIG_NO_FRAME_PTR
354 .globl entry_int_timer_slow
355 entry_int_timer_slow:
356 #ifndef CONFIG_NO_FRAME_PTR
358 #ifndef CONFIG_PROFILE
367 call thread_timer_interrupt_slow /* enter with disabled irqs */
368 in_timer_interrupt_slow:
369 jmp do_timer_interrupt
373 .globl entry_int_timer_stop
374 entry_int_timer_stop:
375 #ifndef CONFIG_NO_FRAME_PTR
377 #ifndef CONFIG_PROFILE
385 call thread_timer_interrupt_stop
386 #ifndef CONFIG_NO_FRAME_PTR
387 CHECK_SANITY 20(%esp) /* scratches ecx */
389 CHECK_SANITY 16(%esp) /* scratches ecx */
392 #ifndef CONFIG_NO_FRAME_PTR
398 /* profiling timer interrupt entry point */
399 #ifdef CONFIG_PROFILE
402 .globl profile_interrupt_entry
403 .type profile_interrupt_entry,@function
404 profile_interrupt_entry:
406 #ifndef CONFIG_NO_FRAME_PTR
410 movl 8(%esp),%eax /* %eax = return address */
413 movl 4(%esp),%eax /* %eax = return address */
417 call profile_interrupt /* enter with disabled irqs */
418 #ifndef CONFIG_NO_FRAME_PTR
419 CHECK_SANITY 20(%esp) /* scratches ecx */
421 CHECK_SANITY 16(%esp) /* scratches ecx */
426 #ifndef CONFIG_NO_FRAME_PTR
431 #endif /* CONFIG_PROFILE */
433 /* other interrupts */
435 #define INTERRUPT(int,name) \
436 GATE_ENTRY(int,entry_##name,ACC_PL_K | ACC_INTR_GATE) ;\
440 movl $ (int - 0x20), %eax /* ARG1: irqnum */ ;\
443 #ifndef CONFIG_SCHED_PIT
446 /* spurious IRQ handlers */
447 GATE_ENTRY(0x27,entry_int_pic_ignore,ACC_PL_K | ACC_INTR_GATE)
448 GATE_ENTRY(0x2f,entry_int_pic_ignore,ACC_PL_K | ACC_INTR_GATE)
449 #ifndef CONFIG_SCHED_RTC
454 .type all_irqs,@function
455 .type __generic_irq_entry,@function
456 .global __generic_irq_entry
462 movl 12(%esp), %edx /* ARG2: eip */
463 call irq_interrupt /* enter with disabled irqs */
465 CHECK_SANITY 16(%esp) /* scratches ecx */
470 entry_int_pic_ignore:
473 .global entry_int_pic_ignore
477 /****************************************************************************/
479 /****************************************************************************/
481 #ifdef CONFIG_ASSEMBLER_IPC_SHORTCUT
482 GATE_ENTRY(0x30,entry_sys_ipc,ACC_PL_U | ACC_INTR_GATE);
484 GATE_ENTRY(0x30,entry_sys_ipc_c,ACC_PL_U | ACC_INTR_GATE);
487 #if defined (CONFIG_JDB_LOGGING) || !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT)
489 .globl entry_sys_ipc_c
495 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
497 RESET_THREAD_CANCEL_AT %ebx
498 call sys_ipc_wrapper //ipc_short_cut_wrapper
500 CHECK_SANITY $3 /* scratches ecx */
501 RESTORE_STATE_AFTER_IPC
509 /* The slow variant of sys_ipc_entry is used when logging IPC */
511 .globl entry_sys_ipc_log
517 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
518 jnz alien_sys_ipc_log
519 RESET_THREAD_CANCEL_AT %ebx
522 CHECK_SANITY $3 /* scratches ecx */
523 RESTORE_STATE_AFTER_IPC
530 // these labels help show_tcb to guess the thread state
534 .globl in_handle_fputrap
536 .globl in_timer_interrupt
537 .globl in_timer_interrupt_slow
539 #define SYSTEM_CALL(int,name) \
540 GATE_ENTRY(int,entry_##name,ACC_PL_U | ACC_INTR_GATE) ;\
544 movl $(syscall_table+4*(int-0x30)), %eax ;\
548 .type all_syscalls,@function
553 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
555 RESET_THREAD_CANCEL_AT %ebx
556 call *(%eax) /* interrupts enabled in wrappers */
560 CHECK_SANITY $3 /* scratches ecx */
566 SYSTEM_CALL(0x32,sys_invoke_debug)
569 /* these functions are implemented in entry-native.S */
570 GATE_ENTRY(0x0a,entry_vec0a_invalid_tss,ACC_PL_K | ACC_INTR_GATE)
571 GATE_ENTRY(0x0f,entry_vec0f_apic_spurious_interrupt_bug,ACC_PL_K | ACC_INTR_GATE)
572 GATE_ENTRY(APIC_IRQ_BASE + 3,entry_apic_error_interrupt,ACC_PL_K | ACC_INTR_GATE)
573 GATE_ENTRY(APIC_IRQ_BASE + 0xf,entry_apic_spurious_interrupt,ACC_PL_K | ACC_INTR_GATE)
577 GATE_ENTRY(APIC_IRQ_BASE + 2, entry_ipi, ACC_PL_K | ACC_INTR_GATE)
578 GATE_ENTRY(APIC_IRQ_BASE - 2, entry_debug_ipi, ACC_PL_K | ACC_INTR_GATE)
579 GATE_ENTRY(APIC_IRQ_BASE - 1, entry_ipi_remote_request, ACC_PL_K | ACC_INTR_GATE)
584 .globl alien_sys_ipc_c /* Also used in shortcut */
591 #if defined (CONFIG_JDB)
600 * input: eax: address to syscall function
601 * output: eax: error code
603 .macro SC_ADDR_TO_ERR val
604 sub $syscall_table , %eax /* eax = byte offset to syscall */
605 shr $2, %eax /* convert eax to syscall nr */
606 add $0x30, %eax /* convert eax to syscall int nr */
607 shl $3, %eax /* construct error code */
608 orl $\val, %eax /* -"- */
612 btrl $17, OFS__THREAD__STATE (%ebx) /* Thread_dis_alien */
615 sub $2, 4(%esp) /* Correct EIP to point to insn */
622 1: /* do alien syscall and trap afterwards */
623 RESET_THREAD_CANCEL_AT %ebx
625 call *(%eax) /* call with ENABLED interrupts */
627 CHECK_SANITY $3 /* scratches ecx */
635 .globl leave_by_trigger_exception
636 leave_by_trigger_exception:
638 subl $12,%esp /* clean up stack from previous
641 call thread_restore_exc_state
649 .globl leave_by_vcpu_upcall
650 leave_by_vcpu_upcall:
652 subl $12,%esp /* clean up stack from previous
655 call thread_restore_exc_state
658 mov OFS__THREAD__USER_VCPU(%ecx), %eax /* vcpu state poiner from TCB */
659 mov OFS__THREAD__VCPU_STATE(%ecx), %ecx /* vcpu state poiner from TCB */
660 addl $(VAL__SIZEOF_TRAP_STATE - 20), %ecx /* skip return frame */
661 mov SCRATCH_REGISTER_SIZE(%esp), %edx
662 mov %edx, (%ecx) /* EIP */
663 mov 8 + SCRATCH_REGISTER_SIZE(%esp), %edx
664 mov %edx, 8(%ecx) /* EFLAGS */
665 mov 12 + SCRATCH_REGISTER_SIZE(%esp), %edx
666 mov %edx, 12(%ecx) /* ESP */
667 mov 16 + SCRATCH_REGISTER_SIZE(%esp), %edx
668 mov %edx, 16(%ecx) /* SS */
670 mov 0(%esp), %edx /* EDX */
672 mov 4(%esp), %edx /* ECX */
674 mov 8(%esp), %edx /* EAX */
681 sub $4, %esp /* SKIP PFA */
686 /*add SCRATCH_REGISTER_SIZE, %esp*/
689 # define REG_GS CPU_GS
694 pushl %fs /* we save the segment regs in the trap */
695 pushl REG_GS /* state, but we do not restore them. We */
696 pushl %ds /* rather reload them using */
697 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
700 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_SP(%ecx), %edx
702 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_IP(%ecx), %edx
710 addl $(2*4), %esp // skip es and ds for now
720 .section ".text.debug.stack_profiling"
722 .global __cyg_profile_func_enter
723 .global __cyg_profile_func_exit
728 __cyg_profile_func_enter:
729 __cyg_profile_func_exit:
730 cmp $0xc0000000, %esp
735 // and $0x7ff, %ecx /* 2K TCBs */
736 and $0xfff, %ecx /* 4K TCBs */
744 // fast return from Dirq::hit
746 .globl fast_ret_from_irq
748 CHECK_SANITY $3 // scratches ecx
749 RESTORE_STATE_AFTER_IPC
751 andl $0x7f, 4(%esp) // if entered using sysenter
752 orl $EFLAGS_IF, 8(%esp) // if entered using sysenter