source: mainline/kernel/arch/ia32/src/asm.S@ 3abfe9a8

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

unify kernel byte string implementations

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