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
Line 
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 */
28
29#define IREGISTER_SPACE 80
30
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
41
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 */
47#define ERROR_WORD_INTERRUPT_LIST 0x00027D00
48
49#include <arch/pm.h>
50#include <arch/mm/page.h>
51
52.text
53.global interrupt_handlers
54.global syscall_entry
55.global cpuid
56.global has_cpuid
57.global read_efer_flag
58.global set_efer_flag
59.global memsetb
60.global memsetw
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
66.global early_putchar
67
68/* Wrapper for generic memsetb */
69memsetb:
70 jmp _memsetb
71
72/* Wrapper for generic memsetw */
73memsetw:
74 jmp _memsetw
75
76#define MEMCPY_DST %rdi
77#define MEMCPY_SRC %rsi
78#define MEMCPY_SIZE %rdx
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 *
89 * @param MEMCPY_DST Destination address.
90 * @param MEMCPY_SRC Source address.
91 * @param MEMCPY_SIZE Number of bytes to copy.
92 *
93 * @retrun MEMCPY_DST on success, 0 on failure.
94 *
95 */
96memcpy:
97memcpy_from_uspace:
98memcpy_to_uspace:
99 movq MEMCPY_DST, %rax
100
101 movq MEMCPY_SIZE, %rcx
102 shrq $3, %rcx /* size / 8 */
103
104 rep movsq /* copy as much as possible word by word */
105
106 movq MEMCPY_SIZE, %rcx
107 andq $7, %rcx /* size % 8 */
108 jz 0f
109
110 rep movsb /* copy the rest byte by byte */
111
112 0:
113 ret /* return MEMCPY_SRC, success */
114
115memcpy_from_uspace_failover_address:
116memcpy_to_uspace_failover_address:
117 xorq %rax, %rax /* return 0, failure */
118 ret
119
120/** Determine CPUID support
121*
122* @return 0 in EAX if CPUID is not support, 1 if supported.
123*
124*/
125has_cpuid:
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 */
135 pushq %rdx
136 popfq
137 pushfq
138
139 /* Get the ID bit again */
140 popq %rdx
141 andl $(1 << 21), %eax
142 andl $(1 << 21), %edx
143
144 /* 0 if not supported, 1 if supported */
145 xorl %edx, %eax
146 ret
147
148cpuid:
149 /* Preserve %rbx across function calls */
150 movq %rbx, %r10
151
152 /* Load the command into %eax */
153 movl %edi, %eax
154
155 cpuid
156 movl %eax, 0(%rsi)
157 movl %ebx, 4(%rsi)
158 movl %ecx, 8(%rsi)
159 movl %edx, 12(%rsi)
160
161 movq %r10, %rbx
162 ret
163
164set_efer_flag:
165 movq $0xc0000080, %rcx
166 rdmsr
167 btsl %edi, %eax
168 wrmsr
169 ret
170
171read_efer_flag:
172 movq $0xc0000080, %rcx
173 rdmsr
174 ret
175
176/** Push all volatile general purpose registers on stack
177 *
178 */
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)
189 movq %rbp, IOFFSET_RBP(%rsp)
190.endm
191
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
202 movq IOFFSET_RBP(%rsp), %rbp
203.endm
204
205#define INTERRUPT_ALIGN 128
206
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 */
215.macro handler i n
216
217 /*
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.
223 * Therefore we align the interrupt handlers.
224 */
225
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 */
236 subq $(IREGISTER_SPACE + 8), %rsp
237 .endif
238 .else
239 /*
240 * Version without error word,
241 */
242 subq $(IREGISTER_SPACE + 8), %rsp
243 .endif
244
245 save_all_gpr
246 cld
247
248 /*
249 * Stop stack traces here if we came from userspace.
250 */
251 movq %cs, %rax
252 xorq %rdx, %rdx
253 cmpq %rax, IREGISTER_SPACE+16(%rsp)
254 cmovneq %rdx, %rbp
255
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
261
262 restore_all_gpr
263
264 /* $8 = Skip error word */
265 addq $(IREGISTER_SPACE + 8), %rsp
266 iretq
267
268 .align INTERRUPT_ALIGN
269 .if (\n - \i) - 1
270 handler "(\i + 1)", \n
271 .endif
272.endm
273
274.align INTERRUPT_ALIGN
275interrupt_handlers:
276 h_start:
277 handler 0 IDT_ITEMS
278 h_end:
279
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 */
299syscall_entry:
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
313 sti
314
315 pushq %rcx
316 pushq %r11
317 pushq %rbp
318
319 xorq %rbp, %rbp /* stop the stack traces here */
320
321 /* Copy the 4th argument where it is expected */
322 movq %r10, %rcx
323 pushq %rax
324
325 call syscall_handler
326
327 addq $8, %rsp
328
329 popq %rbp
330 popq %r11
331 popq %rcx
332
333 cli
334 swapgs
335
336 /* Restore the user RSP */
337 movq %gs:0, %rsp
338 swapgs
339
340 sysretq
341
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
349 * can be displayed in a wrong way. Only newline and backspace
350 * are interpreted, all other characters (even unprintable) are
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
401 jne early_putchar_backspace
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
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
429
430 early_putchar_print:
431
432 /* Print character */
433
434 movb $0x0e, %ah /* black background, yellow foreground */
435 stosw
436 inc %bx
437
438 early_putchar_skip:
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
486.data
487.global interrupt_handler_size
488
489interrupt_handler_size: .quad (h_end - h_start) / IDT_ITEMS
Note: See TracBrowser for help on using the repository browser.