aboutsummaryrefslogtreecommitdiff
path: root/linux-user/x86_64/vdso.S
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/x86_64/vdso.S')
-rw-r--r--linux-user/x86_64/vdso.S78
1 files changed, 78 insertions, 0 deletions
diff --git a/linux-user/x86_64/vdso.S b/linux-user/x86_64/vdso.S
new file mode 100644
index 0000000000..47d16c00ab
--- /dev/null
+++ b/linux-user/x86_64/vdso.S
@@ -0,0 +1,78 @@
+/*
+ * x86-64 linux replacement vdso.
+ *
+ * Copyright 2023 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <asm/unistd.h>
+
+.macro endf name
+ .globl \name
+ .type \name, @function
+ .size \name, . - \name
+.endm
+
+.macro weakalias name
+\name = __vdso_\name
+ .weak \name
+.endm
+
+.macro vdso_syscall name, nr
+__vdso_\name:
+ mov $\nr, %eax
+ syscall
+ ret
+endf __vdso_\name
+weakalias \name
+.endm
+
+ .cfi_startproc
+
+vdso_syscall clock_gettime, __NR_clock_gettime
+vdso_syscall clock_getres, __NR_clock_getres
+vdso_syscall gettimeofday, __NR_gettimeofday
+vdso_syscall time, __NR_time
+
+__vdso_getcpu:
+ /*
+ * There is no syscall number for this allocated on x64.
+ * We can handle this several ways:
+ *
+ * (1) Invent a syscall number for use within qemu.
+ * It should be easy enough to pick a number that
+ * is well out of the way of the kernel numbers.
+ *
+ * (2) Force the emulated cpu to support the rdtscp insn,
+ * and initialize the TSC_AUX value the appropriate value.
+ *
+ * (3) Pretend that we're always running on cpu 0.
+ *
+ * This last is the one that's implemented here, with the
+ * tiny bit of extra code to support rdtscp in place.
+ */
+ xor %ecx, %ecx /* rdtscp w/ tsc_aux = 0 */
+
+ /* if (cpu != NULL) *cpu = (ecx & 0xfff); */
+ test %rdi, %rdi
+ jz 1f
+ mov %ecx, %eax
+ and $0xfff, %eax
+ mov %eax, (%rdi)
+
+ /* if (node != NULL) *node = (ecx >> 12); */
+1: test %rsi, %rsi
+ jz 2f
+ shr $12, %ecx
+ mov %ecx, (%rsi)
+
+2: xor %eax, %eax
+ ret
+endf __vdso_getcpu
+
+weakalias getcpu
+
+ .cfi_endproc
+
+/* TODO: Add elf note for LINUX_VERSION_CODE */