xref: /OK3568_Linux_fs/kernel/arch/mips/include/asm/vdso/vdso.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2015 Imagination Technologies
4*4882a593Smuzhiyun  * Author: Alex Smith <alex.smith@imgtec.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <asm/sgidefs.h>
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #ifndef __ASSEMBLY__
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <asm/asm.h>
12*4882a593Smuzhiyun #include <asm/page.h>
13*4882a593Smuzhiyun #include <asm/vdso.h>
14*4882a593Smuzhiyun 
get_vdso_base(void)15*4882a593Smuzhiyun static inline unsigned long get_vdso_base(void)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	unsigned long addr;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	/*
20*4882a593Smuzhiyun 	 * We can't use cpu_has_mips_r6 since it needs the cpu_data[]
21*4882a593Smuzhiyun 	 * kernel symbol.
22*4882a593Smuzhiyun 	 */
23*4882a593Smuzhiyun #ifdef CONFIG_CPU_MIPSR6
24*4882a593Smuzhiyun 	/*
25*4882a593Smuzhiyun 	 * lapc <symbol> is an alias to addiupc reg, <symbol> - .
26*4882a593Smuzhiyun 	 *
27*4882a593Smuzhiyun 	 * We can't use addiupc because there is no label-label
28*4882a593Smuzhiyun 	 * support for the addiupc reloc
29*4882a593Smuzhiyun 	 */
30*4882a593Smuzhiyun 	__asm__("lapc	%0, _start			\n"
31*4882a593Smuzhiyun 		: "=r" (addr) : :);
32*4882a593Smuzhiyun #else
33*4882a593Smuzhiyun 	/*
34*4882a593Smuzhiyun 	 * Get the base load address of the VDSO. We have to avoid generating
35*4882a593Smuzhiyun 	 * relocations and references to the GOT because ld.so does not peform
36*4882a593Smuzhiyun 	 * relocations on the VDSO. We use the current offset from the VDSO base
37*4882a593Smuzhiyun 	 * and perform a PC-relative branch which gives the absolute address in
38*4882a593Smuzhiyun 	 * ra, and take the difference. The assembler chokes on
39*4882a593Smuzhiyun 	 * "li %0, _start - .", so embed the offset as a word and branch over
40*4882a593Smuzhiyun 	 * it.
41*4882a593Smuzhiyun 	 *
42*4882a593Smuzhiyun 	 */
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	__asm__(
45*4882a593Smuzhiyun 	"	.set push				\n"
46*4882a593Smuzhiyun 	"	.set noreorder				\n"
47*4882a593Smuzhiyun 	"	bal	1f				\n"
48*4882a593Smuzhiyun 	"	 nop					\n"
49*4882a593Smuzhiyun 	"	.word	_start - .			\n"
50*4882a593Smuzhiyun 	"1:	lw	%0, 0($31)			\n"
51*4882a593Smuzhiyun 	"	" STR(PTR_ADDU) " %0, $31, %0		\n"
52*4882a593Smuzhiyun 	"	.set pop				\n"
53*4882a593Smuzhiyun 	: "=r" (addr)
54*4882a593Smuzhiyun 	:
55*4882a593Smuzhiyun 	: "$31");
56*4882a593Smuzhiyun #endif /* CONFIG_CPU_MIPSR6 */
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	return addr;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
get_vdso_data(void)61*4882a593Smuzhiyun static inline const struct vdso_data *get_vdso_data(void)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	return (const struct vdso_data *)(get_vdso_base() - PAGE_SIZE);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #ifdef CONFIG_CLKSRC_MIPS_GIC
67*4882a593Smuzhiyun 
get_gic(const struct vdso_data * data)68*4882a593Smuzhiyun static inline void __iomem *get_gic(const struct vdso_data *data)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	return (void __iomem *)((unsigned long)data & PAGE_MASK) - PAGE_SIZE;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #endif /* CONFIG_CLKSRC_MIPS_GIC */
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #endif /* __ASSEMBLY__ */
76