aboutsummaryrefslogtreecommitdiff
path: root/linux-user/i386/vdso.S
blob: e7a1f333a1ee6a204ca2472b5bf3103f1ae1e8f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * i386 linux replacement vdso.
 *
 * Copyright 2023 Linaro, Ltd.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include <asm/unistd.h>
#include "vdso-asmoffset.h"

.macro endf name
	.globl	\name
	.type	\name, @function
	.size	\name, . - \name
.endm

.macro vdso_syscall1 name, nr
\name:
	.cfi_startproc
	mov	%ebx, %edx
	.cfi_register %ebx, %edx
	mov	4(%esp), %ebx
	mov	$\nr, %eax
	int	$0x80
	mov	%edx, %ebx
	ret
	.cfi_endproc
endf	\name
.endm

.macro vdso_syscall2 name, nr
\name:
	.cfi_startproc
	mov	%ebx, %edx
	.cfi_register %ebx, %edx
	mov	4(%esp), %ebx
	mov	8(%esp), %ecx
	mov	$\nr, %eax
	int	$0x80
	mov	%edx, %ebx
	ret
	.cfi_endproc
endf	\name
.endm

.macro vdso_syscall3 name, nr
\name:
	.cfi_startproc
	push	%ebx
	.cfi_adjust_cfa_offset 4
	.cfi_rel_offset %ebx, 0
	mov	8(%esp), %ebx
	mov	12(%esp), %ecx
	mov	16(%esp), %edx
	mov	$\nr, %eax
	int	$0x80
	pop	%ebx
	.cfi_adjust_cfa_offset -4
	.cfi_restore %ebx
	ret
	.cfi_endproc
endf	\name
.endm

__kernel_vsyscall:
	.cfi_startproc
	int	$0x80
	ret
	.cfi_endproc
endf	__kernel_vsyscall

vdso_syscall2 __vdso_clock_gettime, __NR_clock_gettime
vdso_syscall2 __vdso_clock_gettime64, __NR_clock_gettime64
vdso_syscall2 __vdso_clock_getres, __NR_clock_getres
vdso_syscall2 __vdso_gettimeofday, __NR_gettimeofday
vdso_syscall1 __vdso_time, __NR_time
vdso_syscall3 __vdso_getcpu, __NR_gettimeofday

/*
 * Signal return handlers.
 */

	.cfi_startproc simple
	.cfi_signal_frame

/*
 * For convenience, put the cfa just above eip in sigcontext, and count
 * offsets backward from there.  Re-compute the cfa in the two contexts
 * we have for signal unwinding.  This is far simpler than the
 * DW_CFA_expression form that the kernel uses, and is equally correct.
 */

	.cfi_def_cfa	%esp, SIGFRAME_SIGCONTEXT_eip + 4

	.cfi_offset	%eip, -4
			/* err, -8 */
			/* trapno, -12 */
	.cfi_offset	%eax, -16
	.cfi_offset	%ecx, -20
	.cfi_offset	%edx, -24
	.cfi_offset	%ebx, -28
	.cfi_offset	%esp, -32
	.cfi_offset	%ebp, -36
	.cfi_offset	%esi, -40
	.cfi_offset	%edi, -44

/*
 * While this frame is marked as a signal frame, that only applies to how
 * the return address is handled for the outer frame.  The return address
 * that arrived here, from the inner frame, is not marked as a signal frame
 * and so the unwinder still tries to subtract 1 to examine the presumed
 * call insn.  Thus we must extend the unwind info to a nop before the start.
 */
	nop

__kernel_sigreturn:
	popl	%eax	/* pop sig */
	.cfi_adjust_cfa_offset -4
	movl	$__NR_sigreturn, %eax
	int	$0x80
endf	__kernel_sigreturn

	.cfi_def_cfa_offset RT_SIGFRAME_SIGCONTEXT_eip + 4
	nop

__kernel_rt_sigreturn:
	movl	$__NR_rt_sigreturn, %eax
	int	$0x80
endf	__kernel_rt_sigreturn

	.cfi_endproc

/*
 * TODO: Add elf notes.  E.g.
 *
 * #include <linux/elfnote.h>
 * ELFNOTE_START(Linux, 0, "a")
 *   .long LINUX_VERSION_CODE
 * ELFNOTE_END
 *
 * but what version number would we set for QEMU?
 */