1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Dummy stubs used when CONFIG_POSIX_TIMERS=n |
4 | * |
5 | * Created by: Nicolas Pitre, July 2016 |
6 | * Copyright: (C) 2016 Linaro Limited |
7 | */ |
8 | |
9 | #include <linux/linkage.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/sched.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/syscalls.h> |
14 | #include <linux/ktime.h> |
15 | #include <linux/timekeeping.h> |
16 | #include <linux/posix-timers.h> |
17 | #include <linux/time_namespace.h> |
18 | #include <linux/compat.h> |
19 | |
20 | #ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER |
21 | /* Architectures may override SYS_NI and COMPAT_SYS_NI */ |
22 | #include <asm/syscall_wrapper.h> |
23 | #endif |
24 | |
25 | asmlinkage long sys_ni_posix_timers(void) |
26 | { |
27 | pr_err_once("process %d (%s) attempted a POSIX timer syscall " |
28 | "while CONFIG_POSIX_TIMERS is not set\n" , |
29 | current->pid, current->comm); |
30 | return -ENOSYS; |
31 | } |
32 | |
33 | #ifndef SYS_NI |
34 | #define SYS_NI(name) SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers) |
35 | #endif |
36 | |
37 | #ifndef COMPAT_SYS_NI |
38 | #define COMPAT_SYS_NI(name) SYSCALL_ALIAS(compat_sys_##name, sys_ni_posix_timers) |
39 | #endif |
40 | |
41 | SYS_NI(timer_create); |
42 | SYS_NI(timer_gettime); |
43 | SYS_NI(timer_getoverrun); |
44 | SYS_NI(timer_settime); |
45 | SYS_NI(timer_delete); |
46 | SYS_NI(clock_adjtime); |
47 | SYS_NI(getitimer); |
48 | SYS_NI(setitimer); |
49 | SYS_NI(clock_adjtime32); |
50 | #ifdef __ARCH_WANT_SYS_ALARM |
51 | SYS_NI(alarm); |
52 | #endif |
53 | |
54 | /* |
55 | * We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC |
56 | * as it is easy to remain compatible with little code. CLOCK_BOOTTIME |
57 | * is also included for convenience as at least systemd uses it. |
58 | */ |
59 | |
60 | SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, |
61 | const struct __kernel_timespec __user *, tp) |
62 | { |
63 | struct timespec64 new_tp; |
64 | |
65 | if (which_clock != CLOCK_REALTIME) |
66 | return -EINVAL; |
67 | if (get_timespec64(ts: &new_tp, uts: tp)) |
68 | return -EFAULT; |
69 | |
70 | return do_sys_settimeofday64(tv: &new_tp, NULL); |
71 | } |
72 | |
73 | static int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp) |
74 | { |
75 | switch (which_clock) { |
76 | case CLOCK_REALTIME: |
77 | ktime_get_real_ts64(tv: tp); |
78 | break; |
79 | case CLOCK_MONOTONIC: |
80 | ktime_get_ts64(ts: tp); |
81 | timens_add_monotonic(ts: tp); |
82 | break; |
83 | case CLOCK_BOOTTIME: |
84 | ktime_get_boottime_ts64(ts: tp); |
85 | timens_add_boottime(ts: tp); |
86 | break; |
87 | default: |
88 | return -EINVAL; |
89 | } |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, |
95 | struct __kernel_timespec __user *, tp) |
96 | { |
97 | int ret; |
98 | struct timespec64 kernel_tp; |
99 | |
100 | ret = do_clock_gettime(which_clock, tp: &kernel_tp); |
101 | if (ret) |
102 | return ret; |
103 | |
104 | if (put_timespec64(ts: &kernel_tp, uts: tp)) |
105 | return -EFAULT; |
106 | return 0; |
107 | } |
108 | |
109 | SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct __kernel_timespec __user *, tp) |
110 | { |
111 | struct timespec64 rtn_tp = { |
112 | .tv_sec = 0, |
113 | .tv_nsec = hrtimer_resolution, |
114 | }; |
115 | |
116 | switch (which_clock) { |
117 | case CLOCK_REALTIME: |
118 | case CLOCK_MONOTONIC: |
119 | case CLOCK_BOOTTIME: |
120 | if (put_timespec64(ts: &rtn_tp, uts: tp)) |
121 | return -EFAULT; |
122 | return 0; |
123 | default: |
124 | return -EINVAL; |
125 | } |
126 | } |
127 | |
128 | SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, |
129 | const struct __kernel_timespec __user *, rqtp, |
130 | struct __kernel_timespec __user *, rmtp) |
131 | { |
132 | struct timespec64 t; |
133 | ktime_t texp; |
134 | |
135 | switch (which_clock) { |
136 | case CLOCK_REALTIME: |
137 | case CLOCK_MONOTONIC: |
138 | case CLOCK_BOOTTIME: |
139 | break; |
140 | default: |
141 | return -EINVAL; |
142 | } |
143 | |
144 | if (get_timespec64(ts: &t, uts: rqtp)) |
145 | return -EFAULT; |
146 | if (!timespec64_valid(ts: &t)) |
147 | return -EINVAL; |
148 | if (flags & TIMER_ABSTIME) |
149 | rmtp = NULL; |
150 | current->restart_block.fn = do_no_restart_syscall; |
151 | current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE; |
152 | current->restart_block.nanosleep.rmtp = rmtp; |
153 | texp = timespec64_to_ktime(ts: t); |
154 | if (flags & TIMER_ABSTIME) |
155 | texp = timens_ktime_to_host(clockid: which_clock, tim: texp); |
156 | return hrtimer_nanosleep(rqtp: texp, mode: flags & TIMER_ABSTIME ? |
157 | HRTIMER_MODE_ABS : HRTIMER_MODE_REL, |
158 | clockid: which_clock); |
159 | } |
160 | |
161 | #ifdef CONFIG_COMPAT |
162 | COMPAT_SYS_NI(timer_create); |
163 | #endif |
164 | |
165 | #if defined(CONFIG_COMPAT) || defined(CONFIG_ALPHA) |
166 | COMPAT_SYS_NI(getitimer); |
167 | COMPAT_SYS_NI(setitimer); |
168 | #endif |
169 | |
170 | #ifdef CONFIG_COMPAT_32BIT_TIME |
171 | SYS_NI(timer_settime32); |
172 | SYS_NI(timer_gettime32); |
173 | |
174 | SYSCALL_DEFINE2(clock_settime32, const clockid_t, which_clock, |
175 | struct old_timespec32 __user *, tp) |
176 | { |
177 | struct timespec64 new_tp; |
178 | |
179 | if (which_clock != CLOCK_REALTIME) |
180 | return -EINVAL; |
181 | if (get_old_timespec32(&new_tp, tp)) |
182 | return -EFAULT; |
183 | |
184 | return do_sys_settimeofday64(tv: &new_tp, NULL); |
185 | } |
186 | |
187 | SYSCALL_DEFINE2(clock_gettime32, clockid_t, which_clock, |
188 | struct old_timespec32 __user *, tp) |
189 | { |
190 | int ret; |
191 | struct timespec64 kernel_tp; |
192 | |
193 | ret = do_clock_gettime(which_clock, tp: &kernel_tp); |
194 | if (ret) |
195 | return ret; |
196 | |
197 | if (put_old_timespec32(&kernel_tp, tp)) |
198 | return -EFAULT; |
199 | return 0; |
200 | } |
201 | |
202 | SYSCALL_DEFINE2(clock_getres_time32, clockid_t, which_clock, |
203 | struct old_timespec32 __user *, tp) |
204 | { |
205 | struct timespec64 rtn_tp = { |
206 | .tv_sec = 0, |
207 | .tv_nsec = hrtimer_resolution, |
208 | }; |
209 | |
210 | switch (which_clock) { |
211 | case CLOCK_REALTIME: |
212 | case CLOCK_MONOTONIC: |
213 | case CLOCK_BOOTTIME: |
214 | if (put_old_timespec32(&rtn_tp, tp)) |
215 | return -EFAULT; |
216 | return 0; |
217 | default: |
218 | return -EINVAL; |
219 | } |
220 | } |
221 | |
222 | SYSCALL_DEFINE4(clock_nanosleep_time32, clockid_t, which_clock, int, flags, |
223 | struct old_timespec32 __user *, rqtp, |
224 | struct old_timespec32 __user *, rmtp) |
225 | { |
226 | struct timespec64 t; |
227 | ktime_t texp; |
228 | |
229 | switch (which_clock) { |
230 | case CLOCK_REALTIME: |
231 | case CLOCK_MONOTONIC: |
232 | case CLOCK_BOOTTIME: |
233 | break; |
234 | default: |
235 | return -EINVAL; |
236 | } |
237 | |
238 | if (get_old_timespec32(&t, rqtp)) |
239 | return -EFAULT; |
240 | if (!timespec64_valid(ts: &t)) |
241 | return -EINVAL; |
242 | if (flags & TIMER_ABSTIME) |
243 | rmtp = NULL; |
244 | current->restart_block.fn = do_no_restart_syscall; |
245 | current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE; |
246 | current->restart_block.nanosleep.compat_rmtp = rmtp; |
247 | texp = timespec64_to_ktime(ts: t); |
248 | if (flags & TIMER_ABSTIME) |
249 | texp = timens_ktime_to_host(clockid: which_clock, tim: texp); |
250 | return hrtimer_nanosleep(rqtp: texp, mode: flags & TIMER_ABSTIME ? |
251 | HRTIMER_MODE_ABS : HRTIMER_MODE_REL, |
252 | clockid: which_clock); |
253 | } |
254 | #endif |
255 | |