source: mainline/kernel/arch/ia32/src/asm.S@ 6473d41

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

Alter the ia32 istate_t so that the stack trace printed upon a panic shows the
faulting instruction and modify the exception/interrupt handlers accordingly.
With this change, the ia32 istate_t contains all GPRs again.

  • 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 128
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.