xref: /qemu/linux-user/i386/vdso.S (revision ec6f3fc3)
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