source: mainline/kernel/arch/ia32/src/asm.S@ 44c69b66

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

Make the code in asm.S independent of the interrupt vector used for syscalls.

  • Property mode set to 100644
File size: 13.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#include <arch/pm.h>
41#include <arch/mm/page.h>
42
43.text
44.global paging_on
45.global enable_l_apic_in_msr
46.global memsetb
47.global memsetw
48.global memcpy
49.global memcpy_from_uspace
50.global memcpy_from_uspace_failover_address
51.global memcpy_to_uspace
52.global memcpy_to_uspace_failover_address
53.global early_putchar
54
55/* Wrapper for generic memsetb */
56memsetb:
57 jmp _memsetb
58
59/* Wrapper for generic memsetw */
60memsetw:
61 jmp _memsetw
62
63#define MEMCPY_DST 4
64#define MEMCPY_SRC 8
65#define MEMCPY_SIZE 12
66
67/** Copy memory to/from userspace.
68 *
69 * This is almost conventional memcpy().
70 * The difference is that there is a failover part
71 * to where control is returned from a page fault
72 * if the page fault occurs during copy_from_uspace()
73 * or copy_to_uspace().
74 *
75 * @param MEMCPY_DST(%esp) Destination address.
76 * @param MEMCPY_SRC(%esp) Source address.
77 * @param MEMCPY_SIZE(%esp) Size.
78 *
79 * @return MEMCPY_DST(%esp) on success and 0 on failure.
80 *
81 */
82memcpy:
83memcpy_from_uspace:
84memcpy_to_uspace:
85 movl %edi, %edx /* save %edi */
86 movl %esi, %eax /* save %esi */
87
88 movl MEMCPY_SIZE(%esp), %ecx
89 shrl $2, %ecx /* size / 4 */
90
91 movl MEMCPY_DST(%esp), %edi
92 movl MEMCPY_SRC(%esp), %esi
93
94 /* Copy whole words */
95 rep movsl
96
97 movl MEMCPY_SIZE(%esp), %ecx
98 andl $3, %ecx /* size % 4 */
99 jz 0f
100
101 /* Copy the rest byte by byte */
102 rep movsb
103
104 0:
105
106 movl %edx, %edi
107 movl %eax, %esi
108
109 /* MEMCPY_DST(%esp), success */
110 movl MEMCPY_DST(%esp), %eax
111 ret
112
113/*
114 * We got here from as_page_fault() after the memory operations
115 * above had caused a page fault.
116 */
117memcpy_from_uspace_failover_address:
118memcpy_to_uspace_failover_address:
119 movl %edx, %edi
120 movl %eax, %esi
121
122 /* Return 0, failure */
123 xorl %eax, %eax
124 ret
125
126/** Turn paging on
127 *
128 * Enable paging and write-back caching in CR0.
129 *
130 */
131paging_on:
132 movl %cr0, %edx
133 orl $(1 << 31), %edx /* paging on */
134
135 /* Clear Cache Disable and not Write Though */
136 andl $~((1 << 30) | (1 << 29)), %edx
137 movl %edx, %cr0
138 jmp 0f
139
140 0:
141 ret
142
143/** Enable local APIC
144 *
145 * Enable local APIC in MSR.
146 *
147 */
148enable_l_apic_in_msr:
149 movl $0x1b, %ecx
150 rdmsr
151 orl $(1 << 11), %eax
152 orl $(0xfee00000), %eax
153 wrmsr
154 ret
155
156/** Clear nested flag
157 *
158 */
159.macro CLEAR_NT_FLAG
160 pushfl
161 andl $0xffffbfff, (%esp)
162 popfl
163.endm
164
165#define ISTATE_OFFSET_EDX 0
166#define ISTATE_OFFSET_ECX 4
167#define ISTATE_OFFSET_EBX 8
168#define ISTATE_OFFSET_ESI 12
169#define ISTATE_OFFSET_EDI 16
170#define ISTATE_OFFSET_EBP 20
171#define ISTATE_OFFSET_EAX 24
172#define ISTATE_OFFSET_EBP_FRAME 28
173#define ISTATE_OFFSET_EIP_FRAME 32
174#define ISTATE_OFFSET_GS 36
175#define ISTATE_OFFSET_FS 40
176#define ISTATE_OFFSET_ES 44
177#define ISTATE_OFFSET_DS 48
178#define ISTATE_OFFSET_ERROR_WORD 52
179#define ISTATE_OFFSET_EIP 56
180#define ISTATE_OFFSET_CS 60
181#define ISTATE_OFFSET_EFLAGS 64
182#define ISTATE_OFFSET_ESP 68
183#define ISTATE_OFFSET_SS 72
184
185/*
186 * Size of the istate structure without the hardware-saved part
187 * and without the error word.
188 */
189#define ISTATE_SOFT_SIZE 52
190
191/*
192 * Size of the entire istate structure including the error word and the
193 * hardware-saved part.
194 */
195#define ISTATE_REAL_SIZE (ISTATE_SOFT_SIZE + 24)
196
197/*
198 * The SYSENTER syscall mechanism can be used for syscalls with
199 * four or fewer arguments. To pass these four arguments, we
200 * use four registers: EDX, ECX, EBX, ESI. The syscall number
201 * is passed in EAX. We use EDI to remember the return address
202 * and EBP to remember the stack. The INT-based syscall mechanism
203 * can actually handle six arguments plus the syscall number
204 * entirely in registers.
205 */
206.global sysenter_handler
207sysenter_handler:
208 sti
209 subl $(ISTATE_REAL_SIZE), %esp
210
211 /*
212 * Save the return address and the userspace stack in the istate
213 * structure on locations that would normally be taken by them.
214 */
215 movl %ebp, ISTATE_OFFSET_ESP(%esp)
216 movl %edi, ISTATE_OFFSET_EIP(%esp)
217
218 /*
219 * Push syscall arguments onto the stack
220 */
221 movl %eax, ISTATE_OFFSET_EAX(%esp)
222 movl %ebx, ISTATE_OFFSET_EBX(%esp)
223 movl %ecx, ISTATE_OFFSET_ECX(%esp)
224 movl %edx, ISTATE_OFFSET_EDX(%esp)
225 movl %esi, ISTATE_OFFSET_ESI(%esp)
226 movl %edi, ISTATE_OFFSET_EDI(%esp) /* observability; not needed */
227 movl %ebp, ISTATE_OFFSET_EBP(%esp) /* observability; not needed */
228
229 /*
230 * Fake up the stack trace linkage.
231 */
232 movl %edi, ISTATE_OFFSET_EIP_FRAME(%esp)
233 movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
234 leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
235
236 /*
237 * Save TLS.
238 */
239 movl %gs, %edx
240 movl %edx, ISTATE_OFFSET_GS(%esp)
241
242 /*
243 * Switch to kernel selectors.
244 */
245 movw $16, %ax
246 movw %ax, %ds
247 movw %ax, %es
248
249 cld
250 call syscall_handler
251
252 /*
253 * Restore TLS.
254 */
255 movl ISTATE_OFFSET_GS(%esp), %edx
256 movl %edx, %gs
257
258 /*
259 * Prepare return address and userspace stack for SYSEXIT.
260 */
261 movl ISTATE_OFFSET_EIP(%esp), %edx
262 movl ISTATE_OFFSET_ESP(%esp), %ecx
263
264 addl $(ISTATE_REAL_SIZE), %esp
265
266 sysexit /* return to userspace */
267
268/*
269 * This is the legacy syscall handler using the interrupt mechanism.
270 */
271.global int_syscall
272int_syscall:
273 subl $(ISTATE_SOFT_SIZE + 4), %esp
274
275 /*
276 * Push syscall arguments onto the stack
277 *
278 * NOTE: The idea behind the order of arguments passed
279 * in registers is to use all scratch registers
280 * first and preserved registers next. An optimized
281 * libc syscall wrapper can make use of this setup.
282 * The istate structure is arranged in the way to support
283 * this idea.
284 *
285 */
286 movl %eax, ISTATE_OFFSET_EAX(%esp)
287 movl %ebx, ISTATE_OFFSET_EBX(%esp)
288 movl %ecx, ISTATE_OFFSET_ECX(%esp)
289 movl %edx, ISTATE_OFFSET_EDX(%esp)
290 movl %edi, ISTATE_OFFSET_EDI(%esp)
291 movl %esi, ISTATE_OFFSET_ESI(%esp)
292 movl %ebp, ISTATE_OFFSET_EBP(%esp)
293
294 /*
295 * Save the selector registers.
296 */
297 movl %gs, %ecx
298 movl %fs, %edx
299
300 movl %ecx, ISTATE_OFFSET_GS(%esp)
301 movl %edx, ISTATE_OFFSET_FS(%esp)
302
303 movl %es, %ecx
304 movl %ds, %edx
305
306 movl %ecx, ISTATE_OFFSET_ES(%esp)
307 movl %edx, ISTATE_OFFSET_DS(%esp)
308
309 /*
310 * Switch to kernel selectors.
311 */
312 movl $16, %eax
313 movl %eax, %ds
314 movl %eax, %es
315
316 movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
317 movl ISTATE_OFFSET_EIP(%esp), %eax
318 movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
319 leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
320
321 cld
322 sti
323
324 /* Call syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax) */
325 call syscall_handler
326
327 CLEAR_NT_FLAG
328
329 /*
330 * Restore the selector registers.
331 */
332 movl ISTATE_OFFSET_GS(%esp), %ecx
333 movl ISTATE_OFFSET_FS(%esp), %edx
334
335 movl %ecx, %gs
336 movl %edx, %fs
337
338 movl ISTATE_OFFSET_ES(%esp), %ecx
339 movl ISTATE_OFFSET_DS(%esp), %edx
340
341 movl %ecx, %es
342 movl %edx, %ds
343
344 /*
345 * Restore the preserved registers the handler cloberred itself
346 * (i.e. EBP).
347 */
348 movl ISTATE_OFFSET_EBP(%esp), %ebp
349
350 addl $(ISTATE_SOFT_SIZE + 4), %esp
351 iret
352
353
354/** Declare interrupt handlers
355 *
356 * Declare interrupt handlers for n interrupt
357 * vectors starting at vector i.
358 *
359 */
360.macro handler i
361.global int_\i
362int_\i:
363 /*
364 * This macro distinguishes between two versions of ia32
365 * exceptions. One version has error word and the other
366 * does not have it. The latter version fakes the error
367 * word on the stack so that the handlers and istate_t
368 * can be the same for both types.
369 */
370 .iflt \i - 32
371 .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
372 /*
373 * Exception with error word: do nothing
374 */
375 .else
376 /*
377 * Exception without error word: fake up one
378 */
379 pushl $0
380 .endif
381 .else
382 /*
383 * Interrupt: fake up one
384 */
385 pushl $0
386 .endif
387
388 subl $ISTATE_SOFT_SIZE, %esp
389
390 /*
391 * Save the general purpose registers.
392 */
393 movl %eax, ISTATE_OFFSET_EAX(%esp)
394 movl %ebx, ISTATE_OFFSET_EBX(%esp)
395 movl %ecx, ISTATE_OFFSET_ECX(%esp)
396 movl %edx, ISTATE_OFFSET_EDX(%esp)
397 movl %edi, ISTATE_OFFSET_EDI(%esp)
398 movl %esi, ISTATE_OFFSET_ESI(%esp)
399 movl %ebp, ISTATE_OFFSET_EBP(%esp)
400
401 /*
402 * Save the selector registers.
403 */
404 movl %gs, %eax
405 movl %fs, %ebx
406 movl %es, %ecx
407 movl %ds, %edx
408
409 movl %eax, ISTATE_OFFSET_GS(%esp)
410 movl %ebx, ISTATE_OFFSET_FS(%esp)
411 movl %ecx, ISTATE_OFFSET_ES(%esp)
412 movl %edx, ISTATE_OFFSET_DS(%esp)
413
414 /*
415 * Switch to kernel selectors.
416 */
417 movl $16, %eax
418 movl %eax, %ds
419 movl %eax, %es
420
421 /*
422 * Imitate a regular stack frame linkage.
423 * Stop stack traces here if we came from userspace.
424 */
425 cmpl $8, ISTATE_OFFSET_CS(%esp)
426 jz 0f
427 xorl %ebp, %ebp
428
429 0:
430
431 movl %ebp, ISTATE_OFFSET_EBP_FRAME(%esp)
432 movl ISTATE_OFFSET_EIP(%esp), %eax
433 movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
434 leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
435
436 cld
437
438 pushl %esp /* pass istate address */
439 pushl $(\i) /* pass intnum */
440
441 /* Call exc_dispatch(intnum, istate) */
442 call exc_dispatch
443
444 addl $8, %esp /* clear arguments from the stack */
445
446 CLEAR_NT_FLAG
447
448 /*
449 * Restore the selector registers.
450 */
451 movl ISTATE_OFFSET_GS(%esp), %eax
452 movl ISTATE_OFFSET_FS(%esp), %ebx
453 movl ISTATE_OFFSET_ES(%esp), %ecx
454 movl ISTATE_OFFSET_DS(%esp), %edx
455
456 movl %eax, %gs
457 movl %ebx, %fs
458 movl %ecx, %es
459 movl %edx, %ds
460
461 /*
462 * Restore the scratch registers and the preserved
463 * registers the handler cloberred itself
464 * (i.e. EBX and EBP).
465 */
466 movl ISTATE_OFFSET_EAX(%esp), %eax
467 movl ISTATE_OFFSET_EBX(%esp), %ebx
468 movl ISTATE_OFFSET_ECX(%esp), %ecx
469 movl ISTATE_OFFSET_EDX(%esp), %edx
470 movl ISTATE_OFFSET_EBP(%esp), %ebp
471
472 addl $(ISTATE_SOFT_SIZE + 4), %esp
473 iret
474.endm
475
476#define LIST_0_63 \
477 0, 1, 2, 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,\
478 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,\
479 53,54,55,56,57,58,59,60,61,62,63
480
481interrupt_handlers:
482.irp cnt, LIST_0_63
483 handler \cnt
484.endr
485
486/** Print Unicode character to EGA display.
487 *
488 * If CONFIG_EGA is undefined or CONFIG_FB is defined
489 * then this function does nothing.
490 *
491 * Since the EGA can only display Extended ASCII (usually
492 * ISO Latin 1) characters, some of the Unicode characters
493 * can be displayed in a wrong way. Only newline and backspace
494 * are interpreted, all other characters (even unprintable) are
495 * printed verbatim.
496 *
497 * @param %ebp+0x08 Unicode character to be printed.
498 *
499 */
500early_putchar:
501
502#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
503
504 /* Prologue, save preserved registers */
505 pushl %ebp
506 movl %esp, %ebp
507 pushl %ebx
508 pushl %esi
509 pushl %edi
510
511 movl $(PA2KA(0xb8000)), %edi /* base of EGA text mode memory */
512 xorl %eax, %eax
513
514 /* Read bits 8 - 15 of the cursor address */
515 movw $0x3d4, %dx
516 movb $0xe, %al
517 outb %al, %dx
518
519 movw $0x3d5, %dx
520 inb %dx, %al
521 shl $8, %ax
522
523 /* Read bits 0 - 7 of the cursor address */
524 movw $0x3d4, %dx
525 movb $0xf, %al
526 outb %al, %dx
527
528 movw $0x3d5, %dx
529 inb %dx, %al
530
531 /* Sanity check for the cursor on screen */
532 cmp $2000, %ax
533 jb early_putchar_cursor_ok
534
535 movw $1998, %ax
536
537 early_putchar_cursor_ok:
538
539 movw %ax, %bx
540 shl $1, %eax
541 addl %eax, %edi
542
543 movl 0x08(%ebp), %eax
544
545 cmp $0x0a, %al
546 jne early_putchar_backspace
547
548 /* Interpret newline */
549
550 movw %bx, %ax /* %bx -> %dx:%ax */
551 xorw %dx, %dx
552
553 movw $80, %cx
554 idivw %cx, %ax /* %dx = %bx % 80 */
555
556 /* %bx <- %bx + 80 - (%bx % 80) */
557 addw %cx, %bx
558 subw %dx, %bx
559
560 jmp early_putchar_skip
561
562 early_putchar_backspace:
563
564 cmp $0x08, %al
565 jne early_putchar_print
566
567 /* Interpret backspace */
568
569 cmp $0x0000, %bx
570 je early_putchar_skip
571
572 dec %bx
573 jmp early_putchar_skip
574
575 early_putchar_print:
576
577 /* Print character */
578
579 movb $0x0e, %ah /* black background, yellow foreground */
580 stosw
581 inc %bx
582
583 early_putchar_skip:
584
585 /* Sanity check for the cursor on the last line */
586 cmp $2000, %bx
587 jb early_putchar_no_scroll
588
589 /* Scroll the screen (24 rows) */
590 movl $(PA2KA(0xb80a0)), %esi
591 movl $(PA2KA(0xb8000)), %edi
592 movl $960, %ecx
593 rep movsl
594
595 /* Clear the 24th row */
596 xorl %eax, %eax
597 movl $40, %ecx
598 rep stosl
599
600 /* Go to row 24 */
601 movw $1920, %bx
602
603 early_putchar_no_scroll:
604
605 /* Write bits 8 - 15 of the cursor address */
606 movw $0x3d4, %dx
607 movb $0xe, %al
608 outb %al, %dx
609
610 movw $0x3d5, %dx
611 movb %bh, %al
612 outb %al, %dx
613
614 /* Write bits 0 - 7 of the cursor address */
615 movw $0x3d4, %dx
616 movb $0xf, %al
617 outb %al, %dx
618
619 movw $0x3d5, %dx
620 movb %bl, %al
621 outb %al, %dx
622
623 /* Epilogue, restore preserved registers */
624 popl %edi
625 popl %esi
626 popl %ebx
627 leave
628
629#endif
630
631 ret
632
Note: See TracBrowser for help on using the repository browser.