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

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

Autogenerate amd64 istate_t and its offsets.

  • Property mode set to 100644
File size: 12.5 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#include <arch/pm.h>
30#include <arch/mm/page.h>
31#include <arch/istate_struct.h>
32
33.text
34.global interrupt_handlers
35.global syscall_entry
36.global cpuid
37.global has_cpuid
38.global read_efer_flag
39.global set_efer_flag
40.global memcpy_from_uspace
41.global memcpy_to_uspace
42.global memcpy_from_uspace_failover_address
43.global memcpy_to_uspace_failover_address
44.global early_putchar
45
46#define MEMCPY_DST %rdi
47#define MEMCPY_SRC %rsi
48#define MEMCPY_SIZE %rdx
49
50/**
51 * Copy memory from/to userspace.
52 *
53 * This is almost conventional memcpy().
54 * The difference is that there is a failover part
55 * to where control is returned from a page fault if
56 * the page fault occurs during copy_from_uspace()
57 * or copy_to_uspace().
58 *
59 * @param MEMCPY_DST Destination address.
60 * @param MEMCPY_SRC Source address.
61 * @param MEMCPY_SIZE Number of bytes to copy.
62 *
63 * @retrun MEMCPY_DST on success, 0 on failure.
64 *
65 */
66memcpy_from_uspace:
67memcpy_to_uspace:
68 movq MEMCPY_DST, %rax
69
70 movq MEMCPY_SIZE, %rcx
71 shrq $3, %rcx /* size / 8 */
72
73 rep movsq /* copy as much as possible word by word */
74
75 movq MEMCPY_SIZE, %rcx
76 andq $7, %rcx /* size % 8 */
77 jz 0f
78
79 rep movsb /* copy the rest byte by byte */
80
81 0:
82 ret /* return MEMCPY_SRC, success */
83
84memcpy_from_uspace_failover_address:
85memcpy_to_uspace_failover_address:
86 xorl %eax, %eax /* return 0, failure */
87 ret
88
89/** Determine CPUID support
90*
91* @return 0 in EAX if CPUID is not support, 1 if supported.
92*
93*/
94has_cpuid:
95 /* Load RFLAGS */
96 pushfq
97 popq %rax
98 movq %rax, %rdx
99
100 /* Flip the ID bit */
101 btcl $21, %edx
102
103 /* Store RFLAGS */
104 pushq %rdx
105 popfq
106 pushfq
107
108 /* Get the ID bit again */
109 popq %rdx
110 andl $(1 << 21), %eax
111 andl $(1 << 21), %edx
112
113 /* 0 if not supported, 1 if supported */
114 xorl %edx, %eax
115 ret
116
117cpuid:
118 /* Preserve %rbx across function calls */
119 movq %rbx, %r10
120
121 /* Load the command into %eax */
122 movl %edi, %eax
123
124 cpuid
125 movl %eax, 0(%rsi)
126 movl %ebx, 4(%rsi)
127 movl %ecx, 8(%rsi)
128 movl %edx, 12(%rsi)
129
130 movq %r10, %rbx
131 ret
132
133set_efer_flag:
134 movl $0xc0000080, %ecx
135 rdmsr
136 btsl %edi, %eax
137 wrmsr
138 ret
139
140read_efer_flag:
141 movl $0xc0000080, %ecx
142 rdmsr
143 ret
144
145/*
146 * Size of the istate structure without the hardware-saved part and without the
147 * error word.
148 */
149#define ISTATE_SOFT_SIZE ISTATE_SIZE - (6 * 8)
150
151/**
152 * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
153 * has no error word and 1 means interrupt with error word
154 *
155 */
156#define ERROR_WORD_INTERRUPT_LIST 0x00027D00
157
158.macro handler i
159.global int_\i
160int_\i:
161
162 /*
163 * Choose between version with error code and version without error
164 * code.
165 */
166
167 .iflt \i-32
168 .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
169 /*
170 * Version with error word.
171 */
172 subq $ISTATE_SOFT_SIZE, %rsp
173 .else
174 /*
175 * Version without error word.
176 */
177 subq $(ISTATE_SOFT_SIZE + 8), %rsp
178 .endif
179 .else
180 /*
181 * Version without error word.
182 */
183 subq $(ISTATE_SOFT_SIZE + 8), %rsp
184 .endif
185
186 /*
187 * Save the general purpose registers.
188 */
189 movq %rax, ISTATE_OFFSET_RAX(%rsp)
190 movq %rbx, ISTATE_OFFSET_RBX(%rsp)
191 movq %rcx, ISTATE_OFFSET_RCX(%rsp)
192 movq %rdx, ISTATE_OFFSET_RDX(%rsp)
193 movq %rsi, ISTATE_OFFSET_RSI(%rsp)
194 movq %rdi, ISTATE_OFFSET_RDI(%rsp)
195 movq %rbp, ISTATE_OFFSET_RBP(%rsp)
196 movq %r8, ISTATE_OFFSET_R8(%rsp)
197 movq %r9, ISTATE_OFFSET_R9(%rsp)
198 movq %r10, ISTATE_OFFSET_R10(%rsp)
199 movq %r11, ISTATE_OFFSET_R11(%rsp)
200 movq %r12, ISTATE_OFFSET_R12(%rsp)
201 movq %r13, ISTATE_OFFSET_R13(%rsp)
202 movq %r14, ISTATE_OFFSET_R14(%rsp)
203 movq %r15, ISTATE_OFFSET_R15(%rsp)
204
205 /*
206 * Imitate a regular stack frame linkage.
207 * Stop stack traces here if we came from userspace.
208 */
209 xorl %edx, %edx
210 cmpq $(GDT_SELECTOR(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
211 cmovnzq %rdx, %rbp
212
213 movq %rbp, ISTATE_OFFSET_RBP_FRAME(%rsp)
214 movq ISTATE_OFFSET_RIP(%rsp), %rax
215 movq %rax, ISTATE_OFFSET_RIP_FRAME(%rsp)
216 leaq ISTATE_OFFSET_RBP_FRAME(%rsp), %rbp
217
218 movq $(\i), %rdi /* pass intnum in the first argument */
219 movq %rsp, %rsi /* pass istate address in the second argument */
220
221 cld
222
223 /* Call exc_dispatch(i, istate) */
224 call exc_dispatch
225
226 /*
227 * Restore all scratch registers and the preserved registers we have
228 * clobbered in this handler (i.e. RBP).
229 */
230 movq ISTATE_OFFSET_RAX(%rsp), %rax
231 movq ISTATE_OFFSET_RCX(%rsp), %rcx
232 movq ISTATE_OFFSET_RDX(%rsp), %rdx
233 movq ISTATE_OFFSET_RSI(%rsp), %rsi
234 movq ISTATE_OFFSET_RDI(%rsp), %rdi
235 movq ISTATE_OFFSET_RBP(%rsp), %rbp
236 movq ISTATE_OFFSET_R8(%rsp), %r8
237 movq ISTATE_OFFSET_R9(%rsp), %r9
238 movq ISTATE_OFFSET_R10(%rsp), %r10
239 movq ISTATE_OFFSET_R11(%rsp), %r11
240
241 /* $8 = Skip error word */
242 addq $(ISTATE_SOFT_SIZE + 8), %rsp
243 iretq
244.endm
245
246#define LIST_0_63 \
247 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,\
248 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,\
249 53,54,55,56,57,58,59,60,61,62,63
250
251interrupt_handlers:
252.irp cnt, LIST_0_63
253 handler \cnt
254.endr
255
256/** Low-level syscall handler
257 *
258 * Registers on entry:
259 *
260 * @param %rcx Userspace return address.
261 * @param %r11 Userspace RLFAGS.
262 *
263 * @param %rax Syscall number.
264 * @param %rdi 1st syscall argument.
265 * @param %rsi 2nd syscall argument.
266 * @param %rdx 3rd syscall argument.
267 * @param %r10 4th syscall argument. Used instead of RCX because
268 * the SYSCALL instruction clobbers it.
269 * @param %r8 5th syscall argument.
270 * @param %r9 6th syscall argument.
271 *
272 * @return Return value is in %rax.
273 *
274 */
275syscall_entry:
276 /* Switch to hidden %gs */
277 swapgs
278
279 /*
280 * %gs:0 Scratch space for this thread's user RSP
281 * %gs:8 Address to be used as this thread's kernel RSP
282 */
283
284 movq %rsp, %gs:0 /* save this thread's user RSP */
285 movq %gs:8, %rsp /* set this thread's kernel RSP */
286
287 /*
288 * Note that the space needed for the imitated istate structure has been
289 * preallocated for us in thread_create_arch() and set in
290 * before_thread_runs_arch().
291 */
292
293 /*
294 * Save the general purpose registers and push the 7th argument (syscall
295 * number) onto the stack. Note that the istate structure has a layout
296 * which supports this.
297 */
298 movq %rax, ISTATE_OFFSET_RAX(%rsp) /* 7th argument, passed on stack */
299 movq %rbx, ISTATE_OFFSET_RBX(%rsp) /* observability */
300 movq %rcx, ISTATE_OFFSET_RCX(%rsp) /* userspace RIP */
301 movq %rdx, ISTATE_OFFSET_RDX(%rsp) /* 3rd argument, observability */
302 movq %rsi, ISTATE_OFFSET_RSI(%rsp) /* 2nd argument, observability */
303 movq %rdi, ISTATE_OFFSET_RDI(%rsp) /* 1st argument, observability */
304 movq %rbp, ISTATE_OFFSET_RBP(%rsp) /* need to preserve userspace RBP */
305 movq %r8, ISTATE_OFFSET_R8(%rsp) /* 5th argument, observability */
306 movq %r9, ISTATE_OFFSET_R9(%rsp) /* 6th argument, observability */
307 movq %r10, ISTATE_OFFSET_R10(%rsp) /* 4th argument, observability */
308 movq %r11, ISTATE_OFFSET_R11(%rsp) /* low 32 bits userspace RFLAGS */
309 movq %r12, ISTATE_OFFSET_R12(%rsp) /* observability */
310 movq %r13, ISTATE_OFFSET_R13(%rsp) /* observability */
311 movq %r14, ISTATE_OFFSET_R14(%rsp) /* observability */
312 movq %r15, ISTATE_OFFSET_R15(%rsp) /* observability */
313
314 /*
315 * Save the return address and the userspace stack on locations that
316 * would normally be taken by them.
317 */
318 movq %gs:0, %rax
319 movq %rax, ISTATE_OFFSET_RSP(%rsp)
320 movq %rcx, ISTATE_OFFSET_RIP(%rsp)
321
322 /*
323 * Imitate a regular stack frame linkage.
324 */
325 movq $0, ISTATE_OFFSET_RBP_FRAME(%rsp)
326 movq %rcx, ISTATE_OFFSET_RIP_FRAME(%rsp)
327 leaq ISTATE_OFFSET_RBP_FRAME(%rsp), %rbp
328
329 /* Switch back to normal %gs */
330 swapgs
331 sti
332
333 /* Copy the 4th argument where it is expected */
334 movq %r10, %rcx
335
336 /*
337 * Call syscall_handler() with the 7th argument passed on stack.
338 */
339 call syscall_handler
340
341 /*
342 * Test if the saved return address is canonical and not-kernel.
343 * We do this by looking at the 16 most significant bits
344 * of the saved return address (two bytes at offset 6).
345 */
346 testw $0xffff, ISTATE_OFFSET_RIP+6(%rsp)
347 jnz bad_rip
348
349 cli
350
351 /*
352 * Restore registers needed for return via the SYSRET instruction and
353 * the clobbered preserved registers (i.e. RBP).
354 */
355 movq ISTATE_OFFSET_RBP(%rsp), %rbp
356 movq ISTATE_OFFSET_RCX(%rsp), %rcx
357 movq ISTATE_OFFSET_R11(%rsp), %r11
358 movq ISTATE_OFFSET_RSP(%rsp), %rsp
359
360 /*
361 * Clear the rest of the scratch registers to prevent information leak.
362 * The 32-bit XOR on the low GPRs actually clears the entire 64-bit
363 * register and the instruction is shorter.
364 */
365 xorl %edx, %edx
366 xorl %esi, %esi
367 xorl %edi, %edi
368 xorq %r8, %r8
369 xorq %r9, %r9
370 xorq %r10, %r10
371
372 sysretq
373
374bad_rip:
375 movq %rsp, %rdi
376 movabs $bad_rip_msg, %rsi
377 xorb %al, %al
378 callq fault_from_uspace
379 /* not reached */
380
381bad_rip_msg:
382 .asciz "Invalid instruction pointer."
383
384/** Print Unicode character to EGA display.
385 *
386 * If CONFIG_EGA is undefined or CONFIG_FB is defined
387 * then this function does nothing.
388 *
389 * Since the EGA can only display Extended ASCII (usually
390 * ISO Latin 1) characters, some of the Unicode characters
391 * can be displayed in a wrong way. Only newline and backspace
392 * are interpreted, all other characters (even unprintable) are
393 * printed verbatim.
394 *
395 * @param %rdi Unicode character to be printed.
396 *
397 */
398early_putchar:
399
400#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
401
402 /* Prologue, save preserved registers */
403 pushq %rbp
404 movq %rsp, %rbp
405 pushq %rbx
406
407 movq %rdi, %rsi
408 movq $(PA2KA(0xb8000)), %rdi /* base of EGA text mode memory */
409 xorl %eax, %eax
410
411 /* Read bits 8 - 15 of the cursor address */
412 movw $0x3d4, %dx
413 movb $0xe, %al
414 outb %al, %dx
415
416 movw $0x3d5, %dx
417 inb %dx, %al
418 shl $8, %ax
419
420 /* Read bits 0 - 7 of the cursor address */
421 movw $0x3d4, %dx
422 movb $0xf, %al
423 outb %al, %dx
424
425 movw $0x3d5, %dx
426 inb %dx, %al
427
428 /* Sanity check for the cursor on screen */
429 cmp $2000, %ax
430 jb early_putchar_cursor_ok
431
432 movw $1998, %ax
433
434 early_putchar_cursor_ok:
435
436 movw %ax, %bx
437 shl $1, %rax
438 addq %rax, %rdi
439
440 movq %rsi, %rax
441
442 cmp $0x0a, %al
443 jne early_putchar_backspace
444
445 /* Interpret newline */
446
447 movw %bx, %ax /* %bx -> %dx:%ax */
448 xorw %dx, %dx
449
450 movw $80, %cx
451 idivw %cx, %ax /* %dx = %bx % 80 */
452
453 /* %bx <- %bx + 80 - (%bx % 80) */
454 addw %cx, %bx
455 subw %dx, %bx
456
457 jmp early_putchar_skip
458
459 early_putchar_backspace:
460
461 cmp $0x08, %al
462 jne early_putchar_print
463
464 /* Interpret backspace */
465
466 cmp $0x0000, %bx
467 je early_putchar_skip
468
469 dec %bx
470 jmp early_putchar_skip
471
472 early_putchar_print:
473
474 /* Print character */
475
476 movb $0x0e, %ah /* black background, yellow foreground */
477 stosw
478 inc %bx
479
480 early_putchar_skip:
481
482 /* Sanity check for the cursor on the last line */
483 cmp $2000, %bx
484 jb early_putchar_no_scroll
485
486 /* Scroll the screen (24 rows) */
487 movq $(PA2KA(0xb80a0)), %rsi
488 movq $(PA2KA(0xb8000)), %rdi
489 movl $480, %ecx
490 rep movsq
491
492 /* Clear the 24th row */
493 xorl %eax, %eax
494 movl $20, %ecx
495 rep stosq
496
497 /* Go to row 24 */
498 movw $1920, %bx
499
500 early_putchar_no_scroll:
501
502 /* Write bits 8 - 15 of the cursor address */
503 movw $0x3d4, %dx
504 movb $0xe, %al
505 outb %al, %dx
506
507 movw $0x3d5, %dx
508 movb %bh, %al
509 outb %al, %dx
510
511 /* Write bits 0 - 7 of the cursor address */
512 movw $0x3d4, %dx
513 movb $0xf, %al
514 outb %al, %dx
515
516 movw $0x3d5, %dx
517 movb %bl, %al
518 outb %al, %dx
519
520 /* Epilogue, restore preserved registers */
521 popq %rbx
522 leave
523
524#endif
525
526 ret
527
Note: See TracBrowser for help on using the repository browser.