1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* |
3 | * Userland implementation of gettimeofday() for processes |
4 | * for use in the vDSO |
5 | * |
6 | * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org, |
7 | * IBM Corp. |
8 | */ |
9 | #include <asm/processor.h> |
10 | #include <asm/ppc_asm.h> |
11 | #include <asm/vdso.h> |
12 | #include <asm/vdso_datapage.h> |
13 | #include <asm/asm-offsets.h> |
14 | #include <asm/unistd.h> |
15 | |
16 | /* |
17 | * The macro sets two stack frames, one for the caller and one for the callee |
18 | * because there are no requirement for the caller to set a stack frame when |
19 | * calling VDSO so it may have omitted to set one, especially on PPC64 |
20 | */ |
21 | |
22 | .macro cvdso_call funct call_time=0 |
23 | .cfi_startproc |
24 | PPC_STLU r1, -PPC_MIN_STKFRM(r1) |
25 | .cfi_adjust_cfa_offset PPC_MIN_STKFRM |
26 | mflr r0 |
27 | PPC_STLU r1, -PPC_MIN_STKFRM(r1) |
28 | .cfi_adjust_cfa_offset PPC_MIN_STKFRM |
29 | PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) |
30 | .cfi_rel_offset lr, PPC_MIN_STKFRM + PPC_LR_STKOFF |
31 | #ifdef __powerpc64__ |
32 | PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) |
33 | .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT |
34 | #endif |
35 | get_datapage r5 |
36 | .ifeq \call_time |
37 | addi r5, r5, VDSO_DATA_OFFSET |
38 | .else |
39 | addi r4, r5, VDSO_DATA_OFFSET |
40 | .endif |
41 | #ifdef __powerpc64__ |
42 | bl CFUNC(DOTSYM(\funct)) |
43 | #else |
44 | bl \funct |
45 | #endif |
46 | PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) |
47 | #ifdef __powerpc64__ |
48 | PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) |
49 | .cfi_restore r2 |
50 | #endif |
51 | .ifeq \call_time |
52 | cmpwi r3, 0 |
53 | .endif |
54 | mtlr r0 |
55 | addi r1, r1, 2 * PPC_MIN_STKFRM |
56 | .cfi_restore lr |
57 | .cfi_def_cfa_offset 0 |
58 | crclr so |
59 | .ifeq \call_time |
60 | beqlr+ |
61 | crset so |
62 | neg r3, r3 |
63 | .endif |
64 | blr |
65 | .cfi_endproc |
66 | .endm |
67 | |
68 | .text |
69 | /* |
70 | * Exact prototype of gettimeofday |
71 | * |
72 | * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); |
73 | * |
74 | */ |
75 | V_FUNCTION_BEGIN(__kernel_gettimeofday) |
76 | cvdso_call __c_kernel_gettimeofday |
77 | V_FUNCTION_END(__kernel_gettimeofday) |
78 | |
79 | /* |
80 | * Exact prototype of clock_gettime() |
81 | * |
82 | * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); |
83 | * |
84 | */ |
85 | V_FUNCTION_BEGIN(__kernel_clock_gettime) |
86 | cvdso_call __c_kernel_clock_gettime |
87 | V_FUNCTION_END(__kernel_clock_gettime) |
88 | |
89 | /* |
90 | * Exact prototype of clock_gettime64() |
91 | * |
92 | * int __kernel_clock_gettime64(clockid_t clock_id, struct __timespec64 *ts); |
93 | * |
94 | */ |
95 | #ifndef __powerpc64__ |
96 | V_FUNCTION_BEGIN(__kernel_clock_gettime64) |
97 | cvdso_call __c_kernel_clock_gettime64 |
98 | V_FUNCTION_END(__kernel_clock_gettime64) |
99 | #endif |
100 | |
101 | /* |
102 | * Exact prototype of clock_getres() |
103 | * |
104 | * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); |
105 | * |
106 | */ |
107 | V_FUNCTION_BEGIN(__kernel_clock_getres) |
108 | cvdso_call __c_kernel_clock_getres |
109 | V_FUNCTION_END(__kernel_clock_getres) |
110 | |
111 | |
112 | /* |
113 | * Exact prototype of time() |
114 | * |
115 | * time_t time(time *t); |
116 | * |
117 | */ |
118 | V_FUNCTION_BEGIN(__kernel_time) |
119 | cvdso_call __c_kernel_time call_time=1 |
120 | V_FUNCTION_END(__kernel_time) |
121 | |
122 | /* Routines for restoring integer registers, called by the compiler. */ |
123 | /* Called with r11 pointing to the stack header word of the caller of the */ |
124 | /* function, just beyond the end of the integer restore area. */ |
125 | #ifndef __powerpc64__ |
126 | _GLOBAL(_restgpr_31_x) |
127 | _GLOBAL(_rest32gpr_31_x) |
128 | lwz r0,4(r11) |
129 | lwz r31,-4(r11) |
130 | mtlr r0 |
131 | mr r1,r11 |
132 | blr |
133 | #endif |
134 | |