source: mainline/kernel/arch/ia32/src/asm.S@ 35599c9

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

Use the proper condition code with the CMOVcc instruction.

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