]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/32/entry-native.S
be9694f6fd6505b60e54c5de41be8bed4a8725cc
[l4.git] / kernel / fiasco / src / kern / ia32 / 32 / entry-native.S
1
2 #include "config_tcbsize.h"
3 #include "config_gdt.h"
4 #include "globalconfig.h"
5 #include "idt_init.h"
6 #include <low_level.h>
7 #include "regdefs.h"
8 #include "shortcut.h"
9 #include "tcboffset.h"
10
11 .macro  PRE_FAST_ALIEN_IPC
12         btrl    $17, OFS__THREAD__STATE (%ebx)  /* Thread_dis_alien */
13         jc      1f
14         RESTORE_STATE
15         popl    %eax
16         andl    $0x7f,4(%esp)
17         orl     $EFLAGS_IF,8(%esp)
18         pushl   $(0x30 << 3 | 2)
19         pushl   $(0xd)
20         pusha
21         /* emulate entry code in KIP */
22         mov     40(%esp), %ebp         /* offset 40: eip */
23         mov     %ebp, 16(%esp)         /* offset 16: ebx */
24         movl    $(VAL__MEM_LAYOUT__SYSCALLS + 4f - 3f), 40(%esp)
25         mov     52(%esp), %ebp         /* offset 52: sp */
26         mov     %ebp, 8(%esp)          /* offset  8: ebp */
27         jmp     slowtraps
28 3: /* must be the same code as code before sysenter in syscall-page.... */
29         pop     %ebx
30         mov     %esp, %ebp
31 4: /* the code between 3 and 4 shall never be executed, it is just to calculate
32     * the offset for the sysenter insn in the KIP / syscall page
33     */
34 1:      /* do alien IPC and raise a trap afterwards */
35         RESET_THREAD_CANCEL_AT %ebx
36 .endm
37
38 .macro  POST_FAST_ALIEN_IPC
39         RESTORE_STATE_AFTER_IPC
40         popl    %eax
41         andl    $0x7f,4(%esp)
42         orl     $EFLAGS_IF, 8(%esp)
43         pushl   $(0x30 << 3 | 6)
44         pushl   $(0xd)
45         pusha
46         jmp     slowtraps
47 .endm
48
49         .p2align 4
50         .globl  entry_vec01_debug
51 entry_vec01_debug:
52 #if 0 // FIXME: figure out stuff differently
53         cmpl    $VAL__MEM_LAYOUT__TCBS, %esp
54         ja      2f
55         cmpl    $VAL__MEM_LAYOUT__TCBS_END, %esp
56         jbe     2f
57 #endif
58 1:      pushl   $0
59         pushl   $1
60         pusha
61         jmp     slowtraps
62
63 2:      /* We came from an address equal to one of the sysenter entry
64          * points. Did we also come from kernel? */
65         testl   $3,4(%esp)
66         jne     1b
67
68         /* copy last three dwords to the current kernel stack */
69         pushl   %eax
70         pushl   %ecx
71         movl    20(%esp),%ecx                   // x86_tss.esp0
72         movl     8(%esp),%eax                   // 3rd dword == EIP
73         incl    %eax                            // skip ``pop %esp''
74         movl    %eax,-12(%ecx)
75         movl    12(%esp),%eax                   // 2nd dword == CS
76         movl    %eax, -8(%ecx)
77         movl    16(%esp),%eax                   // 1st dword == EFLAGS
78         movl    %eax, -4(%ecx)
79         popl    %ecx
80         popl    %eax
81         movl    12(%esp),%esp                   // x86_tss.esp0
82         subl    $12, %esp                       // skip entry frame
83         pushl   $0
84         pushl   $1
85         pusha
86         jmp     slowtraps
87
88
89         .globl  entry_vec0a_invalid_tss
90 entry_vec0a_invalid_tss:
91         andl    $0xffffbfff, 12(%esp)
92         addl    $4, %esp                        /* skip error code */
93         iret
94
95
96         .globl  entry_vec08_dbf
97 entry_vec08_dbf:
98 #if 0 /* XXX: disable debug feature reset on double fault */
99         testl   $0xffffffff,CPU_DEBUGCTL_BUSY
100         jnz     thread_handle_double_fault
101         SAVE_SCRATCH
102         movl    CPU_DEBUGCTL_RESET, %eax
103         xorl    %edx, %edx
104         movl    $0x1d9,%ecx
105         wrmsr
106         RESTORE_SCRATCH
107 #endif
108         jmp     thread_handle_double_fault
109
110
111 /* PPro spurious interrupt bug: 
112  * See "Pentium Pro Processor Specification Update / January 1999"
113  * Erratum "Virtual Wire mode through local APIC may cause int 15"
114  * This exception can be silently ignored */
115         .p2align(4)
116         .globl  entry_vec0f_apic_spurious_interrupt_bug
117 entry_vec0f_apic_spurious_interrupt_bug:
118         pushl   %ecx
119         pushl   %edx
120         incl    apic_spurious_interrupt_bug_cnt
121         popl    %edx
122         popl    %ecx
123         iret
124
125 /* APIC error interrupt */
126         .p2align(4)
127         .globl  entry_apic_error_interrupt
128 entry_apic_error_interrupt:
129         cld
130         SAVE_SCRATCH
131         leal    SCRATCH_REGISTER_SIZE(%esp), %eax /* &Return_frame */
132         call    apic_error_interrupt
133         RESTORE_SCRATCH
134         iret
135
136 /* Intel Architecture Software Developer's Manual Volume 3,
137  * Advanced Programmable Interrupt Controller (APIC):
138  * Spurious Interrupt: "If at the time the INTA cycle is issued, the
139  * interupt that was to be dispensed has become masked (programmed by
140  * software), the local APIC will deliver a spurious-interrupt vector." */
141         .p2align(4)
142         .globl  entry_apic_spurious_interrupt
143 entry_apic_spurious_interrupt:
144         pushl   %ecx
145         pushl   %edx
146         incl    apic_spurious_interrupt_cnt
147         popl    %edx
148         popl    %ecx
149         iret
150
151         .p2align(4)
152         .global entry_int_apic_ignore
153 entry_int_apic_ignore:
154         pushl   %ecx
155         pushl   %edx
156         mov     apic_io_base, %ecx
157         mov     0xf0(%ecx), %edx
158         movl    $0, 0xb0(%ecx)
159         popl    %edx
160         popl    %ecx
161         iret
162
163 #if defined(CONFIG_JDB)
164
165         .p2align(4)
166         .global entry_sys_fast_ipc_log
167 entry_sys_fast_ipc_log:
168         pop     %esp
169         pushl   $(GDT_DATA_USER|SEL_PL_U) /* user ss */
170         pushl   %ebp                      // user esp
171 #ifdef CONFIG_IO_PROT
172         // We must not fake the interrupt flags since we must not
173         // loose the current IOPL of the user task
174         pushf
175 #else
176         // Fake user eflags, set IOPL to 3
177         pushl   $EFLAGS_IOPL_U
178 #endif
179         cld
180         // Fake user cs. This cs value is never used with exception
181         // that the thread is ex_regs'd before we leave with sysexit.
182         // lthread_ex_regs has to check user cs for that value. If
183         // it is faked, the thread would leave the kernel by sysexit
184         // and the thread is in the slow ipc path. Sysexit would
185         // adapt the user eip (by subtracting 2) to ensure the user
186         // executes the "mov %ebp,%edx" sequence. This is wrong if
187         // the thread is ex_regs'd. In that case, we modify the return
188         // value from "call dispatch_syscall" to an alternate exit
189         // path using "iret".
190         pushl   $(GDT_CODE_USER|SEL_PL_U|0x80)  /* user cs */
191         pushl   %ebx                            /* user eip */
192
193         pushl   %eax
194         pushl   $0 // %ebp
195         pushl   $0 // %ebx
196         pushl   %edi
197         pushl   %esi
198         pushl   %edx
199         pushl   %ecx
200
201         ESP_TO_TCB_AT %ebx
202         testl   $Thread_alien, OFS__THREAD__STATE (%ebx)
203         jnz     alien_sys_fast_ipc_log
204         RESET_THREAD_CANCEL_AT %ebx
205         call    *syscall_table
206 in_slow_ipc5:
207         DO_SYSEXIT
208
209 alien_sys_fast_ipc_log:
210         PRE_FAST_ALIEN_IPC
211         push    $ret_from_fast_alien_ipc
212         jmp     *syscall_table
213
214         .globl  in_slow_ipc5
215
216 #endif // CONFIG_JDB
217
218
219 #if (defined (CONFIG_JDB_LOGGING) || !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT))
220         .p2align(4)
221         .global entry_sys_fast_ipc_c
222 entry_sys_fast_ipc_c:
223         pop     %esp
224         pushl   $(GDT_DATA_USER|SEL_PL_U)       /* user ss */
225         pushl   %ebp                            // push user SP (get in ebp)
226 #ifdef CONFIG_IO_PROT
227         // We must not fake the interrupt flags since we must not
228         // loose the current IOPL of the user task
229         pushf
230 #else
231         // Fake user eflags, set IOPL to 3
232         pushl   $EFLAGS_IOPL_U
233 #endif
234         cld
235         // Fake user cs. This cs value is never used with exception
236         // that the thread is ex_regs'd before we leave with sysexit.
237         // lthread_ex_regs has to check user cs for that value. If
238         // it is faked, the thread would leave the kernel by sysexit
239         // and the thread is in the slow ipc path. Sysexit would
240         // adapt the user eip (by subtracting 2) to ensure the user
241         // executes the "mov %ebp,%edx" sequence. This is wrong if
242         // the thread is ex_regs'd. In that case, we modify the return
243         // value from "call dispatch_syscall" to an alternate exit
244         // path using "iret".
245         pushl   $(GDT_CODE_USER|SEL_PL_U|0x80)  /* user cs */
246         pushl   %ebx                            // push user return address
247
248         pushl   %eax
249         pushl   $0                              // ebp
250         pushl   $0 // %ebx
251         pushl   %edi
252         pushl   %esi
253         pushl   %edx
254         pushl   %ecx                            /* save ecx */
255         ESP_TO_TCB_AT %ebx
256         testl   $Thread_alien, OFS__THREAD__STATE (%ebx)
257         jnz     alien_sys_fast_ipc_c
258         RESET_THREAD_CANCEL_AT %ebx
259         call    ipc_short_cut_wrapper
260 in_sc_ipc2:
261         DO_SYSEXIT
262 #endif
263
264         .globl alien_sys_fast_ipc_c     /* Also used in shortcut */
265         .global ret_from_fast_alien_ipc /* used in ex-regs */
266 /* ex-regs patches the return address of the call to the 'sys_ipc' function
267  * in the case of sysenter, because we need to leave the kernel by iret
268  * to prevent the need of user-level trampoline code.
269  * In the case of alien ipc there must be a special case because otherwise the
270  * second alien exception is not generated. Therefore ex-regs uses 
271  * 'ret_from_fast_alien_ipc' to determine this case and patches the return
272  * address with 'leave_alien_from_sysenter_by_iret' instead of
273  * 'leave_from_sysenter_by_iret'. (see Thread::user_ip in thread-ia32-ux.cpp)
274  */
275
276
277 alien_sys_fast_ipc_c:
278         cld
279         PRE_FAST_ALIEN_IPC
280         call    ipc_short_cut_wrapper
281 ret_from_fast_alien_ipc:
282         POST_FAST_ALIEN_IPC
283
284         .globl  in_sc_ipc2
285
286 .macro  LEAVE_SE_BY_IRET
287         ESP_TO_TCB_AT %ebx
288         RESET_THREAD_IPC_MASK_AT %ebx
289         RESTORE_STATE_AFTER_IPC
290         popl    %eax
291         orl     $EFLAGS_IF, 8(%esp)
292 .endm
293
294         .p2align(4)
295         .globl  leave_from_sysenter_by_iret
296 leave_from_sysenter_by_iret:
297         LEAVE_SE_BY_IRET
298         iret
299
300         .globl  leave_alien_from_sysenter_by_iret
301 leave_alien_from_sysenter_by_iret:
302         LEAVE_SE_BY_IRET
303         pushl   $(0x30 << 3 | 6)
304         pushl   $(0xd)
305         pusha
306         jmp     slowtraps
307
308         .bss
309         .space  4096
310         .global dbf_stack_top
311 dbf_stack_top: