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

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

rename gdtselector to GDT_SELECTOR to make explicit it is a macro
unify how bootstrap_gdtr is defined on amd64 and ia32

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