source: mainline/kernel/arch/ia32/src/asm.S@ 1558d85

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

Autogenerate istate_t and its offsets on ia32.

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