source: mainline/kernel/arch/ia32/src/asm.S@ 9171f12

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

Use symbolic representation for selectors.

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