blob: e7a1f333a1ee6a204ca2472b5bf3103f1ae1e8f5 [file] [log] [blame]
/*
* 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?
*/