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 .macro EXCEPTION n, name
28 GATE_ENTRY \n, entry_\name, (ACC_PL_K | ACC_INTR_GATE)
38 * User-accessible exception. Otherwise, same as above.
40 .macro EXCEP_USR n,name
41 GATE_ENTRY \n, entry_\name, (ACC_PL_U | ACC_INTR_GATE)
51 * Error code has been pushed. Just push trap number.
53 .macro EXCEP_ERR n, name
54 GATE_ENTRY \n, entry_\name, (ACC_PL_K | ACC_INTR_GATE)
63 btrl $17, OFS__THREAD__STATE (%ebx) /* Thread_dis_alien */
66 sub $2, 4(%esp) /* Correct EIP to point to insn */
68 pushl $(0x30 << 3 | 2)
73 1: /* do alien IPC and raise a trap afterwards */
74 RESET_THREAD_CANCEL_AT %ebx
78 CHECK_SANITY $3 /* scratches ecx */
79 RESTORE_STATE_AFTER_IPC
81 pushl $(0x30 << 3 | 6)
87 GATE_INITTAB_BEGIN idt_init_table
89 EXCEPTION 0x00, vec00_zero_div
91 EXCEPTION 0x01, vec01_debug
93 /* IA32 has to handle breakpoint exceptions if occured exactly at
94 entry_sys_fast_ipc -- see ia32/entry-ia32.S */
95 GATE_ENTRY 0x01, entry_vec01_debug, (ACC_PL_K | ACC_INTR_GATE)
97 /* XXX IA32 has to handle NMI occured exactly at entry_sys_fast_ipc */
98 EXCEP_USR 0x02, vec02_nmi
99 EXCEP_USR 0x03, vec03_breakpoint
100 EXCEP_USR 0x04, vec04_into
101 EXCEP_USR 0x05, vec05_bounds
102 EXCEPTION 0x06, vec06_invop
103 # EXCEPTION 0x07, nofpu
105 EXCEP_ERR 0x08, vec08_dbl_fault
107 GATE_ENTRY 0x08, GDT_TSS_DBF, (ACC_PL_K | ACC_TASK_GATE)
109 EXCEPTION 0x09, vec09_fpu_ovfl
110 # EXCEP_ERR 0x0a, vec0a_inv_tss
111 EXCEP_ERR 0x0b, vec0b_segnp
112 EXCEP_ERR 0x0c, vec0c_stack_fault
113 EXCEP_ERR 0x0d, vec0d_gen_prot
114 # EXCEP_ERR 0x0e, vec0e_page_fault
115 # EXCEPTION 0x0f, vec0f_trap_0f
116 EXCEPTION 0x10, vec10_fpu_err
117 EXCEP_ERR 0x11, vec11_align
118 EXCEPTION 0x12, vec12_mcheck
119 EXCEPTION 0x13, vec13_simd_err
123 .type slowtraps,@function
125 /* We have to introduce the label .L_slowtraps besides the label
126 slowtraps to achieve that jmps from exception entry points
127 are optimized to two-byte jmps. The label slowtraps is visible
132 # define REG_GS CPU_GS
133 # define REG_FS CPU_FS
139 pushl REG_FS /* we save the segment regs in the trap */
140 pushl REG_GS /* state, but we do not restore them. We */
141 pushl %ds /* rather reload them using */
142 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
146 /* Load the kernel's segment registers. */
147 RESET_KERNEL_SEGMENTS_FORCE_DS_ES /* scratches ecx, edx */
149 /* Note: we do not use RESET_THREAD_CANCEL_* here as that is
150 needed only when an I/O-page-fault IPC is sent and when the
151 thread is killed. Resetting Thread_cancel here could
152 be harmful when using this trap handler in debugging.
153 Instead, we clear this flag in Thread::handle_slow_trap()
154 just before sending the IPC message or before killing the
155 thread. That's OK, because it is still atomic -- we never
156 enable IRQs (sti) before that point. */
158 movl %esp,%eax /* ARG1: address of trap_state */
159 xorl %edx,%edx /* ARG2: default CPU = 0 */
160 #ifndef CONFIG_NO_FRAME_PTR
161 pushl OFS__TRAP_STATE__IP(%esp) /* create artificial stack frame */
166 /* Call the C handler function if one has been installed. */
167 movl BASE_TRAP_HANDLER, %ecx
169 jz .Lunexpected_trap_pop
173 #ifndef CONFIG_NO_FRAME_PTR
177 /* If the handler function returned zero (success),
178 then resume execution as if the trap never happened.
179 Otherwise, just panic. */
181 jnz .Lunexpected_trap
183 CHECK_SANITY 60(%esp) /* scratches ecx */
185 addl $4*2,%esp /* Pop ds, es segment registers */
187 popl REG_FS /* Restore segment registers */
189 addl $4*2,%esp /* Pop trap number and error code */
192 .Lunexpected_trap_pop:
193 #ifndef CONFIG_NO_FRAME_PTR
204 GATE_ENTRY 0x0e, entry_vec0e_page_fault, (ACC_PL_K | ACC_INTR_GATE)
206 /* we must save %cr2 before we can be preempted -- therefore we're an
207 interrupt gate (invoked with interrupts turned off). Also, we
208 don't turn them on again here, but only after checking for
209 page-ins from the global page directory in thread_page_fault().
210 XXX: If you make changes to stack layout here, fix thread_page_fault */
212 /* XXX slow version - sets up nice stack frame for debugger */
215 .type entry_vec0e_page_fault,@function
216 entry_vec0e_page_fault:
219 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
220 movl 12(%esp),%edx /* save error code in ARG2 ... */
221 movl PAGE_FAULT_ADDR,%eax /* save page fault address in ARG1 */
223 /* We must reset the cancel flag here atomically
224 if we are entering fresh from user mode and an IPC might occur.
225 NOTE: We cannot test the user-mode bit in the error code because
226 it will flag "kernel" in case an I/O-bitmap page is not mapped
227 during an I/O access. */
229 movl 20(%esp),%ecx /* get CS from stack */
230 andb $3,%cl /* retrieve current privilege level (CPL) */
231 jz 1f /* CPL == 0 -> kernel, skip resetting state */
233 RESET_THREAD_CANCEL_AT %ecx
234 1: movl %ebp,12(%esp) /* save frame pointer */
235 leal 12(%esp),%ebp /* load new frame pointer */
236 pushl %eax /* save pf address */
237 pushl %edx /* save error code */
238 leal 24(%esp),%ecx /* ARG5: ptr to Return_frame */
240 pushl 36(%esp) /* ARG4: eflags */
241 movl 32(%esp),%ecx /* ARG3: eip */
242 call thread_page_fault
248 CHECK_SANITY 20(%esp) /* scratches ecx */
253 /* recover from a bad page fault by invoking the slow_trap handler */
257 addl $8,%esp /* pop ARG4 and ARG5 */
258 movl (%ebp),%eax /* old ebp */
259 popl (%ebp) /* error code */
260 popl %edx /* page fault address */
263 /* we have on stack: error code, eax, ecx, edx
264 move registers down to make room for trap number */
272 movl $0x0e,12(%esp) /* error code */
273 pushl %ebx /* rest of trap state */
274 pushl %edx /* page fault address */
281 /* FPU not available in this context. */
282 GATE_ENTRY 0x07, entry_vec07_fpu_unavail, (ACC_PL_K | ACC_INTR_GATE)
284 /* do all of this with disabled interrupts */
286 .type entry_vec07_fpu_unavail,@function
287 entry_vec07_fpu_unavail:
290 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
291 call thread_handle_fputrap
293 CHECK_SANITY 16(%esp) /* scratches ecx */
295 jz .Lreal_fpu_exception
298 .Lreal_fpu_exception:
306 /* timer interrupt */
307 #ifdef CONFIG_SCHED_PIT
308 GATE_ENTRY 0x20, entry_int_timer, (ACC_PL_K | ACC_INTR_GATE)
310 #ifdef CONFIG_SCHED_RTC
311 GATE_ENTRY 0x28, entry_int_timer, (ACC_PL_K | ACC_INTR_GATE)
313 #ifdef CONFIG_SCHED_APIC
314 GATE_ENTRY APIC_IRQ_BASE, entry_int_timer, (ACC_PL_K | ACC_INTR_GATE)
316 #ifdef CONFIG_SCHED_HPET
317 /* HPET is set at startup */
321 .globl entry_int_timer
323 #ifndef CONFIG_NO_FRAME_PTR
328 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
330 .Ldo_timer_interrupt:
331 #ifdef CONFIG_NO_FRAME_PTR
332 movl 12(%esp), %eax /* ARG1: eip for logging */
334 movl 16(%esp), %eax /* ARG1: eip for logging */
336 call thread_timer_interrupt /* enter with disabled irqs */
338 #ifndef CONFIG_NO_FRAME_PTR
339 CHECK_SANITY 20(%esp) /* scratches ecx */
341 CHECK_SANITY 16(%esp) /* scratches ecx */
344 #ifndef CONFIG_NO_FRAME_PTR
350 .globl entry_int_timer_slow
351 entry_int_timer_slow:
352 #ifndef CONFIG_NO_FRAME_PTR
357 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
360 call thread_timer_interrupt_slow /* enter with disabled irqs */
361 in_timer_interrupt_slow:
362 jmp .Ldo_timer_interrupt
366 .globl entry_int_timer_stop
367 entry_int_timer_stop:
368 #ifndef CONFIG_NO_FRAME_PTR
374 call thread_timer_interrupt_stop
375 #ifndef CONFIG_NO_FRAME_PTR
376 CHECK_SANITY 20(%esp) /* scratches ecx */
378 CHECK_SANITY 16(%esp) /* scratches ecx */
381 #ifndef CONFIG_NO_FRAME_PTR
387 /* other interrupts */
389 .macro INTERRUPT int, name
390 GATE_ENTRY \int, entry_\name, (ACC_PL_K | ACC_INTR_GATE)
394 movl $ (\int - 0x20), %eax /* ARG1: irqnum */
398 #ifndef CONFIG_SCHED_PIT
401 /* spurious IRQ handlers */
402 GATE_ENTRY 0x27, entry_int_pic_ignore, (ACC_PL_K | ACC_INTR_GATE)
403 GATE_ENTRY 0x2f, entry_int_pic_ignore, (ACC_PL_K | ACC_INTR_GATE)
404 #ifndef CONFIG_SCHED_RTC
409 .type .Lall_irqs,@function
410 .type __generic_irq_entry,@function
411 .global __generic_irq_entry
417 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
418 movl 12(%esp), %edx /* ARG2: eip */
419 call irq_interrupt /* enter with disabled irqs */
421 CHECK_SANITY 16(%esp) /* scratches ecx */
426 entry_int_pic_ignore:
429 .global entry_int_pic_ignore
433 /****************************************************************************/
435 /****************************************************************************/
437 GATE_ENTRY 0x30, entry_sys_ipc_c, (ACC_PL_U | ACC_INTR_GATE)
440 .globl entry_sys_ipc_c
445 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
447 testl $VAL__Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
448 jnz .Lalien_sys_ipc_c
449 RESET_THREAD_CANCEL_AT %ebx
450 call sys_ipc_wrapper //ipc_short_cut_wrapper
452 CHECK_SANITY $3 /* scratches ecx */
453 RESTORE_STATE_AFTER_IPC
460 /* The slow variant of sys_ipc_entry is used when logging IPC */
462 .globl entry_sys_ipc_log
467 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
469 testl $VAL__Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
470 jnz .Lalien_sys_ipc_log
471 RESET_THREAD_CANCEL_AT %ebx
474 CHECK_SANITY $3 /* scratches ecx */
475 RESTORE_STATE_AFTER_IPC
482 // these labels help show_tcb to guess the thread state
486 .globl in_handle_fputrap
488 .globl in_timer_interrupt
489 .globl in_timer_interrupt_slow
491 .macro SYSTEM_CALL int, name
492 GATE_ENTRY \int, entry_\name, (ACC_PL_U | ACC_INTR_GATE)
496 movl $(syscall_table+4*(\int-0x30)), %eax
501 .type .Lall_syscalls,@function
505 RESET_KERNEL_SEGMENTS_FORCE_DS_ES
507 testl $VAL__Thread_alien_or_vcpu_user, OFS__THREAD__STATE (%ebx)
509 RESET_THREAD_CANCEL_AT %ebx
510 call *(%eax) /* interrupts enabled in wrappers */
514 CHECK_SANITY $3 /* scratches ecx */
520 SYSTEM_CALL 0x32, sys_invoke_debug
523 /* these functions are implemented in entry-native.S */
524 GATE_ENTRY 0x0a, entry_vec0a_invalid_tss, (ACC_PL_K | ACC_INTR_GATE)
525 GATE_ENTRY 0x0f, entry_vec0f_apic_spurious_interrupt_bug, (ACC_PL_K | ACC_INTR_GATE)
526 GATE_ENTRY (APIC_IRQ_BASE + 3), entry_apic_error_interrupt, (ACC_PL_K | ACC_INTR_GATE)
527 GATE_ENTRY (APIC_IRQ_BASE + 4), entry_apic_spurious_interrupt, (ACC_PL_K | ACC_INTR_GATE)
531 GATE_ENTRY (APIC_IRQ_BASE + 2), entry_ipi, (ACC_PL_K | ACC_INTR_GATE)
532 GATE_ENTRY (APIC_IRQ_BASE - 2), entry_debug_ipi, (ACC_PL_K | ACC_INTR_GATE)
533 GATE_ENTRY (APIC_IRQ_BASE - 1), entry_ipi_remote_request, (ACC_PL_K | ACC_INTR_GATE)
543 #if defined (CONFIG_JDB)
551 * input: eax: address to syscall function
552 * output: eax: error code
554 .macro SC_ADDR_TO_ERR val
555 sub $syscall_table , %eax /* eax = byte offset to syscall */
556 shr $2, %eax /* convert eax to syscall nr */
557 add $0x30, %eax /* convert eax to syscall int nr */
558 shl $3, %eax /* construct error code */
559 orl $\val, %eax /* -"- */
563 btrl $17, OFS__THREAD__STATE (%ebx) /* Thread_dis_alien */
566 sub $2, 4(%esp) /* Correct EIP to point to insn */
573 1: /* do alien syscall and trap afterwards */
574 RESET_THREAD_CANCEL_AT %ebx
576 call *(%eax) /* call with ENABLED interrupts */
578 CHECK_SANITY $3 /* scratches ecx */
586 .globl leave_by_trigger_exception
587 leave_by_trigger_exception:
588 subl $12,%esp /* clean up stack from previous
591 call thread_restore_exc_state
599 .globl leave_by_vcpu_upcall
600 leave_by_vcpu_upcall:
601 subl $12,%esp /* clean up stack from previous
604 call thread_restore_exc_state
607 mov OFS__THREAD__USER_VCPU(%ecx), %eax /* vcpu state pointer from TCB */
608 mov OFS__THREAD__VCPU_STATE(%ecx), %ecx /* vcpu state pointer from TCB */
609 addl $(VAL__SIZEOF_TRAP_STATE - 20), %ecx /* skip return frame */
610 mov SCRATCH_REGISTER_SIZE(%esp), %edx
611 mov %edx, (%ecx) /* EIP */
612 mov 8 + SCRATCH_REGISTER_SIZE(%esp), %edx
613 mov %edx, 8(%ecx) /* EFLAGS */
614 mov 12 + SCRATCH_REGISTER_SIZE(%esp), %edx
615 mov %edx, 12(%ecx) /* ESP */
616 mov 16 + SCRATCH_REGISTER_SIZE(%esp), %edx
617 mov %edx, 16(%ecx) /* SS */
619 mov 0(%esp), %edx /* EDX */
621 mov 4(%esp), %edx /* ECX */
623 mov 8(%esp), %edx /* EAX */
630 sub $4, %esp /* SKIP PFA */
635 /*add SCRATCH_REGISTER_SIZE, %esp*/
637 pushl REG_FS /* we save the segment regs in the trap */
638 pushl REG_GS /* state, but we do not restore them. We */
639 pushl %ds /* rather reload them using */
640 pushl %es /* RESET_{KERNEL,USER}_SEGMENTS */
643 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_SP(%ecx), %edx
645 mov -VAL__SIZEOF_TRAP_STATE + 20 + OFS__VCPU_STATE__ENTRY_IP(%ecx), %edx
647 movl $EFLAGS_IF, 8(%esp)
654 addl $(2*4), %esp // skip es and ds for now
663 // fast return from Dirq::hit
665 .globl fast_ret_from_irq
667 CHECK_SANITY $3 // scratches ecx
668 RESTORE_STATE_AFTER_IPC
670 andl $0x7f, 4(%esp) // if entered using sysenter