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

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

ia32: use asmtool.h macros for defining symbols

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