1/* 2 * Copyright (c) 2018 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files 6 * (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, merge, 8 * publish, distribute, sublicense, and/or sell copies of the Software, 9 * and to permit persons to whom the Software is furnished to do so, 10 * subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24#include <asm.h> 25 26#define SYSCALL_ENTRY_SIZE 0x08 27#define SYSCALL_STACK_OFF 0x08 28 29/* 30 * Entry state: 31 * %rax: syscall number set by syscall stub 32 * %rdi: 1st argument 33 * %rsi: 2nd argument 34 * %rdx: 3rd argument 35 * %rcx: return address saved by syscall instructions (4th argument in ABI) 36 * %r8: 5th argument (unused?) 37 * %r9: 6th argument (unused?) 38 * %r10: 4th argument copied from %rcx by syscall stub 39 * %r11: flags saved by syscall instructions 40 * %rsp: user-space stack (ignored) 41 * %r15: user-space stack saved by stub 42 */ 43FUNCTION (x86_syscall) 44 /* clear user-space controlled stack pointer */ 45 xor %esp, %esp 46 47 /* switch to kernel gs */ 48 swapgs 49 movq %gs:SYSCALL_STACK_OFF, %rsp 50 51 sti 52 pushq %rcx /* Ring 3 return address */ 53 pushq %r15 /* Ring 3 RSP */ 54 movq %r10, %rcx 55 56 pushq %r11 /* saved flags */ 57 subq $0x8, %rsp /* align stack */ 58 59 /* Check if syscall index (%rax) is in range */ 60 cmp $nr_syscalls, %rax 61 jae .Lundefined_syscall 62 63 /* Load entry from syscall table */ 64 movq syscall_table(,%rax,SYSCALL_ENTRY_SIZE), %rax 65 66 /* Check if syscall entry is NULL */ 67 test %rax, %rax 68 jz .Lundefined_syscall 69 70 /* Call syscall handler now in %rax */ 71.Lsyscall_addr_ready: 72 call *%rax 73 74 /* 75 * Clear non-callee saved registers to avoid leaking kernel data to 76 * user-space. 77 * Skip floating/vector registers since the kernel is not allowed to use 78 * them. 79 * Skip 4th argument (%rcx) and %r11 since they get overwritten with 80 * user-space pointers or flags below. 81 */ 82 xor %edi, %edi /* clear 1st argument/temporary register */ 83 xor %esi, %esi /* clear 2nd argument/temporary register */ 84 xor %edx, %edx /* clear 3rd argument/temporary register */ 85 xor %r8d, %r8d /* clear 5th argument/temporary register */ 86 xor %r9d, %r9d /* clear 6th argument/temporary register */ 87 xor %r10d, %r10d /* clear temporary register */ 88 89 addq $0x8, %rsp /* remove stack alignment padding */ 90 popq %r11 /* saved flags */ 91 popq %r15 /* pop RSP */ 92 popq %rcx /* pop RIP */ 93 94 /* 95 * switch to user gs 96 * Have to make sure there is no interrupt triggered between swapgs and sysexit instructions, 97 * if this happens, GS.base is switch to user level GS.base, but current context is still in 98 * kernel level, it leads to get global states failure on current processor. 99 */ 100 cli 101 swapgs 102 103 /* 104 * Clear kernel stack pointer to avoid leaking ASLR info. We don't restore 105 * the user-space stack pointer here, since sysret can trigger a fault and 106 * we don't want that fault handler to use a user-space controlled stack 107 * pointer. A 0 stack pointer will trigger a double fault instead. 108 */ 109 xor %esp, %esp 110 111 /* 112 * Exit state: 113 * %rax: return code 114 * %rcx: return address used by sysret instruction 115 * %r11: saved flags used by sysret instruction 116 * %r15: user-space stack used by stub 117 */ 118 sysretq 119 120 /* 121 * Use sys_undefined as the syscall handler if the index in %rax is out of 122 * range of the syscall table or if %rax is in range, but the entry in the 123 * syscall table is NULL. 124 */ 125.Lundefined_syscall: 126 movq $sys_undefined, %rax 127 jmp .Lsyscall_addr_ready 128