aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/vdso
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/vdso
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/vdso')
-rw-r--r--arch/mips/vdso/.gitignore5
-rw-r--r--arch/mips/vdso/Kconfig18
-rw-r--r--arch/mips/vdso/Makefile208
-rw-r--r--arch/mips/vdso/config-n32-o32-env.c19
-rw-r--r--arch/mips/vdso/elf.S62
-rw-r--r--arch/mips/vdso/genvdso.c312
-rw-r--r--arch/mips/vdso/genvdso.h132
-rw-r--r--arch/mips/vdso/sigreturn.S35
-rw-r--r--arch/mips/vdso/vdso.lds.S105
-rw-r--r--arch/mips/vdso/vgettimeofday.c78
10 files changed, 974 insertions, 0 deletions
diff --git a/arch/mips/vdso/.gitignore b/arch/mips/vdso/.gitignore
new file mode 100644
index 000000000..1f43f6dd8
--- /dev/null
+++ b/arch/mips/vdso/.gitignore
@@ -0,0 +1,5 @@
1# SPDX-License-Identifier: GPL-2.0-only
2*.so*
3vdso-*image.c
4genvdso
5vdso*.lds
diff --git a/arch/mips/vdso/Kconfig b/arch/mips/vdso/Kconfig
new file mode 100644
index 000000000..7aec72139
--- /dev/null
+++ b/arch/mips/vdso/Kconfig
@@ -0,0 +1,18 @@
1# For the pre-R6 code in arch/mips/vdso/vdso.h for locating
2# the base address of VDSO, the linker will emit a R_MIPS_PC32
3# relocation in binutils > 2.25 but it will fail with older versions
4# because that relocation is not supported for that symbol. As a result
5# of which we are forced to disable the VDSO symbols when building
6# with < 2.25 binutils on pre-R6 kernels. For more references on why we
7# can't use other methods to get the base address of VDSO please refer to
8# the comments on that file.
9#
10# GCC (at least up to version 9.2) appears to emit function calls that make use
11# of the GOT when targeting microMIPS, which we can't use in the VDSO due to
12# the lack of relocations. As such, we disable the VDSO for microMIPS builds.
13
14config MIPS_LD_CAN_LINK_VDSO
15 def_bool LD_VERSION >= 225000000 || LD_IS_LLD
16
17config MIPS_DISABLE_VDSO
18 def_bool CPU_MICROMIPS || (!CPU_MIPSR6 && !MIPS_LD_CAN_LINK_VDSO)
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
new file mode 100644
index 000000000..2131d3fd7
--- /dev/null
+++ b/arch/mips/vdso/Makefile
@@ -0,0 +1,208 @@
1# SPDX-License-Identifier: GPL-2.0
2# Objects to go into the VDSO.
3
4# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before
5# the inclusion of generic Makefile.
6ARCH_REL_TYPE_ABS := R_MIPS_JUMP_SLOT|R_MIPS_GLOB_DAT
7include $(srctree)/lib/vdso/Makefile
8
9obj-vdso-y := elf.o vgettimeofday.o sigreturn.o
10
11# Common compiler flags between ABIs.
12ccflags-vdso := \
13 $(filter -I%,$(KBUILD_CFLAGS)) \
14 $(filter -E%,$(KBUILD_CFLAGS)) \
15 $(filter -mmicromips,$(KBUILD_CFLAGS)) \
16 $(filter -march=%,$(KBUILD_CFLAGS)) \
17 $(filter -m%-float,$(KBUILD_CFLAGS)) \
18 $(filter -mno-loongson-%,$(KBUILD_CFLAGS)) \
19 $(CLANG_FLAGS) \
20 -D__VDSO__
21
22ifndef CONFIG_64BIT
23ccflags-vdso += -DBUILD_VDSO32
24endif
25
26#
27# The -fno-jump-tables flag only prevents the compiler from generating
28# jump tables but does not prevent the compiler from emitting absolute
29# offsets.
30cflags-vdso := $(ccflags-vdso) \
31 $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
32 -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
33 -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \
34 -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
35 $(call cc-option, -fno-asynchronous-unwind-tables)
36aflags-vdso := $(ccflags-vdso) \
37 -D__ASSEMBLY__ -Wa,-gdwarf-2
38
39ifneq ($(c-gettimeofday-y),)
40CFLAGS_vgettimeofday.o = -include $(c-gettimeofday-y)
41
42# config-n32-o32-env.c prepares the environment to build a 32bit vDSO
43# library on a 64bit kernel.
44# Note: Needs to be included before than the generic library.
45CFLAGS_vgettimeofday-o32.o = -include $(srctree)/$(src)/config-n32-o32-env.c -include $(c-gettimeofday-y)
46CFLAGS_vgettimeofday-n32.o = -include $(srctree)/$(src)/config-n32-o32-env.c -include $(c-gettimeofday-y)
47endif
48
49CFLAGS_REMOVE_vgettimeofday.o = -pg
50
51ifdef CONFIG_MIPS_DISABLE_VDSO
52 ifndef CONFIG_MIPS_LD_CAN_LINK_VDSO
53 $(warning MIPS VDSO requires binutils >= 2.25)
54 endif
55 obj-vdso-y := $(filter-out vgettimeofday.o, $(obj-vdso-y))
56endif
57
58# VDSO linker flags.
59ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
60 $(filter -E%,$(KBUILD_CFLAGS)) -nostdlib -shared \
61 -G 0 --eh-frame-hdr --hash-style=sysv --build-id=sha1 -T
62
63CFLAGS_REMOVE_vdso.o = -pg
64
65GCOV_PROFILE := n
66UBSAN_SANITIZE := n
67KCOV_INSTRUMENT := n
68
69# Check that we don't have PIC 'jalr t9' calls left
70quiet_cmd_vdso_mips_check = VDSOCHK $@
71 cmd_vdso_mips_check = if $(OBJDUMP) --disassemble $@ | egrep -h "jalr.*t9" > /dev/null; \
72 then (echo >&2 "$@: PIC 'jalr t9' calls are not supported"; \
73 rm -f $@; /bin/false); fi
74
75#
76# Shared build commands.
77#
78
79quiet_cmd_vdsold_and_vdso_check = LD $@
80 cmd_vdsold_and_vdso_check = $(cmd_ld); $(cmd_vdso_check); $(cmd_vdso_mips_check)
81
82quiet_cmd_vdsoas_o_S = AS $@
83 cmd_vdsoas_o_S = $(CC) $(a_flags) -c -o $@ $<
84
85# Strip rule for the raw .so files
86$(obj)/%.so.raw: OBJCOPYFLAGS := -S
87$(obj)/%.so.raw: $(obj)/%.so.dbg.raw FORCE
88 $(call if_changed,objcopy)
89
90hostprogs := genvdso
91
92quiet_cmd_genvdso = GENVDSO $@
93define cmd_genvdso
94 $(foreach file,$(filter %.raw,$^),cp $(file) $(file:%.raw=%) &&) \
95 $(obj)/genvdso $(<:%.raw=%) $(<:%.dbg.raw=%) $@ $(VDSO_NAME)
96endef
97
98#
99# Build native VDSO.
100#
101
102native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS))
103
104targets += $(obj-vdso-y)
105targets += vdso.lds
106targets += vdso.so.dbg.raw vdso.so.raw
107targets += vdso.so.dbg vdso.so
108targets += vdso-image.c
109
110obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o)
111
112$(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi)
113$(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi)
114
115$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi)
116
117$(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE
118 $(call if_changed,vdsold_and_vdso_check)
119
120$(obj)/vdso-image.c: $(obj)/vdso.so.dbg.raw $(obj)/vdso.so.raw \
121 $(obj)/genvdso FORCE
122 $(call if_changed,genvdso)
123
124obj-y += vdso-image.o
125
126#
127# Build O32 VDSO.
128#
129
130# Define these outside the ifdef to ensure they are picked up by clean.
131targets += $(obj-vdso-y:%.o=%-o32.o)
132targets += vdso-o32.lds
133targets += vdso-o32.so.dbg.raw vdso-o32.so.raw
134targets += vdso-o32.so.dbg vdso-o32.so
135targets += vdso-o32-image.c
136
137ifdef CONFIG_MIPS32_O32
138
139obj-vdso-o32 := $(obj-vdso-y:%.o=$(obj)/%-o32.o)
140
141$(obj-vdso-o32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=32
142$(obj-vdso-o32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=32
143
144$(obj)/%-o32.o: $(src)/%.S FORCE
145 $(call if_changed_dep,vdsoas_o_S)
146
147$(obj)/%-o32.o: $(src)/%.c FORCE
148 $(call cmd,force_checksrc)
149 $(call if_changed_rule,cc_o_c)
150
151$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=32
152$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
153 $(call if_changed_dep,cpp_lds_S)
154
155$(obj)/vdso-o32.so.dbg.raw: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE
156 $(call if_changed,vdsold_and_vdso_check)
157
158$(obj)/vdso-o32-image.c: VDSO_NAME := o32
159$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg.raw $(obj)/vdso-o32.so.raw \
160 $(obj)/genvdso FORCE
161 $(call if_changed,genvdso)
162
163obj-y += vdso-o32-image.o
164
165endif
166
167#
168# Build N32 VDSO.
169#
170
171targets += $(obj-vdso-y:%.o=%-n32.o)
172targets += vdso-n32.lds
173targets += vdso-n32.so.dbg.raw vdso-n32.so.raw
174targets += vdso-n32.so.dbg vdso-n32.so
175targets += vdso-n32-image.c
176
177ifdef CONFIG_MIPS32_N32
178
179obj-vdso-n32 := $(obj-vdso-y:%.o=$(obj)/%-n32.o)
180
181$(obj-vdso-n32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=n32
182$(obj-vdso-n32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=n32
183
184$(obj)/%-n32.o: $(src)/%.S FORCE
185 $(call if_changed_dep,vdsoas_o_S)
186
187$(obj)/%-n32.o: $(src)/%.c FORCE
188 $(call cmd,force_checksrc)
189 $(call if_changed_rule,cc_o_c)
190
191$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=n32
192$(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
193 $(call if_changed_dep,cpp_lds_S)
194
195$(obj)/vdso-n32.so.dbg.raw: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE
196 $(call if_changed,vdsold_and_vdso_check)
197
198$(obj)/vdso-n32-image.c: VDSO_NAME := n32
199$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg.raw $(obj)/vdso-n32.so.raw \
200 $(obj)/genvdso FORCE
201 $(call if_changed,genvdso)
202
203obj-y += vdso-n32-image.o
204
205endif
206
207# FIXME: Need install rule for debug.
208# Needs to deal with dependency for generation of dbg by cmd_genvdso...
diff --git a/arch/mips/vdso/config-n32-o32-env.c b/arch/mips/vdso/config-n32-o32-env.c
new file mode 100644
index 000000000..0011a632a
--- /dev/null
+++ b/arch/mips/vdso/config-n32-o32-env.c
@@ -0,0 +1,19 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Configuration file for O32 and N32 binaries.
4 * Note: To be included before lib/vdso/gettimeofday.c
5 */
6#if defined(CONFIG_MIPS32_O32) || defined(CONFIG_MIPS32_N32)
7/*
8 * In case of a 32 bit VDSO for a 64 bit kernel fake a 32 bit kernel
9 * configuration.
10 */
11#undef CONFIG_64BIT
12
13#define BUILD_VDSO32
14#define CONFIG_32BIT 1
15#define CONFIG_GENERIC_ATOMIC64 1
16#define BUILD_VDSO32_64
17
18#endif
19
diff --git a/arch/mips/vdso/elf.S b/arch/mips/vdso/elf.S
new file mode 100644
index 000000000..a25cb147f
--- /dev/null
+++ b/arch/mips/vdso/elf.S
@@ -0,0 +1,62 @@
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (C) 2015 Imagination Technologies
4 * Author: Alex Smith <alex.smith@imgtec.com>
5 */
6
7#include <asm/vdso/vdso.h>
8
9#include <asm/isa-rev.h>
10
11#include <linux/elfnote.h>
12#include <linux/version.h>
13
14ELFNOTE_START(Linux, 0, "a")
15 .long LINUX_VERSION_CODE
16ELFNOTE_END
17
18/*
19 * The .MIPS.abiflags section must be defined with the FP ABI flags set
20 * to 'any' to be able to link with both old and new libraries.
21 * Newer toolchains are capable of automatically generating this, but we want
22 * to work with older toolchains as well. Therefore, we define the contents of
23 * this section here (under different names), and then genvdso will patch
24 * it to have the correct name and type.
25 *
26 * We base the .MIPS.abiflags section on preprocessor definitions rather than
27 * CONFIG_* because we need to match the particular ABI we are building the
28 * VDSO for.
29 *
30 * See https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
31 * for the .MIPS.abiflags section description.
32 */
33
34 .section .mips_abiflags, "a"
35 .align 3
36__mips_abiflags:
37 .hword 0 /* version */
38 .byte __mips /* isa_level */
39
40 /* isa_rev */
41 .byte MIPS_ISA_REV
42
43 /* gpr_size */
44#ifdef __mips64
45 .byte 2 /* AFL_REG_64 */
46#else
47 .byte 1 /* AFL_REG_32 */
48#endif
49
50 /* cpr1_size */
51#if (MIPS_ISA_REV >= 6) || defined(__mips64)
52 .byte 2 /* AFL_REG_64 */
53#else
54 .byte 1 /* AFL_REG_32 */
55#endif
56
57 .byte 0 /* cpr2_size (AFL_REG_NONE) */
58 .byte 0 /* fp_abi (Val_GNU_MIPS_ABI_FP_ANY) */
59 .word 0 /* isa_ext */
60 .word 0 /* ases */
61 .word 0 /* flags1 */
62 .word 0 /* flags2 */
diff --git a/arch/mips/vdso/genvdso.c b/arch/mips/vdso/genvdso.c
new file mode 100644
index 000000000..abb06ae04
--- /dev/null
+++ b/arch/mips/vdso/genvdso.c
@@ -0,0 +1,312 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2015 Imagination Technologies
4 * Author: Alex Smith <alex.smith@imgtec.com>
5 */
6
7/*
8 * This tool is used to generate the real VDSO images from the raw image. It
9 * first patches up the MIPS ABI flags and GNU attributes sections defined in
10 * elf.S to have the correct name and type. It then generates a C source file
11 * to be compiled into the kernel containing the VDSO image data and a
12 * mips_vdso_image struct for it, including symbol offsets extracted from the
13 * image.
14 *
15 * We need to be passed both a stripped and unstripped VDSO image. The stripped
16 * image is compiled into the kernel, but we must also patch up the unstripped
17 * image's ABI flags sections so that it can be installed and used for
18 * debugging.
19 */
20
21#include <sys/mman.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
25#include <byteswap.h>
26#include <elf.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <inttypes.h>
30#include <stdarg.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37/* Define these in case the system elf.h is not new enough to have them. */
38#ifndef SHT_GNU_ATTRIBUTES
39# define SHT_GNU_ATTRIBUTES 0x6ffffff5
40#endif
41#ifndef SHT_MIPS_ABIFLAGS
42# define SHT_MIPS_ABIFLAGS 0x7000002a
43#endif
44
45enum {
46 ABI_O32 = (1 << 0),
47 ABI_N32 = (1 << 1),
48 ABI_N64 = (1 << 2),
49
50 ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64,
51};
52
53/* Symbols the kernel requires offsets for. */
54static struct {
55 const char *name;
56 const char *offset_name;
57 unsigned int abis;
58} vdso_symbols[] = {
59 { "__vdso_sigreturn", "off_sigreturn", ABI_O32 },
60 { "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL },
61 {}
62};
63
64static const char *program_name;
65static const char *vdso_name;
66static unsigned char elf_class;
67static unsigned int elf_abi;
68static bool need_swap;
69static FILE *out_file;
70
71#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
72# define HOST_ORDER ELFDATA2LSB
73#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
74# define HOST_ORDER ELFDATA2MSB
75#endif
76
77#define BUILD_SWAP(bits) \
78 static uint##bits##_t swap_uint##bits(uint##bits##_t val) \
79 { \
80 return need_swap ? bswap_##bits(val) : val; \
81 }
82
83BUILD_SWAP(16)
84BUILD_SWAP(32)
85BUILD_SWAP(64)
86
87#define __FUNC(name, bits) name##bits
88#define _FUNC(name, bits) __FUNC(name, bits)
89#define FUNC(name) _FUNC(name, ELF_BITS)
90
91#define __ELF(x, bits) Elf##bits##_##x
92#define _ELF(x, bits) __ELF(x, bits)
93#define ELF(x) _ELF(x, ELF_BITS)
94
95/*
96 * Include genvdso.h twice with ELF_BITS defined differently to get functions
97 * for both ELF32 and ELF64.
98 */
99
100#define ELF_BITS 64
101#include "genvdso.h"
102#undef ELF_BITS
103
104#define ELF_BITS 32
105#include "genvdso.h"
106#undef ELF_BITS
107
108static void *map_vdso(const char *path, size_t *_size)
109{
110 int fd;
111 struct stat stat;
112 void *addr;
113 const Elf32_Ehdr *ehdr;
114
115 fd = open(path, O_RDWR);
116 if (fd < 0) {
117 fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
118 path, strerror(errno));
119 return NULL;
120 }
121
122 if (fstat(fd, &stat) != 0) {
123 fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
124 path, strerror(errno));
125 close(fd);
126 return NULL;
127 }
128
129 addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
130 0);
131 if (addr == MAP_FAILED) {
132 fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
133 path, strerror(errno));
134 close(fd);
135 return NULL;
136 }
137
138 /* ELF32/64 header formats are the same for the bits we're checking. */
139 ehdr = addr;
140
141 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
142 fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
143 path);
144 close(fd);
145 return NULL;
146 }
147
148 elf_class = ehdr->e_ident[EI_CLASS];
149 switch (elf_class) {
150 case ELFCLASS32:
151 case ELFCLASS64:
152 break;
153 default:
154 fprintf(stderr, "%s: '%s' has invalid ELF class\n",
155 program_name, path);
156 close(fd);
157 return NULL;
158 }
159
160 switch (ehdr->e_ident[EI_DATA]) {
161 case ELFDATA2LSB:
162 case ELFDATA2MSB:
163 need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
164 break;
165 default:
166 fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
167 program_name, path);
168 close(fd);
169 return NULL;
170 }
171
172 if (swap_uint16(ehdr->e_machine) != EM_MIPS) {
173 fprintf(stderr,
174 "%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
175 program_name, path);
176 close(fd);
177 return NULL;
178 } else if (swap_uint16(ehdr->e_type) != ET_DYN) {
179 fprintf(stderr,
180 "%s: '%s' has invalid ELF type (expected ET_DYN)\n",
181 program_name, path);
182 close(fd);
183 return NULL;
184 }
185
186 *_size = stat.st_size;
187 close(fd);
188 return addr;
189}
190
191static bool patch_vdso(const char *path, void *vdso)
192{
193 if (elf_class == ELFCLASS64)
194 return patch_vdso64(path, vdso);
195 else
196 return patch_vdso32(path, vdso);
197}
198
199static bool get_symbols(const char *path, void *vdso)
200{
201 if (elf_class == ELFCLASS64)
202 return get_symbols64(path, vdso);
203 else
204 return get_symbols32(path, vdso);
205}
206
207int main(int argc, char **argv)
208{
209 const char *dbg_vdso_path, *vdso_path, *out_path;
210 void *dbg_vdso, *vdso;
211 size_t dbg_vdso_size, vdso_size, i;
212
213 program_name = argv[0];
214
215 if (argc < 4 || argc > 5) {
216 fprintf(stderr,
217 "Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n",
218 program_name);
219 return EXIT_FAILURE;
220 }
221
222 dbg_vdso_path = argv[1];
223 vdso_path = argv[2];
224 out_path = argv[3];
225 vdso_name = (argc > 4) ? argv[4] : "";
226
227 dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size);
228 if (!dbg_vdso)
229 return EXIT_FAILURE;
230
231 vdso = map_vdso(vdso_path, &vdso_size);
232 if (!vdso)
233 return EXIT_FAILURE;
234
235 /* Patch both the VDSOs' ABI flags sections. */
236 if (!patch_vdso(dbg_vdso_path, dbg_vdso))
237 return EXIT_FAILURE;
238 if (!patch_vdso(vdso_path, vdso))
239 return EXIT_FAILURE;
240
241 if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) {
242 fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
243 dbg_vdso_path, strerror(errno));
244 return EXIT_FAILURE;
245 } else if (msync(vdso, vdso_size, MS_SYNC) != 0) {
246 fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
247 vdso_path, strerror(errno));
248 return EXIT_FAILURE;
249 }
250
251 out_file = fopen(out_path, "w");
252 if (!out_file) {
253 fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
254 out_path, strerror(errno));
255 return EXIT_FAILURE;
256 }
257
258 fprintf(out_file, "/* Automatically generated - do not edit */\n");
259 fprintf(out_file, "#include <linux/linkage.h>\n");
260 fprintf(out_file, "#include <linux/mm.h>\n");
261 fprintf(out_file, "#include <asm/vdso.h>\n");
262 fprintf(out_file, "static int vdso_mremap(\n");
263 fprintf(out_file, " const struct vm_special_mapping *sm,\n");
264 fprintf(out_file, " struct vm_area_struct *new_vma)\n");
265 fprintf(out_file, "{\n");
266 fprintf(out_file, " unsigned long new_size =\n");
267 fprintf(out_file, " new_vma->vm_end - new_vma->vm_start;\n");
268 fprintf(out_file, " if (vdso_image.size != new_size)\n");
269 fprintf(out_file, " return -EINVAL;\n");
270 fprintf(out_file, " current->mm->context.vdso =\n");
271 fprintf(out_file, " (void *)(new_vma->vm_start);\n");
272 fprintf(out_file, " return 0;\n");
273 fprintf(out_file, "}\n");
274
275 /* Write out the stripped VDSO data. */
276 fprintf(out_file,
277 "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t",
278 vdso_size);
279 for (i = 0; i < vdso_size; i++) {
280 if (!(i % 10))
281 fprintf(out_file, "\n\t");
282 fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]);
283 }
284 fprintf(out_file, "\n};\n");
285
286 /* Preallocate a page array. */
287 fprintf(out_file,
288 "static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n",
289 vdso_size);
290
291 fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n",
292 (vdso_name[0]) ? "_" : "", vdso_name);
293 fprintf(out_file, "\t.data = vdso_data,\n");
294 fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size);
295 fprintf(out_file, "\t.mapping = {\n");
296 fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
297 fprintf(out_file, "\t\t.pages = vdso_pages,\n");
298 fprintf(out_file, "\t\t.mremap = vdso_mremap,\n");
299 fprintf(out_file, "\t},\n");
300
301 /* Calculate and write symbol offsets to <output file> */
302 if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
303 unlink(out_path);
304 fclose(out_file);
305 return EXIT_FAILURE;
306 }
307
308 fprintf(out_file, "};\n");
309 fclose(out_file);
310
311 return EXIT_SUCCESS;
312}
diff --git a/arch/mips/vdso/genvdso.h b/arch/mips/vdso/genvdso.h
new file mode 100644
index 000000000..9bfb87403
--- /dev/null
+++ b/arch/mips/vdso/genvdso.h
@@ -0,0 +1,132 @@
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (C) 2015 Imagination Technologies
4 * Author: Alex Smith <alex.smith@imgtec.com>
5 */
6
7static inline bool FUNC(patch_vdso)(const char *path, void *vdso)
8{
9 const ELF(Ehdr) *ehdr = vdso;
10 void *shdrs;
11 ELF(Shdr) *shdr;
12 char *shstrtab, *name;
13 uint16_t sh_count, sh_entsize, i;
14
15 shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
16 sh_count = swap_uint16(ehdr->e_shnum);
17 sh_entsize = swap_uint16(ehdr->e_shentsize);
18
19 shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
20 shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
21
22 for (i = 0; i < sh_count; i++) {
23 shdr = shdrs + (i * sh_entsize);
24 name = shstrtab + swap_uint32(shdr->sh_name);
25
26 /*
27 * Ensure there are no relocation sections - ld.so does not
28 * relocate the VDSO so if there are relocations things will
29 * break.
30 */
31 switch (swap_uint32(shdr->sh_type)) {
32 case SHT_REL:
33 case SHT_RELA:
34 fprintf(stderr,
35 "%s: '%s' contains relocation sections\n",
36 program_name, path);
37 return false;
38 }
39
40 /* Check for existing sections. */
41 if (strcmp(name, ".MIPS.abiflags") == 0) {
42 fprintf(stderr,
43 "%s: '%s' already contains a '.MIPS.abiflags' section\n",
44 program_name, path);
45 return false;
46 }
47
48 if (strcmp(name, ".mips_abiflags") == 0) {
49 strcpy(name, ".MIPS.abiflags");
50 shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
51 shdr->sh_entsize = shdr->sh_size;
52 }
53 }
54
55 return true;
56}
57
58static inline bool FUNC(get_symbols)(const char *path, void *vdso)
59{
60 const ELF(Ehdr) *ehdr = vdso;
61 void *shdrs, *symtab;
62 ELF(Shdr) *shdr;
63 const ELF(Sym) *sym;
64 char *strtab, *name;
65 uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
66 uint64_t offset;
67 uint32_t flags;
68
69 shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
70 sh_count = swap_uint16(ehdr->e_shnum);
71 sh_entsize = swap_uint16(ehdr->e_shentsize);
72
73 for (i = 0; i < sh_count; i++) {
74 shdr = shdrs + (i * sh_entsize);
75
76 if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
77 break;
78 }
79
80 if (i == sh_count) {
81 fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
82 path);
83 return false;
84 }
85
86 /* Get flags */
87 flags = swap_uint32(ehdr->e_flags);
88 if (elf_class == ELFCLASS64)
89 elf_abi = ABI_N64;
90 else if (flags & EF_MIPS_ABI2)
91 elf_abi = ABI_N32;
92 else
93 elf_abi = ABI_O32;
94
95 /* Get symbol table. */
96 symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
97 st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
98 st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
99
100 /* Get string table. */
101 shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
102 strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
103
104 /* Write offsets for symbols needed by the kernel. */
105 for (i = 0; vdso_symbols[i].name; i++) {
106 if (!(vdso_symbols[i].abis & elf_abi))
107 continue;
108
109 for (j = 0; j < st_count; j++) {
110 sym = symtab + (j * st_entsize);
111 name = strtab + swap_uint32(sym->st_name);
112
113 if (!strcmp(name, vdso_symbols[i].name)) {
114 offset = FUNC(swap_uint)(sym->st_value);
115
116 fprintf(out_file,
117 "\t.%s = 0x%" PRIx64 ",\n",
118 vdso_symbols[i].offset_name, offset);
119 break;
120 }
121 }
122
123 if (j == st_count) {
124 fprintf(stderr,
125 "%s: '%s' is missing required symbol '%s'\n",
126 program_name, path, vdso_symbols[i].name);
127 return false;
128 }
129 }
130
131 return true;
132}
diff --git a/arch/mips/vdso/sigreturn.S b/arch/mips/vdso/sigreturn.S
new file mode 100644
index 000000000..e5c0ab98a
--- /dev/null
+++ b/arch/mips/vdso/sigreturn.S
@@ -0,0 +1,35 @@
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (C) 2015 Imagination Technologies
4 * Author: Alex Smith <alex.smith@imgtec.com>
5 */
6
7#include <asm/vdso/vdso.h>
8
9#include <uapi/asm/unistd.h>
10
11#include <asm/regdef.h>
12#include <asm/asm.h>
13
14 .section .text
15 .cfi_sections .debug_frame
16
17LEAF(__vdso_rt_sigreturn)
18 .cfi_signal_frame
19
20 li v0, __NR_rt_sigreturn
21 syscall
22
23 END(__vdso_rt_sigreturn)
24
25#if _MIPS_SIM == _MIPS_SIM_ABI32
26
27LEAF(__vdso_sigreturn)
28 .cfi_signal_frame
29
30 li v0, __NR_sigreturn
31 syscall
32
33 END(__vdso_sigreturn)
34
35#endif
diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
new file mode 100644
index 000000000..d90b65724
--- /dev/null
+++ b/arch/mips/vdso/vdso.lds.S
@@ -0,0 +1,105 @@
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (C) 2015 Imagination Technologies
4 * Author: Alex Smith <alex.smith@imgtec.com>
5 */
6
7#include <asm/sgidefs.h>
8
9#if _MIPS_SIM == _MIPS_SIM_ABI64
10OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips", "elf64-tradlittlemips")
11#elif _MIPS_SIM == _MIPS_SIM_NABI32
12OUTPUT_FORMAT("elf32-ntradlittlemips", "elf32-ntradbigmips", "elf32-ntradlittlemips")
13#else
14OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips", "elf32-tradlittlemips")
15#endif
16
17OUTPUT_ARCH(mips)
18
19SECTIONS
20{
21 PROVIDE(_start = .);
22 . = SIZEOF_HEADERS;
23
24 /*
25 * In order to retain compatibility with older toolchains we provide the
26 * ABI flags section ourself. Newer assemblers will automatically
27 * generate .MIPS.abiflags sections so we discard such input sections,
28 * and then manually define our own section here. genvdso will patch
29 * this section to have the correct name/type.
30 */
31 .mips_abiflags : { *(.mips_abiflags) } :text :abiflags
32
33 .reginfo : { *(.reginfo) } :text :reginfo
34
35 .hash : { *(.hash) } :text
36 .gnu.hash : { *(.gnu.hash) }
37 .dynsym : { *(.dynsym) }
38 .dynstr : { *(.dynstr) }
39 .gnu.version : { *(.gnu.version) }
40 .gnu.version_d : { *(.gnu.version_d) }
41 .gnu.version_r : { *(.gnu.version_r) }
42
43 .note : { *(.note.*) } :text :note
44
45 .text : { *(.text*) } :text
46 PROVIDE (__etext = .);
47 PROVIDE (_etext = .);
48 PROVIDE (etext = .);
49
50 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
51 .eh_frame : { KEEP (*(.eh_frame)) } :text
52
53 .dynamic : { *(.dynamic) } :text :dynamic
54
55 .rodata : { *(.rodata*) } :text
56
57 _end = .;
58 PROVIDE(end = .);
59
60 /DISCARD/ : {
61 *(.MIPS.abiflags)
62 *(.gnu.attributes)
63 *(.note.GNU-stack)
64 *(.data .data.* .gnu.linkonce.d.* .sdata*)
65 *(.bss .sbss .dynbss .dynsbss)
66 }
67}
68
69PHDRS
70{
71 /*
72 * Provide a PT_MIPS_ABIFLAGS header to assign the ABI flags section
73 * to. We can specify the header type directly here so no modification
74 * is needed later on.
75 */
76 abiflags 0x70000003;
77
78 /*
79 * The ABI flags header must exist directly after the PT_INTERP header,
80 * so we must explicitly place the PT_MIPS_REGINFO header after it to
81 * stop the linker putting one in at the start.
82 */
83 reginfo 0x70000000;
84
85 text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
86 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
87 note PT_NOTE FLAGS(4); /* PF_R */
88 eh_frame_hdr PT_GNU_EH_FRAME;
89}
90
91VERSION
92{
93 LINUX_2.6 {
94#ifndef CONFIG_MIPS_DISABLE_VDSO
95 global:
96 __vdso_clock_gettime;
97 __vdso_gettimeofday;
98 __vdso_clock_getres;
99#if _MIPS_SIM != _MIPS_SIM_ABI64
100 __vdso_clock_gettime64;
101#endif
102#endif
103 local: *;
104 };
105}
diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c
new file mode 100644
index 000000000..6b83b6376
--- /dev/null
+++ b/arch/mips/vdso/vgettimeofday.c
@@ -0,0 +1,78 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * MIPS64 and compat userspace implementations of gettimeofday()
4 * and similar.
5 *
6 * Copyright (C) 2015 Imagination Technologies
7 * Copyright (C) 2018 ARM Limited
8 *
9 */
10#include <linux/time.h>
11#include <linux/types.h>
12
13#if _MIPS_SIM != _MIPS_SIM_ABI64
14int __vdso_clock_gettime(clockid_t clock,
15 struct old_timespec32 *ts)
16{
17 return __cvdso_clock_gettime32(clock, ts);
18}
19
20#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
21
22/*
23 * This is behind the ifdef so that we don't provide the symbol when there's no
24 * possibility of there being a usable clocksource, because there's nothing we
25 * can do without it. When libc fails the symbol lookup it should fall back on
26 * the standard syscall path.
27 */
28int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
29 struct timezone *tz)
30{
31 return __cvdso_gettimeofday(tv, tz);
32}
33
34#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */
35
36int __vdso_clock_getres(clockid_t clock_id,
37 struct old_timespec32 *res)
38{
39 return __cvdso_clock_getres_time32(clock_id, res);
40}
41
42int __vdso_clock_gettime64(clockid_t clock,
43 struct __kernel_timespec *ts)
44{
45 return __cvdso_clock_gettime(clock, ts);
46}
47
48#else
49
50int __vdso_clock_gettime(clockid_t clock,
51 struct __kernel_timespec *ts)
52{
53 return __cvdso_clock_gettime(clock, ts);
54}
55
56#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
57
58/*
59 * This is behind the ifdef so that we don't provide the symbol when there's no
60 * possibility of there being a usable clocksource, because there's nothing we
61 * can do without it. When libc fails the symbol lookup it should fall back on
62 * the standard syscall path.
63 */
64int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
65 struct timezone *tz)
66{
67 return __cvdso_gettimeofday(tv, tz);
68}
69
70#endif /* CONFIG_MIPS_CLOCK_VSYSCALL */
71
72int __vdso_clock_getres(clockid_t clock_id,
73 struct __kernel_timespec *res)
74{
75 return __cvdso_clock_getres(clock_id, res);
76}
77
78#endif