source: mainline/kernel/arch/ia32/src/asm.S@ 9097982f

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

Remove outdated comment.

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