source: mainline/kernel/arch/ia32/src/asm.S@ 6dce6af

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6dce6af was 6dce6af, checked in by Martin Decky <martin@…>, 15 years ago

switch to C-style comments
improve indentation

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