|  | /* | 
|  | * 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? | 
|  | */ |