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

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

it might be handy for early_putchar to also interpret backspace
(i.e. for printing numeric updates and avoiding a time-consuming scrolling)

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