1/* 2 * i386 linux replacement vdso. 3 * 4 * Copyright 2023 Linaro, Ltd. 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9#include <asm/unistd.h> 10#include "vdso-asmoffset.h" 11 12.macro endf name 13 .globl \name 14 .type \name, @function 15 .size \name, . - \name 16.endm 17 18.macro vdso_syscall1 name, nr 19\name: 20 .cfi_startproc 21 mov %ebx, %edx 22 .cfi_register %ebx, %edx 23 mov 4(%esp), %ebx 24 mov $\nr, %eax 25 int $0x80 26 mov %edx, %ebx 27 ret 28 .cfi_endproc 29endf \name 30.endm 31 32.macro vdso_syscall2 name, nr 33\name: 34 .cfi_startproc 35 mov %ebx, %edx 36 .cfi_register %ebx, %edx 37 mov 4(%esp), %ebx 38 mov 8(%esp), %ecx 39 mov $\nr, %eax 40 int $0x80 41 mov %edx, %ebx 42 ret 43 .cfi_endproc 44endf \name 45.endm 46 47.macro vdso_syscall3 name, nr 48\name: 49 .cfi_startproc 50 push %ebx 51 .cfi_adjust_cfa_offset 4 52 .cfi_rel_offset %ebx, 0 53 mov 8(%esp), %ebx 54 mov 12(%esp), %ecx 55 mov 16(%esp), %edx 56 mov $\nr, %eax 57 int $0x80 58 pop %ebx 59 .cfi_adjust_cfa_offset -4 60 .cfi_restore %ebx 61 ret 62 .cfi_endproc 63endf \name 64.endm 65 66__kernel_vsyscall: 67 .cfi_startproc 68 int $0x80 69 ret 70 .cfi_endproc 71endf __kernel_vsyscall 72 73vdso_syscall2 __vdso_clock_gettime, __NR_clock_gettime 74vdso_syscall2 __vdso_clock_gettime64, __NR_clock_gettime64 75vdso_syscall2 __vdso_clock_getres, __NR_clock_getres 76vdso_syscall2 __vdso_gettimeofday, __NR_gettimeofday 77vdso_syscall1 __vdso_time, __NR_time 78vdso_syscall3 __vdso_getcpu, __NR_gettimeofday 79 80/* 81 * Signal return handlers. 82 */ 83 84 .cfi_startproc simple 85 .cfi_signal_frame 86 87/* 88 * For convenience, put the cfa just above eip in sigcontext, and count 89 * offsets backward from there. Re-compute the cfa in the two contexts 90 * we have for signal unwinding. This is far simpler than the 91 * DW_CFA_expression form that the kernel uses, and is equally correct. 92 */ 93 94 .cfi_def_cfa %esp, SIGFRAME_SIGCONTEXT_eip + 4 95 96 .cfi_offset %eip, -4 97 /* err, -8 */ 98 /* trapno, -12 */ 99 .cfi_offset %eax, -16 100 .cfi_offset %ecx, -20 101 .cfi_offset %edx, -24 102 .cfi_offset %ebx, -28 103 .cfi_offset %esp, -32 104 .cfi_offset %ebp, -36 105 .cfi_offset %esi, -40 106 .cfi_offset %edi, -44 107 108/* 109 * While this frame is marked as a signal frame, that only applies to how 110 * the return address is handled for the outer frame. The return address 111 * that arrived here, from the inner frame, is not marked as a signal frame 112 * and so the unwinder still tries to subtract 1 to examine the presumed 113 * call insn. Thus we must extend the unwind info to a nop before the start. 114 */ 115 nop 116 117__kernel_sigreturn: 118 popl %eax /* pop sig */ 119 .cfi_adjust_cfa_offset -4 120 movl $__NR_sigreturn, %eax 121 int $0x80 122endf __kernel_sigreturn 123 124 .cfi_def_cfa_offset RT_SIGFRAME_SIGCONTEXT_eip + 4 125 nop 126 127__kernel_rt_sigreturn: 128 movl $__NR_rt_sigreturn, %eax 129 int $0x80 130endf __kernel_rt_sigreturn 131 132 .cfi_endproc 133 134/* 135 * TODO: Add elf notes. E.g. 136 * 137 * #include <linux/elfnote.h> 138 * ELFNOTE_START(Linux, 0, "a") 139 * .long LINUX_VERSION_CODE 140 * ELFNOTE_END 141 * 142 * but what version number would we set for QEMU? 143 */ 144