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 */
163 /* Call the C handler function if one has been installed. */
164 movl BASE_TRAP_HANDLER, %ecx
166 jz unexpected_trap_pop
170 #ifndef CONFIG_NO_FRAME_PTR
174 /* If the handler function returned zero (success),
175 then resume execution as if the trap never happened.
176 Otherwise, just panic. */
180 CHECK_SANITY 60(%esp) /* scratches ecx */
182 addl $4*2,%esp /* Pop ds, es segment registers */
184 popl REG_FS /* Restore segment registers */
186 addl $4*2,%esp /* Pop trap number and error code */
190 #ifndef CONFIG_NO_FRAME_PTR
201 GATE_ENTRY(0x0e,entry_vec0e_page_fault,ACC_PL_K | ACC_INTR_GATE)
203 /* we must save %cr2 before we can be preempted -- therefore we're an
204 interrupt gate (invoked with interrupts turned off). Also, we
205 don't turn them on again here, but only after checking for
206 page-ins from the global page directory in thread_page_fault().
207 XXX: If you make changes to stack layout here, fix thread_page_fault */
209 /* XXX slow version - sets up nice stack frame for debugger */
212 .type entry_vec0e_page_fault,@function
213 entry_vec0e_page_fault:
216 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
217 movl 12(%esp),%edx /* save error code in ARG2 ... */
218 movl PAGE_FAULT_ADDR,%eax /* save page fault address in ARG1 */
220 /* We must reset the cancel flag here atomically
221 if we are entering fresh from user mode and an IPC might occur.
222 NOTE: We cannot test the user-mode bit in the error code because
223 it will flag "kernel" in case an I/O-bitmap page is not mapped
224 during an I/O access. */
226 movl 20(%esp),%ecx /* get CS from stack */
227 andb $3,%cl /* retrieve current privilege level (CPL) */
228 jz 1f /* CPL == 0 -> kernel, skip resetting state */
230 RESET_THREAD_CANCEL_AT %ecx
231 1: movl %ebp,12(%esp) /* save frame pointer */
232 leal 12(%esp),%ebp /* load new frame pointer */
233 pushl %eax /* save pf address */
234 pushl %edx /* save error code */
235 leal 24(%esp),%ecx /* ARG5: ptr to Return_frame */
237 pushl 36(%esp) /* ARG4: eflags */
238 movl 32(%esp),%ecx /* ARG3: eip */
239 call thread_page_fault
245 CHECK_SANITY 20(%esp) /* scratches ecx */
250 /* recover from a bad page fault by invoking the slow_trap handler */
254 addl $8,%esp /* pop ARG4 and ARG5 */
255 movl (%ebp),%eax /* old ebp */
256 popl (%ebp) /* error code */
257 popl %edx /* page fault address */
260 /* we have on stack: error code, eax, ecx, edx
261 move registers down to make room for trap number */
269 movl $0x0e,12(%esp) /* error code */
270 pushl %ebx /* rest of trap state */
271 pushl %edx /* page fault address */
278 /* FPU not available in this context. */
279 GATE_ENTRY(0x07,entry_vec07_fpu_unavail, ACC_PL_K | ACC_INTR_GATE)
281 /* do all of this with disabled interrupts */
283 .type entry_vec07_fpu_unavail,@function
284 entry_vec07_fpu_unavail:
287 call thread_handle_fputrap
289 CHECK_SANITY 16(%esp) /* scratches ecx */
291 jz real_fpu_exception
302 /* timer interrupt */
303 #ifdef CONFIG_SCHED_PIT
304 GATE_ENTRY(0x20,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
306 #ifdef CONFIG_SCHED_RTC
307 GATE_ENTRY(0x28,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
309 #ifdef CONFIG_SCHED_APIC
310 GATE_ENTRY(APIC_IRQ_BASE, entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
312 #ifdef CONFIG_SCHED_HPET
313 /* HPET is set at startup */
317 .globl entry_int_timer
319 #ifndef CONFIG_NO_FRAME_PTR
326 #ifdef CONFIG_NO_FRAME_PTR
327 movl 12(%esp), %eax /* ARG1: eip for logging */
329 movl 16(%esp), %eax /* ARG1: eip for logging */
331 call thread_timer_interrupt /* enter with disabled irqs */
333 #ifndef CONFIG_NO_FRAME_PTR
334 CHECK_SANITY 20(%esp) /* scratches ecx */
336 CHECK_SANITY 16(%esp) /* scratches ecx */
339 #ifndef CONFIG_NO_FRAME_PTR
345 .globl entry_int_timer_slow
346 entry_int_timer_slow:
347 #ifndef CONFIG_NO_FRAME_PTR
354 call thread_timer_interrupt_slow /* enter with disabled irqs */
355 in_timer_interrupt_slow:
356 jmp do_timer_interrupt
360 .globl entry_int_timer_stop
361 entry_int_timer_stop:
362 #ifndef CONFIG_NO_FRAME_PTR
368 call thread_timer_interrupt_stop
369 #ifndef CONFIG_NO_FRAME_PTR
370 CHECK_SANITY 20(%esp) /* scratches ecx */
372 CHECK_SANITY 16(%esp) /* scratches ecx */
375 #ifndef CONFIG_NO_FRAME_PTR
381 /* other interrupts */
383 #define INTERRUPT(int,name) \
384 GATE_ENTRY(int,entry_##name,ACC_PL_K | ACC_INTR_GATE) ;\
388 movl $ (int - 0x20), %eax /* ARG1: irqnum */ ;\
391 #ifndef CONFIG_SCHED_PIT
394 /* spurious IRQ handlers */
395 GATE_ENTRY(0x27,entry_int_pic_ignore,ACC_PL_K | ACC_INTR_GATE)
396 GATE_ENTRY(0x2f,entry_int_pic_ignore,ACC_PL_K | ACC_INTR_GATE)
397 #ifndef CONFIG_SCHED_RTC
402 .type all_irqs,@function
403 .type __generic_irq_entry,@function
404 .global __generic_irq_entry
410 movl 12(%esp), %edx /* ARG2: eip */
411 call irq_interrupt /* enter with disabled irqs */
413 CHECK_SANITY 16(%esp) /* scratches ecx */
418 entry_int_pic_ignore:
421 .global entry_int_pic_ignore
425 /****************************************************************************/
427 /****************************************************************************/
429 #ifdef CONFIG_ASSEMBLER_IPC_SHORTCUT
430 GATE_ENTRY(0x30,entry_sys_ipc,ACC_PL_U | ACC_INTR_GATE);
432 GATE_ENTRY(0x30,entry_sys_ipc_c,ACC_PL_U | ACC_INTR_GATE);
435 #if defined (CONFIG_JDB_LOGGING) || !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT)
437 .globl entry_sys_ipc_c
443 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
445 RESET_THREAD_CANCEL_AT %ebx
446 call sys_ipc_wrapper //ipc_short_cut_wrapper
448 CHECK_SANITY $3 /* scratches ecx */
449 RESTORE_STATE_AFTER_IPC
457 /* The slow variant of sys_ipc_entry is used when logging IPC */
459 .globl entry_sys_ipc_log
465 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
466 jnz alien_sys_ipc_log
467 RESET_THREAD_CANCEL_AT %ebx
470 CHECK_SANITY $3 /* scratches ecx */
471 RESTORE_STATE_AFTER_IPC
478 // these labels help show_tcb to guess the thread state
482 .globl in_handle_fputrap
484 .globl in_timer_interrupt
485 .globl in_timer_interrupt_slow
487 #define SYSTEM_CALL(int,name) \
488 GATE_ENTRY(int,entry_##name,ACC_PL_U | ACC_INTR_GATE) ;\
492 movl $(syscall_table+4*(int-0x30)), %eax ;\
496 .type all_syscalls,@function
501 testl $Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
503 RESET_THREAD_CANCEL_AT %ebx
504 call *(%eax) /* interrupts enabled in wrappers */
508 CHECK_SANITY $3 /* scratches ecx */
514 SYSTEM_CALL(0x32,sys_invoke_debug)
517 /* these functions are implemented in entry-native.S */
518 GATE_ENTRY(0x0a,entry_vec0a_invalid_tss,ACC_PL_K | ACC_INTR_GATE)
519 GATE_ENTRY(0x0f,entry_vec0f_apic_spurious_interrupt_bug,ACC_PL_K | ACC_INTR_GATE)
520 GATE_ENTRY(APIC_IRQ_BASE + 3,entry_apic_error_interrupt,ACC_PL_K | ACC_INTR_GATE)
521 GATE_ENTRY(APIC_IRQ_BASE + 0xf,entry_apic_spurious_interrupt,ACC_PL_K | ACC_INTR_GATE)
525 GATE_ENTRY(APIC_IRQ_BASE + 2, entry_ipi, ACC_PL_K | ACC_INTR_GATE)
526 GATE_ENTRY(APIC_IRQ_BASE - 2, entry_debug_ipi, ACC_PL_K | ACC_INTR_GATE)
527 GATE_ENTRY(APIC_IRQ_BASE - 1, entry_ipi_remote_request, ACC_PL_K | ACC_INTR_GATE)
532 .globl alien_sys_ipc_c /* Also used in shortcut */
539 #if defined (CONFIG_JDB)
548 * input: eax: address to syscall function
549 * output: eax: error code
551 .macro SC_ADDR_TO_ERR val
552 sub $syscall_table , %eax /* eax = byte offset to syscall */
553 shr $2, %eax /* convert eax to syscall nr */
554 add $0x30, %eax /* convert eax to syscall int nr */
555 shl $3, %eax /* construct error code */
556 orl $\val, %eax /* -"- */
560 btrl $17, OFS__THREAD__STATE (%ebx) /* Thread_dis_alien */
563 sub $2, 4(%esp) /* Correct EIP to point to insn */
570 1: /* do alien syscall and trap afterwards */
571 RESET_THREAD_CANCEL_AT %ebx
573 call *(%eax) /* call with ENABLED interrupts */
575 CHECK_SANITY $3 /* scratches ecx */
583 .globl leave_by_trigger_exception
584 leave_by_trigger_exception:
586 subl $12,%esp /* clean up stack from previous
589 call thread_restore_exc_state
597 .globl leave_by_vcpu_upcall
598 leave_by_vcpu_upcall:
600 subl $12,%esp /* clean up stack from previous
603 call thread_restore_exc_state
606 mov OFS__THREAD__USER_VCPU(%ecx), %eax /* vcpu state pointer from TCB */
607 mov OFS__THREAD__VCPU_STATE(%ecx), %ecx /* vcpu state pointer from TCB */
608 addl $(VAL__SIZEOF_TRAP_STATE - 20), %ecx /* skip return frame */
609 mov SCRATCH_REGISTER_SIZE(%esp), %edx
610 mov %edx, (%ecx) /* EIP */
611 mov 8 + SCRATCH_REGISTER_SIZE(%esp), %edx
612 mov %edx, 8(%ecx) /* EFLAGS */
613 mov 12 + SCRATCH_REGISTER_SIZE(%esp), %edx
614 mov %edx, 12(%ecx) /* ESP */
615 mov 16 + SCRATCH_REGISTER_SIZE(%esp), %edx
616 mov %edx, 16(%ecx) /* SS */
618 mov 0(%esp), %edx /* EDX */
620 mov 4(%esp), %edx /* ECX */
622 mov 8(%esp), %edx /* EAX */
629 sub $4, %esp /* SKIP PFA */
634 /*add SCRATCH_REGISTER_SIZE, %esp*/
636 pushl REG_FS /* we save the segment regs in the trap */
637 pushl REG_GS /* state, but we do not restore them. We */
638 pushl %ds /* rather reload them using */
639 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
642 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_SP(%ecx), %edx
644 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_IP(%ecx), %edx
646 movl $EFLAGS_IF, 8(%esp)
653 addl $(2*4), %esp // skip es and ds for now
662 // fast return from Dirq::hit
664 .globl fast_ret_from_irq
666 CHECK_SANITY $3 // scratches ecx
667 RESTORE_STATE_AFTER_IPC
669 andl $0x7f, 4(%esp) // if entered using sysenter
670 orl $EFLAGS_IF, 8(%esp) // if entered using sysenter