xref: /qemu/linux-user/i386/vdso.S (revision 333b3e5fab751cce9f077b827563296c797ff399)
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 __kernel_sigreturn:
118 	popl	%eax	/* pop sig */
119 	.cfi_adjust_cfa_offset -4
120 	movl	$__NR_sigreturn, %eax
121 	int	$0x80
122 endf	__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
130 endf	__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