source: mainline/kernel/arch/ia32/src/asm.S@ 9110ff0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9110ff0 was 9110ff0, checked in by Jakub Jermar <jakub@…>, 15 years ago

Bump up INTERRUPT_ALIGN as the new interrupt handler would not fit in 128 bytes. This should really be fixed in some saner way. I've been bitten by this twice during the last week and will fix this later.

  • Property mode set to 100644
File size: 9.0 KB
Line 
1#
2# Copyright (c) 2001-2004 Jakub Jermar
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8#
9# - Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# - Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# - The name of the author may not be used to endorse or promote products
15# derived from this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28
29## very low and hardware-level functions
30
31# Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int has no error
32# word and 1 means interrupt with error word
33#define ERROR_WORD_INTERRUPT_LIST 0x00027d00
34
35.text
36
37.global paging_on
38.global enable_l_apic_in_msr
39.global interrupt_handlers
40.global memsetb
41.global memsetw
42.global memcpy
43.global memcpy_from_uspace
44.global memcpy_from_uspace_failover_address
45.global memcpy_to_uspace
46.global memcpy_to_uspace_failover_address
47
48
49# Wrapper for generic memsetb
50memsetb:
51 jmp _memsetb
52
53# Wrapper for generic memsetw
54memsetw:
55 jmp _memsetw
56
57
58#define MEMCPY_DST 4
59#define MEMCPY_SRC 8
60#define MEMCPY_SIZE 12
61
62/** Copy memory to/from userspace.
63 *
64 * This is almost conventional memcpy().
65 * The difference is that there is a failover part
66 * to where control is returned from a page fault
67 * if the page fault occurs during copy_from_uspace()
68 * or copy_to_uspace().
69 *
70 * @param MEMCPY_DST(%esp) Destination address.
71 * @param MEMCPY_SRC(%esp) Source address.
72 * @param MEMCPY_SIZE(%esp) Size.
73 *
74 * @return MEMCPY_DST(%esp) on success and 0 on failure.
75 */
76memcpy:
77memcpy_from_uspace:
78memcpy_to_uspace:
79 movl %edi, %edx /* save %edi */
80 movl %esi, %eax /* save %esi */
81
82 movl MEMCPY_SIZE(%esp), %ecx
83 shrl $2, %ecx /* size / 4 */
84
85 movl MEMCPY_DST(%esp), %edi
86 movl MEMCPY_SRC(%esp), %esi
87
88 rep movsl /* copy whole words */
89
90 movl MEMCPY_SIZE(%esp), %ecx
91 andl $3, %ecx /* size % 4 */
92 jz 0f
93
94 rep movsb /* copy the rest byte by byte */
95
960:
97 movl %edx, %edi
98 movl %eax, %esi
99 movl MEMCPY_DST(%esp), %eax /* MEMCPY_DST(%esp), success */
100 ret
101
102/*
103 * We got here from as_page_fault() after the memory operations
104 * above had caused a page fault.
105 */
106memcpy_from_uspace_failover_address:
107memcpy_to_uspace_failover_address:
108 movl %edx, %edi
109 movl %eax, %esi
110 xorl %eax, %eax /* return 0, failure */
111 ret
112
113## Turn paging on
114#
115# Enable paging and write-back caching in CR0.
116#
117paging_on:
118 movl %cr0, %edx
119 orl $(1 << 31), %edx # paging on
120 # clear Cache Disable and not Write Though
121 andl $~((1 << 30) | (1 << 29)), %edx
122 movl %edx,%cr0
123 jmp 0f
1240:
125 ret
126
127
128## Enable local APIC
129#
130# Enable local APIC in MSR.
131#
132enable_l_apic_in_msr:
133 movl $0x1b, %ecx
134 rdmsr
135 orl $(1 << 11), %eax
136 orl $(0xfee00000), %eax
137 wrmsr
138 ret
139
140# Clear nested flag
141# overwrites %ecx
142.macro CLEAR_NT_FLAG
143 pushfl
144 pop %ecx
145 and $0xffffbfff, %ecx
146 push %ecx
147 popfl
148.endm
149
150/*
151 * The SYSENTER syscall mechanism can be used for syscalls with
152 * four or fewer arguments. To pass these four arguments, we
153 * use four registers: EDX, ECX, EBX, ESI. The syscall number
154 * is passed in EAX. We use EDI to remember the return address
155 * and EBP to remember the stack. The INT-based syscall mechanism
156 * can actually handle six arguments plus the syscall number
157 * entirely in registers.
158 */
159.global sysenter_handler
160sysenter_handler:
161 sti
162 pushl %ebp # remember user stack
163 pushl %edi # remember return user address
164
165 xorl %ebp, %ebp # stop stack traces here
166
167 pushl %gs # remember TLS
168
169 pushl %eax # syscall number
170 subl $8, %esp # unused sixth and fifth argument
171 pushl %esi # fourth argument
172 pushl %ebx # third argument
173 pushl %ecx # second argument
174 pushl %edx # first argument
175
176 movw $16, %ax
177 movw %ax, %ds
178 movw %ax, %es
179
180 cld
181 call syscall_handler
182 addl $28, %esp # remove arguments from stack
183
184 pop %gs # restore TLS
185
186 pop %edx # prepare return EIP for SYSEXIT
187 pop %ecx # prepare userspace ESP for SYSEXIT
188
189 sysexit # return to userspace
190
191
192#define ISTATE_OFFSET_EAX 0
193#define ISTATE_OFFSET_EBX 4
194#define ISTATE_OFFSET_ECX 8
195#define ISTATE_OFFSET_EDX 12
196#define ISTATE_OFFSET_EDI 16
197#define ISTATE_OFFSET_ESI 20
198#define ISTATE_OFFSET_EBP 24
199#define ISTATE_OFFSET_EBP_FRAME 28
200#define ISTATE_OFFSET_EIP_FRAME 32
201#define ISTATE_OFFSET_GS 36
202#define ISTATE_OFFSET_FS 40
203#define ISTATE_OFFSET_ES 44
204#define ISTATE_OFFSET_DS 48
205#define ISTATE_OFFSET_ERROR_WORD 52
206#define ISTATE_OFFSET_EIP 56
207#define ISTATE_OFFSET_CS 60
208#define ISTATE_OFFSET_EFLAGS 64
209#define ISTATE_OFFSET_ESP 68
210#define ISTATE_OFFSET_SS 72
211
212/*
213 * Size of the istate structure without the hardware-saved part and without the
214 * error word.
215 */
216#define ISTATE_SOFT_SIZE 52
217
218## Declare interrupt handlers
219#
220# Declare interrupt handlers for n interrupt
221# vectors starting at vector i.
222#
223# The handlers setup data segment registers
224# and call exc_dispatch().
225#
226#define INTERRUPT_ALIGN 256
227.macro handler i n
228
229.ifeq \i - 0x30 # Syscall handler
230 pushl %ds
231 pushl %es
232 pushl %fs
233 pushl %gs
234
235 #
236 # Push syscall arguments onto the stack
237 #
238 # NOTE: The idea behind the order of arguments passed in registers is to
239 # use all scratch registers first and preserved registers next.
240 # An optimized libc syscall wrapper can make use of this setup.
241 #
242 pushl %eax
243 pushl %ebp
244 pushl %edi
245 pushl %esi
246 pushl %ebx
247 pushl %ecx
248 pushl %edx
249
250 # we must fill the data segment registers
251 movw $16, %ax
252 movw %ax, %ds
253 movw %ax, %es
254
255 xorl %ebp, %ebp
256
257 cld
258 sti
259 # syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax)
260 call syscall_handler
261 cli
262
263 movl 20(%esp), %ebp # restore EBP
264 addl $28, %esp # clean-up of parameters
265
266 popl %gs
267 popl %fs
268 popl %es
269 popl %ds
270
271 CLEAR_NT_FLAG
272 iret
273.else
274 /*
275 * This macro distinguishes between two versions of ia32 exceptions.
276 * One version has error word and the other does not have it.
277 * The latter version fakes the error word on the stack so that the
278 * handlers and istate_t can be the same for both types.
279 */
280.iflt \i - 32
281.if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
282 #
283 # Exception with error word: do nothing
284 #
285.else
286 #
287 # Exception without error word: fake up one
288 #
289 pushl $0
290.endif
291.else
292 #
293 # Interrupt: fake up one
294 #
295 pushl $0
296.endif
297
298 subl $ISTATE_SOFT_SIZE, %esp
299
300 #
301 # Save the general purpose registers.
302 #
303 movl %eax, ISTATE_OFFSET_EAX(%esp)
304 movl %ebx, ISTATE_OFFSET_EBX(%esp)
305 movl %ecx, ISTATE_OFFSET_ECX(%esp)
306 movl %edx, ISTATE_OFFSET_EDX(%esp)
307 movl %edi, ISTATE_OFFSET_EDI(%esp)
308 movl %esi, ISTATE_OFFSET_ESI(%esp)
309 movl %ebp, ISTATE_OFFSET_EBP(%esp)
310
311 #
312 # Save the selector registers.
313 #
314 movl %gs, %eax
315 movl %fs, %ebx
316 movl %es, %ecx
317 movl %ds, %edx
318
319 movl %eax, ISTATE_OFFSET_GS(%esp)
320 movl %ebx, ISTATE_OFFSET_FS(%esp)
321 movl %ecx, ISTATE_OFFSET_ES(%esp)
322 movl %edx, ISTATE_OFFSET_DS(%esp)
323
324 #
325 # Switch to kernel selectors.
326 #
327 movl $16, %eax
328 movl %eax, %ds
329 movl %eax, %es
330
331 #
332 # Imitate a regular stack frame linkage.
333 # Stop stack traces here if we came from userspace.
334 #
335 cmpl $8, ISTATE_OFFSET_CS(%esp)
336 jz 0f
337 xorl %ebp, %ebp
3380: movl %ebp, ISTATE_OFFSET_EBP_FRAME(%esp)
339 movl ISTATE_OFFSET_EIP(%esp), %eax
340 movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
341 leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
342
343 pushl %esp # pass istate address
344 pushl $(\i) # pass intnum
345 call exc_dispatch # exc_dispatch(intnum, istate)
346 addl $8, %esp # Clear arguments from the stack
347
348 CLEAR_NT_FLAG
349
350 #
351 # Restore the selector registers.
352 #
353 movl ISTATE_OFFSET_GS(%esp), %eax
354 movl ISTATE_OFFSET_FS(%esp), %ebx
355 movl ISTATE_OFFSET_ES(%esp), %ecx
356 movl ISTATE_OFFSET_DS(%esp), %edx
357
358 movl %eax, %gs
359 movl %ebx, %fs
360 movl %ecx, %es
361 movl %edx, %ds
362
363 #
364 # Restore the scratch registers and the preserved registers the handler
365 # cloberred itself (i.e. EBX and EBP).
366 #
367 movl ISTATE_OFFSET_EAX(%esp), %eax
368 movl ISTATE_OFFSET_EBX(%esp), %ebx
369 movl ISTATE_OFFSET_ECX(%esp), %ecx
370 movl ISTATE_OFFSET_EDX(%esp), %edx
371 movl ISTATE_OFFSET_EBP(%esp), %ebp
372
373 addl $(ISTATE_SOFT_SIZE + 4), %esp
374 iret
375.endif
376
377.align INTERRUPT_ALIGN
378.if (\n- \i) - 1
379 handler "(\i + 1)", \n
380.endif
381.endm
382
383# keep in sync with pm.h !!!
384IDT_ITEMS = 64
385.align INTERRUPT_ALIGN
386interrupt_handlers:
387h_start:
388 handler 0 IDT_ITEMS
389h_end:
390
391.data
392.global interrupt_handler_size
393
394interrupt_handler_size: .long (h_end - h_start) / IDT_ITEMS
Note: See TracBrowser for help on using the repository browser.