source: mainline/kernel/arch/amd64/src/asm.S@ ca8f84f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ca8f84f 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: 10.1 KB
RevLine 
[64bbf13]1/*
2 * Copyright (c) 2005 Ondrej Palkovsky
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 */
[e3b9572]28
[a1f60f3]29#define IREGISTER_SPACE 80
[1f7cb3a]30
[a1f60f3]31#define IOFFSET_RAX 0x00
32#define IOFFSET_RCX 0x08
33#define IOFFSET_RDX 0x10
34#define IOFFSET_RSI 0x18
35#define IOFFSET_RDI 0x20
36#define IOFFSET_R8 0x28
37#define IOFFSET_R9 0x30
38#define IOFFSET_R10 0x38
39#define IOFFSET_R11 0x40
40#define IOFFSET_RBP 0x48
[e3b9572]41
[64bbf13]42/**
43 * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
44 * has no error word and 1 means interrupt with error word
45 *
46 */
[a1f60f3]47#define ERROR_WORD_INTERRUPT_LIST 0x00027D00
[e3b9572]48
49#include <arch/pm.h>
[fa2d382]50#include <arch/mm/page.h>
[a1f60f3]51
[e3b9572]52.text
53.global interrupt_handlers
[dd4d6b0]54.global syscall_entry
[36b209a]55.global cpuid
[7df54df]56.global has_cpuid
[89344d85]57.global read_efer_flag
58.global set_efer_flag
[2b17f47]59.global memsetb
60.global memsetw
[e3c762cd]61.global memcpy
62.global memcpy_from_uspace
63.global memcpy_to_uspace
64.global memcpy_from_uspace_failover_address
65.global memcpy_to_uspace_failover_address
[da52547]66.global early_putchar
[e3c762cd]67
[64bbf13]68/* Wrapper for generic memsetb */
[2b17f47]69memsetb:
70 jmp _memsetb
71
[64bbf13]72/* Wrapper for generic memsetw */
[2b17f47]73memsetw:
74 jmp _memsetw
75
[a1f60f3]76#define MEMCPY_DST %rdi
77#define MEMCPY_SRC %rsi
78#define MEMCPY_SIZE %rdx
[e3c762cd]79
80/**
81 * Copy memory from/to userspace.
82 *
83 * This is almost conventional memcpy().
84 * The difference is that there is a failover part
85 * to where control is returned from a page fault if
86 * the page fault occurs during copy_from_uspace()
87 * or copy_to_uspace().
88 *
[a1f60f3]89 * @param MEMCPY_DST Destination address.
90 * @param MEMCPY_SRC Source address.
91 * @param MEMCPY_SIZE Number of bytes to copy.
[e3c762cd]92 *
[da349da0]93 * @retrun MEMCPY_DST on success, 0 on failure.
[a1f60f3]94 *
[e3c762cd]95 */
96memcpy:
97memcpy_from_uspace:
98memcpy_to_uspace:
[da349da0]99 movq MEMCPY_DST, %rax
[a1f60f3]100
[e3c762cd]101 movq MEMCPY_SIZE, %rcx
[a1f60f3]102 shrq $3, %rcx /* size / 8 */
103
104 rep movsq /* copy as much as possible word by word */
[e3c762cd]105
106 movq MEMCPY_SIZE, %rcx
[a1f60f3]107 andq $7, %rcx /* size % 8 */
[e3c762cd]108 jz 0f
109
[a1f60f3]110 rep movsb /* copy the rest byte by byte */
[89344d85]111
[a1f60f3]112 0:
113 ret /* return MEMCPY_SRC, success */
[e3c762cd]114
115memcpy_from_uspace_failover_address:
116memcpy_to_uspace_failover_address:
[a1f60f3]117 xorq %rax, %rax /* return 0, failure */
[e3c762cd]118 ret
119
[64bbf13]120/** Determine CPUID support
121*
122* @return 0 in EAX if CPUID is not support, 1 if supported.
123*
124*/
[7df54df]125has_cpuid:
[64bbf13]126 /* Load RFLAGS */
127 pushfq
128 popq %rax
129 movq %rax, %rdx
130
131 /* Flip the ID bit */
132 btcl $21, %edx
133
134 /* Store RFLAGS */
[d6dcdd2e]135 pushq %rdx
[64bbf13]136 popfq
[7df54df]137 pushfq
[64bbf13]138
139 /* Get the ID bit again */
140 popq %rdx
141 andl $(1 << 21), %eax
[a1f60f3]142 andl $(1 << 21), %edx
[64bbf13]143
144 /* 0 if not supported, 1 if supported */
145 xorl %edx, %eax
[7df54df]146 ret
147
[89344d85]148cpuid:
[64bbf13]149 /* Preserve %rbx across function calls */
150 movq %rbx, %r10
[a1f60f3]151
[64bbf13]152 /* Load the command into %eax */
153 movl %edi, %eax
[a1f60f3]154
155 cpuid
156 movl %eax, 0(%rsi)
157 movl %ebx, 4(%rsi)
158 movl %ecx, 8(%rsi)
159 movl %edx, 12(%rsi)
160
[89344d85]161 movq %r10, %rbx
162 ret
[7df54df]163
[89344d85]164set_efer_flag:
165 movq $0xc0000080, %rcx
166 rdmsr
167 btsl %edi, %eax
168 wrmsr
169 ret
[a1f60f3]170
[64bbf13]171read_efer_flag:
[89344d85]172 movq $0xc0000080, %rcx
173 rdmsr
[a1f60f3]174 ret
[7df54df]175
[64bbf13]176/** Push all volatile general purpose registers on stack
177 *
178 */
[49a39c2]179.macro save_all_gpr
180 movq %rax, IOFFSET_RAX(%rsp)
181 movq %rcx, IOFFSET_RCX(%rsp)
182 movq %rdx, IOFFSET_RDX(%rsp)
183 movq %rsi, IOFFSET_RSI(%rsp)
184 movq %rdi, IOFFSET_RDI(%rsp)
185 movq %r8, IOFFSET_R8(%rsp)
186 movq %r9, IOFFSET_R9(%rsp)
187 movq %r10, IOFFSET_R10(%rsp)
188 movq %r11, IOFFSET_R11(%rsp)
[304342e]189 movq %rbp, IOFFSET_RBP(%rsp)
[e3b9572]190.endm
191
[49a39c2]192.macro restore_all_gpr
193 movq IOFFSET_RAX(%rsp), %rax
194 movq IOFFSET_RCX(%rsp), %rcx
195 movq IOFFSET_RDX(%rsp), %rdx
196 movq IOFFSET_RSI(%rsp), %rsi
197 movq IOFFSET_RDI(%rsp), %rdi
198 movq IOFFSET_R8(%rsp), %r8
199 movq IOFFSET_R9(%rsp), %r9
200 movq IOFFSET_R10(%rsp), %r10
201 movq IOFFSET_R11(%rsp), %r11
[304342e]202 movq IOFFSET_RBP(%rsp), %rbp
[e3b9572]203.endm
[8e0eb63]204
[a1f60f3]205#define INTERRUPT_ALIGN 128
206
[64bbf13]207/** Declare interrupt handlers
208 *
209 * Declare interrupt handlers for n interrupt
210 * vectors starting at vector i.
211 *
212 * The handlers call exc_dispatch().
213 *
214 */
[e3b9572]215.macro handler i n
[a1f60f3]216
[8e0eb63]217 /*
[296426ad]218 * Choose between version with error code and version without error
219 * code. Both versions have to be of the same size. amd64 assembly is,
220 * however, a little bit tricky. For instance, subq $0x80, %rsp and
221 * subq $0x78, %rsp can result in two instructions with different
222 * op-code lengths.
[e1be3b6]223 * Therefore we align the interrupt handlers.
[8e0eb63]224 */
[a1f60f3]225
[8e0eb63]226 .iflt \i-32
227 .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
228 /*
229 * Version with error word.
230 */
231 subq $IREGISTER_SPACE, %rsp
232 .else
233 /*
234 * Version without error word,
235 */
[a1f60f3]236 subq $(IREGISTER_SPACE + 8), %rsp
[8e0eb63]237 .endif
238 .else
239 /*
240 * Version without error word,
241 */
[a1f60f3]242 subq $(IREGISTER_SPACE + 8), %rsp
243 .endif
244
[8e0eb63]245 save_all_gpr
[e13daa5d]246 cld
[64bbf13]247
248 /*
249 * Stop stack traces here if we came from userspace.
250 */
[a043e39]251 movq %cs, %rax
252 xorq %rdx, %rdx
253 cmpq %rax, IREGISTER_SPACE+16(%rsp)
254 cmovneq %rdx, %rbp
[304342e]255
[64bbf13]256 movq $(\i), %rdi /* %rdi - first argument */
257 movq %rsp, %rsi /* %rsi - pointer to istate */
258
259 /* Call exc_dispatch(i, istate) */
260 call exc_dispatch
[8e0eb63]261
[49a39c2]262 restore_all_gpr
[64bbf13]263
264 /* $8 = Skip error word */
[a1f60f3]265 addq $(IREGISTER_SPACE + 8), %rsp
[e3b9572]266 iretq
[a1f60f3]267
[8d25b44]268 .align INTERRUPT_ALIGN
[a1f60f3]269 .if (\n - \i) - 1
270 handler "(\i + 1)", \n
[e3b9572]271 .endif
272.endm
[8d25b44]273
274.align INTERRUPT_ALIGN
[e3b9572]275interrupt_handlers:
[a1f60f3]276 h_start:
277 handler 0 IDT_ITEMS
278 h_end:
[dd4d6b0]279
[64bbf13]280/** Low-level syscall handler
281 *
282 * Registers on entry:
283 *
284 * @param %rcx Userspace return address.
285 * @param %r11 Userspace RLFAGS.
286 *
287 * @param %rax Syscall number.
288 * @param %rdi 1st syscall argument.
289 * @param %rsi 2nd syscall argument.
290 * @param %rdx 3rd syscall argument.
291 * @param %r10 4th syscall argument. Used instead of RCX because
292 * the SYSCALL instruction clobbers it.
293 * @param %r8 5th syscall argument.
294 * @param %r9 6th syscall argument.
295 *
296 * @return Return value is in %rax.
297 *
298 */
[dd4d6b0]299syscall_entry:
[64bbf13]300 /* Switch to hidden %gs */
301 swapgs
302
303 /*
304 * %gs:0 Scratch space for this thread's user RSP
305 * %gs:8 Address to be used as this thread's kernel RSP
306 */
307
308 movq %rsp, %gs:0 /* save this thread's user RSP */
309 movq %gs:8, %rsp /* set this thread's kernel RSP */
310
311 /* Switch back to remain consistent */
312 swapgs
[6d9c49a]313 sti
[c7c0b89b]314
[296426ad]315 pushq %rcx
316 pushq %r11
[a043e39]317 pushq %rbp
[64bbf13]318
319 xorq %rbp, %rbp /* stop the stack traces here */
320
321 /* Copy the 4th argument where it is expected */
322 movq %r10, %rcx
[296426ad]323 pushq %rax
[64bbf13]324
[dd4d6b0]325 call syscall_handler
[64bbf13]326
[296426ad]327 addq $8, %rsp
[64bbf13]328
[a043e39]329 popq %rbp
[37b451f7]330 popq %r11
331 popq %rcx
[a1f60f3]332
[296426ad]333 cli
334 swapgs
[64bbf13]335
336 /* Restore the user RSP */
337 movq %gs:0, %rsp
[296426ad]338 swapgs
[a1f60f3]339
[37b451f7]340 sysretq
[296426ad]341
[da52547]342/** Print Unicode character to EGA display.
343 *
344 * If CONFIG_EGA is undefined or CONFIG_FB is defined
345 * then this function does nothing.
346 *
347 * Since the EGA can only display Extended ASCII (usually
348 * ISO Latin 1) characters, some of the Unicode characters
[ca8f84f]349 * can be displayed in a wrong way. Only newline and backspace
350 * are interpreted, all other characters (even unprintable) are
[da52547]351 * printed verbatim.
352 *
353 * @param %rdi Unicode character to be printed.
354 *
355 */
356early_putchar:
357
358#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
359
360 /* Prologue, save preserved registers */
361 pushq %rbp
362 movq %rsp, %rbp
363 pushq %rbx
364
365 movq %rdi, %rsi
366 movq $(PA2KA(0xb8000)), %rdi /* base of EGA text mode memory */
367 xorq %rax, %rax
368
369 /* Read bits 8 - 15 of the cursor address */
370 movw $0x3d4, %dx
371 movb $0xe, %al
372 outb %al, %dx
373
374 movw $0x3d5, %dx
375 inb %dx, %al
376 shl $8, %ax
377
378 /* Read bits 0 - 7 of the cursor address */
379 movw $0x3d4, %dx
380 movb $0xf, %al
381 outb %al, %dx
382
383 movw $0x3d5, %dx
384 inb %dx, %al
385
386 /* Sanity check for the cursor on screen */
387 cmp $2000, %ax
388 jb early_putchar_cursor_ok
389
390 movw $1998, %ax
391
392 early_putchar_cursor_ok:
393
394 movw %ax, %bx
395 shl $1, %rax
396 addq %rax, %rdi
397
398 movq %rsi, %rax
399
400 cmp $0x0a, %al
[ca8f84f]401 jne early_putchar_backspace
[da52547]402
403 /* Interpret newline */
404
405 movw %bx, %ax /* %bx -> %dx:%ax */
406 xorw %dx, %dx
407
408 movw $80, %cx
409 idivw %cx, %ax /* %dx = %bx % 80 */
410
411 /* %bx <- %bx + 80 - (%bx % 80) */
412 addw %cx, %bx
413 subw %dx, %bx
414
[ca8f84f]415 jmp early_putchar_skip
416
417 early_putchar_backspace:
418
419 cmp $0x08, %al
420 jne early_putchar_print
421
422 /* Interpret backspace */
423
424 cmp $0x0000, %bx
425 je early_putchar_skip
426
427 dec %bx
428 jmp early_putchar_skip
[da52547]429
430 early_putchar_print:
431
432 /* Print character */
433
434 movb $0x0e, %ah /* black background, yellow foreground */
435 stosw
[b5382d4f]436 inc %bx
[da52547]437
[ca8f84f]438 early_putchar_skip:
[da52547]439
440 /* Sanity check for the cursor on the last line */
441 cmp $2000, %bx
442 jb early_putchar_no_scroll
443
444 /* Scroll the screen (24 rows) */
445 movq $(PA2KA(0xb80a0)), %rsi
446 movq $(PA2KA(0xb8000)), %rdi
447 movq $1920, %rcx
448 rep movsw
449
450 /* Clear the 24th row */
451 xorq %rax, %rax
452 movq $80, %rcx
453 rep stosw
454
455 /* Go to row 24 */
456 movw $1920, %bx
457
458 early_putchar_no_scroll:
459
460 /* Write bits 8 - 15 of the cursor address */
461 movw $0x3d4, %dx
462 movb $0xe, %al
463 outb %al, %dx
464
465 movw $0x3d5, %dx
466 movb %bh, %al
467 outb %al, %dx
468
469 /* Write bits 0 - 7 of the cursor address */
470 movw $0x3d4, %dx
471 movb $0xf, %al
472 outb %al, %dx
473
474 movw $0x3d5, %dx
475 movb %bl, %al
476 outb %al, %dx
477
478 /* Epilogue, restore preserved registers */
479 popq %rbx
480 leave
481
482#endif
483
484 ret
485
[e3b9572]486.data
487.global interrupt_handler_size
488
[a1f60f3]489interrupt_handler_size: .quad (h_end - h_start) / IDT_ITEMS
Note: See TracBrowser for help on using the repository browser.