/* * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * x64/syscall.S * An assembly stub that acts as glue for system calls. */ #include .global syscall_handler .section .text .type syscall_handler, @function syscall_handler: cld movl $0, errno pushq %rbp movq %rsp, %rbp pushq %rax sub $8, %rsp pushf pop %r10 mov $0x200, %r11 test %r10, %r11 jz 5f # Make sure the requested system call is valid, if not, then fix it. mov %rax, %r10 cmp $SYSCALL_MAX_NUM, %rax jae 3f 1: # Read a system call function pointer. xorq %r11, %r11 movq syscall_list(%r11,%rax,8), %rax # Oh how nice, user-space put the parameters in: rdi, rsi, rdx, rcx, r8, r9 # Call the system call. callq *%rax pushf pop %rsi mov $0x200, %r8 test %rsi, %r8 jz 6f addq $16, %rsp # Return to user-space, system call result in %rax:%rdx, errno in %ecx. popq %rbp movl errno, %ecx # Zero registers to avoid information leaks. # rax is return value. # rdi is set in a moment. xor %rsi, %rsi # rdx is return value (MIGHT NOT BE INITIALIZED, CAN LEAK!). # rcx is errno. xor %r8, %r8 xor %r9, %r9 xor %r10, %r10 xor %r11, %r11 # The rest of the registers are preserved by the ABI and syscall ABI. # If any signals are pending, fire them now. movq asm_signal_is_pending, %rdi testq %rdi, %rdi jnz 4f # rdi is zero in this branch. 2: iretq 3: # Call the null system call instead. xorq %rax, %rax jmp 1b 4: # We can't return to this location after the signal, since if any system # call is made this stack will get reused and all our nice temporaries wil # be garbage. We therefore pass the kernel the state to return to and it'll # handle it for us when the signal is over. movq 0(%rsp), %rdi # userspace rip movq 16(%rsp), %rsi # userspace rflags movq 24(%rsp), %r8 # userspace rsp, note %rcx is used for errno int $130 # Deliver pending signals. # If we end up here, it means that the signal didn't override anything and # that we should just go ahead and return to userspace ourselves. Zero the # scratch registers to avoid information leaks. xor %rdi, %rdi xor %rsi, %rsi xor %r8, %r8 jmp 2b 5: mov $syscall_interrupt_string_before, %rdi jmp 7f 6: mov $syscall_interrupt_string_after, %rdi jmp 7f 7: add $8, %rsp pop %rsi call PanicF .size syscall_handler, .-syscall_handler .section .rodata .type syscall_interrupt_string_before, @object .size syscall_interrupt_string_before, 56 syscall_interrupt_string_before: .string "System call %u exited without interrupts enabled before" .type syscall_interrupt_string_after, @object .size syscall_interrupt_string_after, 55 syscall_interrupt_string_after: .string "System call %u exited without interrupts enabled after"