]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/64/entry.S
b8c4ae104cbca476b645aca6027db723bdff630c
[l4.git] / kernel / fiasco / src / kern / ia32 / 64 / entry.S
1 /*
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.
6  */
7
8 #include "config_tcbsize.h"
9 #include "config_gdt.h"
10 #include "globalconfig.h"
11 #include "idt_init.h"
12 #include <low_level.h>
13 #include "shortcut.h"
14 #include "tcboffset.h"
15
16 #include "asm.h"
17
18
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). */
23
24 /*
25  * No error code.  Clear error code and push trap number.
26  */
27 #define EXCEPTION(n,name)                                       \
28         GATE_ENTRY(n,entry_##name,ACC_PL_K | ACC_INTR_GATE)     ;\
29         .p2align 3                                              ;\
30 entry_##name:                                                   ;\
31         push    $(0)                                            ;\
32         push    $(n)                                            ;\
33         save_all_regs                                           ;\
34         jmp     _slowtraps
35
36 /*
37  * User-accessible exception.  Otherwise, same as above.
38  */
39 #define EXCEP_USR(n,name)                                       \
40         GATE_ENTRY(n,entry_##name,ACC_PL_U | ACC_INTR_GATE)     ;\
41         .p2align 3                                              ;\
42 entry_##name:                                                   ;\
43         push    $(0)                                            ;\
44         push    $(n)                                            ;\
45         save_all_regs                                           ;\
46         jmp     _slowtraps
47
48 /*
49  * Error code has been pushed.  Just push trap number.
50  */
51 #define EXCEP_ERR(n,name)                                       \
52         GATE_ENTRY(n,entry_##name,ACC_PL_K | ACC_INTR_GATE)     ;\
53         .p2align 3                                              ;\
54 entry_##name:                                                   ;\
55         push    $(n)                                            ;\
56         save_all_regs                                           ;\
57         jmp     _slowtraps
58
59 GATE_INITTAB_BEGIN(idt_init_table)
60
61 EXCEPTION(0x00,vec00_zero_div)
62 /* IA32 has to handle breakpoint exceptions if occured exactly at 
63    entry_sys_fast_ipc -- see ia32/entry-ia32.S */
64 GATE_ENTRY(0x01,entry_vec01_debug,ACC_PL_K | ACC_INTR_GATE)
65 /* XXX IA32 has to handle NMI occured exactly at entry_sys_fast_ipc */
66 EXCEP_USR(0x02,vec02_nmi)
67 EXCEP_USR(0x03,vec03_breakpoint)
68 EXCEP_USR(0x04,vec04_into)
69 EXCEP_USR(0x05,vec05_bounds)
70 EXCEPTION(0x06,vec06_invop)
71 /* EXCEPTION(0x07,nofpu) */
72 // XXX we can't use a task gate, instead we must use IST
73 GATE_ENTRY(0x08,entry_vec08_dbf, ACC_PL_K | ACC_INTR_GATE)
74 EXCEPTION(0x09,vec09_fpu_ovfl)
75 /* EXCEP_ERR(0x0a,vec0a_inv_tss) */
76 EXCEP_ERR(0x0b,vec0b_segnp)
77 EXCEP_ERR(0x0c,vec0c_stack_fault)
78 EXCEP_ERR(0x0d,vec0d_gen_prot)
79 /* EXCEP_ERR(0x0e,vec0e_page_fault) */
80 /* EXCEPTION(0x0f,vec0f_trap_0f) */
81 EXCEPTION(0x10,vec10_fpu_err)
82 EXCEP_ERR(0x11,vec11_align)
83 EXCEPTION(0x12,vec12_mcheck)
84 EXCEPTION(0x13,vec13_simd_err)
85
86
87         .p2align 4
88         .type   slowtraps,@function
89         .globl  slowtraps
90         /* We have to introduce the label _slowtraps besides the label
91            slowtraps to achive that jmps from exception entry points
92            are optimized to two-byte jmps. The label slowtraps is visible
93            from outside. */
94 _slowtraps:
95 slowtraps:
96         mov     %rsp,%rdi               /* ARG1: address of trap_state */
97         mov     $0, %esi                /* ARG2: default CPU = 0 */
98         cld
99 #ifndef CONFIG_NO_FRAME_PTR
100         mov     0x90(%rsp),%rax         /* create artificial stack frame */
101         push    %rax                    /* push rip */
102         push    %rbp
103 # ifndef CONFIG_PROFILE
104         lea     (%rsp),%rbp
105 # endif
106 #endif
107
108         /* Call the C handler function if one has been installed.  */
109         mov     BASE_TRAP_HANDLER, %rax
110         or      %rax,%rax
111         jz      unexpected_trap_pop
112         call    *%rax
113 in_slowtrap:
114
115 #ifndef CONFIG_NO_FRAME_PTR
116         lea     0x10(%rsp),%rsp         /* remove frame pointer */
117 #endif
118
119         /* If the handler function returned zero (success),
120            then resume execution as if the trap never happened.
121            Otherwise, just panic.  */
122         or      %rax,%rax
123         jnz     unexpected_trap
124
125         restore_all_regs
126         add     $0x10,%rsp              /* pop trap number and error code */
127         iretq
128
129 unexpected_trap_pop:
130 #ifndef CONFIG_NO_FRAME_PTR
131         lea     0x10(%rsp), %rsp        /* remove stack frame */
132 #endif
133
134 unexpected_trap:
135         mov     %rsp,%rdi               /* 1st arg: trap state */
136         call    trap_dump_panic
137
138 GATE_ENTRY(0x0e,entry_vec0e_page_fault,ACC_PL_K | ACC_INTR_GATE)
139
140 /* we must save %cr2 before we can be preempted -- therefore we're an
141    interrupt gate (invoked with interrupts turned off).  Also, we
142    don't turn them on again here, but only after checking for
143    page-ins from the global page directory in thread_page_fault().
144    XXX: If you make changes to stack layout here, fix thread_page_fault */
145
146 /* XXX slow version - sets up nice stack frame for debugger */
147
148         .p2align 4
149         .type   entry_vec0e_page_fault,@function
150 .globl entry_vec0e_page_fault
151 entry_vec0e_page_fault:
152         cld
153         SAVE_SCRATCH
154
155 /* We must reset the cancel flag here atomically
156    if we are entering fresh from user mode and an IPC might occur.
157    NOTE: We cannot test the user-mode bit in the error code because
158    it will flag "kernel" in case an I/O-bitmap page is not mapped
159    during an I/O access. */
160
161         mov     0x58(%rsp),%rcx   /* get CS from stack */
162         andb    $3,%cl          /* retrieve current privilege level (CPL) */
163         jz      1f              /* CPL == 0 -> kernel, skip resetting state */
164         ESP_TO_TCB_AT %rcx
165         RESET_THREAD_CANCEL_AT %rcx
166 1:
167         leaq    0x50(%rsp),%r8          /* arg5: ptr to return frame */
168         mov     PAGE_FAULT_ADDR,%rdi    /* arg1: page fault address */
169         mov     0x48(%rsp),%rsi         /* arg2: error code */
170         mov     0x50(%rsp),%rdx         /* arg3: rip */
171         mov     0x60(%rsp),%rcx         /* arg4: rflags */
172         call    thread_page_fault
173
174 in_page_fault:
175         or      %rax,%rax
176         jz      bad_page_fault
177         RESTORE_SCRATCH
178         add     $8,%rsp                         /* remove error code */
179         iretq
180
181 /* If code or stack from a small address space are not yet mapped in the
182    current page directory we might get a page fault on return from the
183    trampoline page. In this case we cannot return to the trampoline page
184    after handling the fault because we are already in user mode (with
185    segment limits below kernel space) while the trampoline code is located
186    in kernel data space. So instead we change ESP and EIP to point to the
187    address the trampoline wanted to return to and do the normal IRET. */
188
189 /* recover from a bad page fault by invoking the slow_trap handler */
190         .p2align 4
191 bad_page_fault:
192         cli
193         /* we have on stack: r8, rdi, rsi, rdx, rcx, rax, error code
194            move registers down to make room for trap number 
195            and build complete trap state before  jumping to trap handler */
196         RESTORE_SCRATCH
197         pushq   $0x0e
198         save_all_regs
199         jmp     slowtraps
200
201
202 /* FPU not available in this context. */
203 GATE_ENTRY(0x07,entry_vec07_fpu_unavail, ACC_PL_K | ACC_INTR_GATE)
204
205 /* do all of this with disabled interrupts */
206         .p2align 4
207         .type   entry_vec07_fpu_unavail,@function
208 entry_vec07_fpu_unavail:
209         cld
210         SAVE_SCRATCH
211         mov     SCRATCH_REGISTER_SIZE(%rsp), %rdi
212         call    thread_handle_fputrap
213 in_handle_fputrap:
214         test    %eax,%eax
215         jz      real_fpu_exception
216         RESTORE_SCRATCH
217         iretq
218 real_fpu_exception:
219         RESTORE_SCRATCH
220         pushq   $(0)
221         pushq   $(7)
222         save_all_regs
223         jmp     _slowtraps
224
225
226 /* timer interrupt */
227 #ifdef CONFIG_SCHED_PIT
228 GATE_ENTRY(0x20,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
229 #endif
230 #ifdef CONFIG_SCHED_RTC
231 GATE_ENTRY(0x28,entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
232 #endif
233 #ifdef CONFIG_SCHED_APIC
234 GATE_ENTRY(APIC_IRQ_BASE, entry_int_timer,ACC_PL_K | ACC_INTR_GATE)
235 #endif
236 #ifdef CONFIG_SCHED_HPET
237 /* HPET is set at startup */
238 #endif
239
240         .p2align 4
241         .globl  entry_int_timer
242 entry_int_timer:
243         SAVE_SCRATCH
244 do_timer_interrupt:
245         cld
246         mov     SCRATCH_REGISTER_SIZE(%rsp),%rdi /* pass rip for logging */
247         call    thread_timer_interrupt          /* enter with disabled irqs */
248 in_timer_interrupt:
249         RESTORE_SCRATCH
250         iretq
251
252         .p2align 4
253         .globl  entry_int_timer_slow
254 entry_int_timer_slow:
255         cld
256         SAVE_SCRATCH
257         call    thread_timer_interrupt_slow     /* enter with disabled irqs */
258 in_timer_interrupt_slow:
259         jmp     do_timer_interrupt
260
261         
262         .p2align 4
263         .globl  entry_int_timer_stop
264 entry_int_timer_stop:
265         cld
266         SAVE_SCRATCH
267         call    thread_timer_interrupt_stop
268         RESTORE_SCRATCH
269         iretq
270
271 /* other interrupts */
272
273 #define INTERRUPT(int,name)                                     \
274         GATE_ENTRY(int,entry_##name,ACC_PL_K | ACC_INTR_GATE)   ;\
275         .p2align 3                                              ;\
276 entry_##name:                                                   ;\
277         SAVE_SCRATCH                                            ;\
278         mov     0x28(%rsp),%rsi                                 ;\
279         mov     $ (int - 0x20),%rdi                             ;\
280         jmp     all_irqs
281
282         .type __generic_irq_entry,@function
283         .global __generic_irq_entry
284
285 __generic_irq_entry:
286         push    %rsi
287         push    %rax
288         push    %rcx
289         push    %rdx
290         push    %r8
291         push    %r9
292         push    %r10
293         push    %r11
294
295         .p2align 4
296         .type   all_irqs,@function
297 all_irqs:
298         cld
299         call    irq_interrupt                   /* enter with disabled irqs */
300 in_interrupt:
301         RESTORE_SCRATCH
302
303 entry_int_pic_ignore:
304         iretq
305
306         .global entry_int_pic_ignore
307         .global entry_int7
308         .global entry_intf
309
310 #ifndef CONFIG_SCHED_PIT
311 INTERRUPT(0x20,int0)
312 #endif
313 INTERRUPT(0x27,int7)
314 INTERRUPT(0x2f,intf)
315 #ifndef CONFIG_SCHED_RTC
316 INTERRUPT(0x28,int8)
317 #endif
318
319 /* system calls */
320 #define SYSTEM_CALL(int,name)                                   \
321         GATE_ENTRY(int,entry_##name,ACC_PL_U | ACC_INTR_GATE)   ;\
322         .p2align 4                                              ;\
323 entry_##name:                                                   ;\
324         push    %rax                                            ;\
325         mov     $(syscall_table+8*(int-0x30)), %rax             ;\
326         jmp     all_syscalls
327
328         .p2align 4
329         .type   all_syscalls,@function
330 all_syscalls:
331         cld
332         SAVE_STATE
333         ESP_TO_TCB_AT %rbx
334         RESET_THREAD_CANCEL_AT %rbx
335
336         call    *(%rax)
337 in_syscall:
338 ret_from_syscall:
339         RESTORE_STATE
340         pop     %rax
341         iretq
342
343 #ifdef CONFIG_ASSEMBLER_IPC_SHORTCUT
344 GATE_ENTRY(0x30,entry_sys_ipc,ACC_PL_U | ACC_INTR_GATE);
345 #else
346 GATE_ENTRY(0x30,entry_sys_ipc_c,ACC_PL_U | ACC_INTR_GATE);
347 #endif
348
349 #if defined (CONFIG_JDB_LOGGING) || !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT)
350         .p2align 4
351         .globl  entry_sys_ipc_c
352 entry_sys_ipc_c:
353         cld
354         push    %rax
355         SAVE_STATE
356         ESP_TO_TCB_AT %rbx
357         RESET_THREAD_CANCEL_AT %rbx
358
359
360         call    sys_ipc_wrapper
361 in_sc_ipc1:
362         RESTORE_STATE
363         pop     %rax
364         iretq
365
366         .globl  in_sc_ipc1
367 #endif
368
369 #ifdef CONFIG_JDB
370         /* The slow variant of sys_ipc_entry is used when logging IPC */
371         .p2align 4
372         .globl  entry_sys_ipc_log
373
374 entry_sys_ipc_log:
375         cld
376         push    %rax
377         SAVE_STATE
378         ESP_TO_TCB_AT %rbx
379         RESET_THREAD_CANCEL_AT %rbx
380         call    *syscall_table
381
382 in_slow_ipc4:
383         RESTORE_STATE
384         pop     %rax
385         iretq
386
387         .globl  in_slow_ipc4
388 #endif // CONFIG_JDB
389
390         // these labels help show_tcb to guess the thread state
391         .globl  in_syscall
392         .globl  in_slowtrap
393         .globl  in_page_fault
394         .globl  in_handle_fputrap
395         .globl  in_interrupt  
396         .globl  in_timer_interrupt
397         .globl  in_timer_interrupt_slow
398
399
400 SYSTEM_CALL(0x32,sys_invoke_debug)
401
402 /* these functions are implemented in entry-native.S */
403 GATE_ENTRY(0x0a,entry_vec0a_invalid_tss,ACC_PL_K | ACC_INTR_GATE)
404 GATE_ENTRY(0x0f,entry_vec0f_apic_spurious_interrupt_bug,ACC_PL_K | ACC_INTR_GATE)
405 GATE_ENTRY(APIC_IRQ_BASE + 3,entry_apic_error_interrupt,ACC_PL_K | ACC_INTR_GATE)
406 GATE_ENTRY(APIC_IRQ_BASE + 0xf,entry_apic_spurious_interrupt,ACC_PL_K | ACC_INTR_GATE)
407
408 #ifdef CONFIG_MP
409 GATE_ENTRY(APIC_IRQ_BASE + 2, entry_ipi, ACC_PL_K | ACC_INTR_GATE)
410 GATE_ENTRY(APIC_IRQ_BASE - 2, entry_debug_ipi, ACC_PL_K | ACC_INTR_GATE)
411 GATE_ENTRY(APIC_IRQ_BASE - 1, entry_ipi_remote_request, ACC_PL_K | ACC_INTR_GATE)
412 #endif
413
414 GATE_INITTAB_END
415
416         .p2align
417         .globl  leave_by_trigger_exception
418 leave_by_trigger_exception:
419         sub $40, %rsp
420         pushq   $0x00
421         pushq   $0xff
422         save_all_regs
423         pushq   $_slowtraps
424         jmp     thread_restore_exc_state
425
426
427         .p2align
428         .globl  leave_by_vcpu_upcall
429 leave_by_vcpu_upcall:
430         cli
431         sub     $40,%rsp                /* clean up stack from previous
432                                          * CPL0-CPL0 iret */
433         SAVE_SCRATCH
434         call    thread_restore_exc_state
435
436         ESP_TO_TCB_AT %rcx
437         mov OFS__THREAD__USER_VCPU(%rcx), %rdi
438         mov OFS__THREAD__VCPU_STATE(%rcx), %rcx
439         add $(VAL__SIZEOF_TRAP_STATE - 40), %rcx
440         mov SCRATCH_REGISTER_SIZE(%rsp),  %rdx
441         mov %rdx, (%rcx)                            /* RIP */
442         mov 16 + SCRATCH_REGISTER_SIZE(%rsp),  %rdx
443         mov %rdx, 16(%rcx)                          /* RFLAGS */
444         mov 24 + SCRATCH_REGISTER_SIZE(%rsp), %rdx
445         mov %rdx, 24(%rcx)                          /* RSP */
446         mov 32 + SCRATCH_REGISTER_SIZE(%rsp), %rdx
447         mov %rdx, 32(%rcx)                          /* SS */
448
449         mov 0(%rsp), %rdx   /* R11 */
450         mov %rdx, -(14*8)(%rcx)
451         mov 8(%rsp), %rdx   /* R10 */
452         mov %rdx, -(13*8)(%rcx)
453         mov (2*8)(%rsp), %rdx
454         mov %rdx, -(12*8)(%rcx)
455         mov (3*8)(%rsp), %rdx
456         mov %rdx, -(11*8)(%rcx)
457         mov (4*8)(%rsp), %rdx
458         mov %rdx, -(5*8)(%rcx)
459         mov (5*8)(%rsp), %rdx
460         mov %rdx, -(4*8)(%rcx)
461         mov (6*8)(%rsp), %rdx
462         mov %rdx, -(3*8)(%rcx)
463         mov (7*8)(%rsp), %rdx
464         mov %rdx, -(9*8)(%rcx)
465         mov (8*8)(%rsp), %rdx
466         mov %rdx, -(10*8)(%rcx)
467
468         lea SCRATCH_REGISTER_SIZE(%rsp), %rdx
469         lea -(5*8)(%rcx), %rsp
470
471         push %rbx
472         sub $8, %rsp
473         push %rbp
474
475         /*add SCRATCH_REGISTER_SIZE, %esp*/
476 #if 0
477 #ifdef CONFIG_PF_UX
478 # define REG_GS CPU_GS
479 #else
480 # define REG_GS %gs
481 #endif
482
483         pushq   %fs             /* we save the segment regs in the trap   */
484         pushq   REG_GS          /* state, but we do not restore them.  We */
485         pushq   %ds             /* rather reload them using               */
486         pushq   %es             /* RESET_{KERNEL,USER}_SEGMENTS           */
487 #endif
488         mov %rdx, %rsp
489         mov -VAL__SIZEOF_TRAP_STATE + 40 + OFS__VCPU_STATE__ENTRY_SP(%rcx), %rax
490         mov %rax, 24(%rsp)
491         mov -VAL__SIZEOF_TRAP_STATE + 40 + OFS__VCPU_STATE__ENTRY_IP(%rcx), %rax
492         mov %rax, 0(%rsp)
493         iretq
494
495         .p2align
496         .globl  vcpu_resume
497 vcpu_resume:
498         mov %rdi, %rsp
499 #if 0
500         popq %es
501         popq %ds
502         popq REG_GS
503         popq %fs
504 #endif
505         restore_all_regs
506         add $(2*8), %rsp
507         iretq
508