| 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 |
| 29 | endf \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 |
| 44 | endf \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 |
| 63 | endf \name |
| 64 | .endm |
| 65 | |
| 66 | __kernel_vsyscall: |
| 67 | .cfi_startproc |
| 68 | int $0x80 |
| 69 | ret |
| 70 | .cfi_endproc |
| 71 | endf __kernel_vsyscall |
| 72 | |
| 73 | vdso_syscall2 __vdso_clock_gettime, __NR_clock_gettime |
| 74 | vdso_syscall2 __vdso_clock_gettime64, __NR_clock_gettime64 |
| 75 | vdso_syscall2 __vdso_clock_getres, __NR_clock_getres |
| 76 | vdso_syscall2 __vdso_gettimeofday, __NR_gettimeofday |
| 77 | vdso_syscall1 __vdso_time, __NR_time |
| 78 | vdso_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 | sigreturn_region_start: |
| 118 | __kernel_sigreturn: |
| 119 | popl %eax /* pop sig */ |
| 120 | .cfi_adjust_cfa_offset -4 |
| 121 | movl $__NR_sigreturn, %eax |
| 122 | int $0x80 |
| 123 | endf __kernel_sigreturn |
| 124 | |
| 125 | .cfi_def_cfa_offset RT_SIGFRAME_SIGCONTEXT_eip + 4 |
| 126 | nop |
| 127 | |
| 128 | __kernel_rt_sigreturn: |
| 129 | movl $__NR_rt_sigreturn, %eax |
| 130 | int $0x80 |
| 131 | endf __kernel_rt_sigreturn |
| 132 | sigreturn_region_end: |
| 133 | |
| 134 | .cfi_endproc |
| 135 | |
| 136 | /* |
| 137 | * TODO: Add elf notes. E.g. |
| 138 | * |
| 139 | * #include <linux/elfnote.h> |
| 140 | * ELFNOTE_START(Linux, 0, "a") |
| 141 | * .long LINUX_VERSION_CODE |
| 142 | * ELFNOTE_END |
| 143 | * |
| 144 | * but what version number would we set for QEMU? |
| 145 | */ |