| /* |
| * i386 linux replacement vdso. |
| * |
| * Copyright 2023 Linaro, Ltd. |
| * |
| * SPDX-License-Identifier: GPL-2.0-or-later |
| */ |
| |
| #include <asm/unistd.h> |
| #include "vdso-asmoffset.h" |
| |
| .macro endf name |
| .globl \name |
| .type \name, @function |
| .size \name, . - \name |
| .endm |
| |
| .macro vdso_syscall1 name, nr |
| \name: |
| .cfi_startproc |
| mov %ebx, %edx |
| .cfi_register %ebx, %edx |
| mov 4(%esp), %ebx |
| mov $\nr, %eax |
| int $0x80 |
| mov %edx, %ebx |
| ret |
| .cfi_endproc |
| endf \name |
| .endm |
| |
| .macro vdso_syscall2 name, nr |
| \name: |
| .cfi_startproc |
| mov %ebx, %edx |
| .cfi_register %ebx, %edx |
| mov 4(%esp), %ebx |
| mov 8(%esp), %ecx |
| mov $\nr, %eax |
| int $0x80 |
| mov %edx, %ebx |
| ret |
| .cfi_endproc |
| endf \name |
| .endm |
| |
| .macro vdso_syscall3 name, nr |
| \name: |
| .cfi_startproc |
| push %ebx |
| .cfi_adjust_cfa_offset 4 |
| .cfi_rel_offset %ebx, 0 |
| mov 8(%esp), %ebx |
| mov 12(%esp), %ecx |
| mov 16(%esp), %edx |
| mov $\nr, %eax |
| int $0x80 |
| pop %ebx |
| .cfi_adjust_cfa_offset -4 |
| .cfi_restore %ebx |
| ret |
| .cfi_endproc |
| endf \name |
| .endm |
| |
| __kernel_vsyscall: |
| .cfi_startproc |
| int $0x80 |
| ret |
| .cfi_endproc |
| endf __kernel_vsyscall |
| |
| vdso_syscall2 __vdso_clock_gettime, __NR_clock_gettime |
| vdso_syscall2 __vdso_clock_gettime64, __NR_clock_gettime64 |
| vdso_syscall2 __vdso_clock_getres, __NR_clock_getres |
| vdso_syscall2 __vdso_gettimeofday, __NR_gettimeofday |
| vdso_syscall1 __vdso_time, __NR_time |
| vdso_syscall3 __vdso_getcpu, __NR_gettimeofday |
| |
| /* |
| * Signal return handlers. |
| */ |
| |
| .cfi_startproc simple |
| .cfi_signal_frame |
| |
| /* |
| * For convenience, put the cfa just above eip in sigcontext, and count |
| * offsets backward from there. Re-compute the cfa in the two contexts |
| * we have for signal unwinding. This is far simpler than the |
| * DW_CFA_expression form that the kernel uses, and is equally correct. |
| */ |
| |
| .cfi_def_cfa %esp, SIGFRAME_SIGCONTEXT_eip + 4 |
| |
| .cfi_offset %eip, -4 |
| /* err, -8 */ |
| /* trapno, -12 */ |
| .cfi_offset %eax, -16 |
| .cfi_offset %ecx, -20 |
| .cfi_offset %edx, -24 |
| .cfi_offset %ebx, -28 |
| .cfi_offset %esp, -32 |
| .cfi_offset %ebp, -36 |
| .cfi_offset %esi, -40 |
| .cfi_offset %edi, -44 |
| |
| /* |
| * While this frame is marked as a signal frame, that only applies to how |
| * the return address is handled for the outer frame. The return address |
| * that arrived here, from the inner frame, is not marked as a signal frame |
| * and so the unwinder still tries to subtract 1 to examine the presumed |
| * call insn. Thus we must extend the unwind info to a nop before the start. |
| */ |
| nop |
| |
| __kernel_sigreturn: |
| popl %eax /* pop sig */ |
| .cfi_adjust_cfa_offset -4 |
| movl $__NR_sigreturn, %eax |
| int $0x80 |
| endf __kernel_sigreturn |
| |
| .cfi_def_cfa_offset RT_SIGFRAME_SIGCONTEXT_eip + 4 |
| nop |
| |
| __kernel_rt_sigreturn: |
| movl $__NR_rt_sigreturn, %eax |
| int $0x80 |
| endf __kernel_rt_sigreturn |
| |
| .cfi_endproc |
| |
| /* |
| * TODO: Add elf notes. E.g. |
| * |
| * #include <linux/elfnote.h> |
| * ELFNOTE_START(Linux, 0, "a") |
| * .long LINUX_VERSION_CODE |
| * ELFNOTE_END |
| * |
| * but what version number would we set for QEMU? |
| */ |