master
s 145 lines 2.88 KB
Raw
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 */