1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Linaro Limited. All rights reserved.
4 * Author: Rafael David Tinoco <[email protected]>
5 */
6
7 #ifndef CLOCK_ADJTIME_H__
8 #define CLOCK_ADJTIME_H__
9
10 #include "config.h"
11 #include "tst_test.h"
12 #include "tst_timer.h"
13 #include "tst_safe_clocks.h"
14 #include "lapi/syscalls.h"
15 #include "lapi/posix_clocks.h"
16 #include <time.h>
17 #include <pwd.h>
18 #include <sys/timex.h>
19 #include <sys/types.h>
20 #include <asm/posix_types.h>
21 #include "lapi/timex.h"
22
23 struct __kernel_old_timex {
24 unsigned int modes; /* mode selector */
25 __kernel_long_t offset; /* time offset (usec) */
26 __kernel_long_t freq; /* frequency offset (scaled ppm) */
27 __kernel_long_t maxerror;/* maximum error (usec) */
28 __kernel_long_t esterror;/* estimated error (usec) */
29 int status; /* clock command/status */
30 __kernel_long_t constant;/* pll time constant */
31 __kernel_long_t precision;/* clock precision (usec) (read only) */
32 __kernel_long_t tolerance;/* clock frequency tolerance (ppm)
33 * (read only)
34 */
35 struct __kernel_old_timeval time; /* (read only, except for ADJ_SETOFFSET) */
36 __kernel_long_t tick; /* (modified) usecs between clock ticks */
37
38 __kernel_long_t ppsfreq;/* pps frequency (scaled ppm) (ro) */
39 __kernel_long_t jitter; /* pps jitter (us) (ro) */
40 int shift; /* interval duration (s) (shift) (ro) */
41 __kernel_long_t stabil; /* pps stability (scaled ppm) (ro) */
42 __kernel_long_t jitcnt; /* jitter limit exceeded (ro) */
43 __kernel_long_t calcnt; /* calibration intervals (ro) */
44 __kernel_long_t errcnt; /* calibration errors (ro) */
45 __kernel_long_t stbcnt; /* stability limit exceeded (ro) */
46
47 int tai; /* TAI offset (ro) */
48
49 int :32; int :32; int :32; int :32;
50 int :32; int :32; int :32; int :32;
51 int :32; int :32; int :32;
52 };
53
54 #ifndef HAVE_STRUCT___KERNEL_TIMEX_TIMEVAL
55 struct __kernel_timex_timeval {
56 __kernel_time64_t tv_sec;
57 long long tv_usec;
58 };
59 #endif
60
61 #ifndef HAVE_STRUCT___KERNEL_TIMEX
62 struct __kernel_timex {
63 unsigned int modes; /* mode selector */
64 int :32; /* pad */
65 long long offset; /* time offset (usec) */
66 long long freq; /* frequency offset (scaled ppm) */
67 long long maxerror;/* maximum error (usec) */
68 long long esterror;/* estimated error (usec) */
69 int status; /* clock command/status */
70 int :32; /* pad */
71 long long constant;/* pll time constant */
72 long long precision;/* clock precision (usec) (read only) */
73 long long tolerance;/* clock frequency tolerance (ppm)
74 * (read only)
75 */
76 struct __kernel_timex_timeval time; /* (read only, except for ADJ_SETOFFSET) */
77 long long tick; /* (modified) usecs between clock ticks */
78
79 long long ppsfreq;/* pps frequency (scaled ppm) (ro) */
80 long long jitter; /* pps jitter (us) (ro) */
81 int shift; /* interval duration (s) (shift) (ro) */
82 int :32; /* pad */
83 long long stabil; /* pps stability (scaled ppm) (ro) */
84 long long jitcnt; /* jitter limit exceeded (ro) */
85 long long calcnt; /* calibration intervals (ro) */
86 long long errcnt; /* calibration errors (ro) */
87 long long stbcnt; /* stability limit exceeded (ro) */
88
89 int tai; /* TAI offset (ro) */
90
91 int :32; int :32; int :32; int :32;
92 int :32; int :32; int :32; int :32;
93 int :32; int :32; int :32;
94 };
95 #endif
96
97 enum tst_timex_type {
98 TST_KERN_OLD_TIMEX,
99 TST_KERN_TIMEX
100 };
101
102 struct tst_timex {
103 enum tst_timex_type type;
104 union tx{
105 struct __kernel_old_timex kern_old_timex;
106 struct __kernel_timex kern_timex;
107 } tx;
108 };
109
tst_timex_get(struct tst_timex * t)110 static inline void *tst_timex_get(struct tst_timex *t)
111 {
112 switch (t->type) {
113 case TST_KERN_OLD_TIMEX:
114 return &t->tx.kern_old_timex;
115 case TST_KERN_TIMEX:
116 return &t->tx.kern_timex;
117 default:
118 tst_brk(TBROK, "Invalid type: %d", t->type);
119 return NULL;
120 }
121 }
122
sys_clock_adjtime(clockid_t clk_id,void * timex)123 static inline int sys_clock_adjtime(clockid_t clk_id, void *timex)
124 {
125 return tst_syscall(__NR_clock_adjtime, clk_id, timex);
126 }
127
sys_clock_adjtime64(clockid_t clk_id,void * timex)128 static inline int sys_clock_adjtime64(clockid_t clk_id, void *timex)
129 {
130 return tst_syscall(__NR_clock_adjtime64, clk_id, timex);
131 }
132
133 #define TIMEX_SHOW(tx, mode, fmt) \
134 tst_res(TINFO, "%s\n" \
135 " mode: %u\n" \
136 " offset: "fmt"\n" \
137 " frequency: "fmt"\n" \
138 " maxerror: "fmt"\n" \
139 " esterror: "fmt"\n" \
140 " status: %d (0x%x)\n" \
141 " time_constant: "fmt"\n" \
142 " precision: "fmt"\n" \
143 " tolerance: "fmt"\n" \
144 " tick: "fmt"\n" \
145 " raw time: "fmt"(s) "fmt"(us)", \
146 mode, \
147 tx.modes, \
148 tx.offset, \
149 tx.freq, \
150 tx.maxerror, \
151 tx.esterror, \
152 tx.status, \
153 tx.status, \
154 tx.constant, \
155 tx.precision, \
156 tx.tolerance, \
157 tx.tick, \
158 tx.time.tv_sec, \
159 tx.time.tv_usec)
160
timex_show(const char * mode,struct tst_timex * timex)161 static inline void timex_show(const char *mode, struct tst_timex *timex)
162 {
163 switch (timex->type) {
164 case TST_KERN_OLD_TIMEX:
165 TIMEX_SHOW(timex->tx.kern_old_timex, mode, "%ld");
166 return;
167 case TST_KERN_TIMEX:
168 TIMEX_SHOW(timex->tx.kern_timex, mode, "%lld");
169 return;
170 default:
171 tst_brk(TBROK, "Invalid type: %d", timex->type);
172 }
173 }
174
175 #undef TIMEX_SHOW
176
177 #define ADJ_MODES 0
178
179 #define SELECT_FIELD(tx, field) \
180 { \
181 switch (field) { \
182 case ADJ_MODES: \
183 return &tx.modes; \
184 case ADJ_OFFSET: \
185 return &tx.offset; \
186 case ADJ_FREQUENCY: \
187 return &tx.freq; \
188 case ADJ_MAXERROR: \
189 return &tx.maxerror; \
190 case ADJ_ESTERROR: \
191 return &tx.esterror; \
192 case ADJ_TIMECONST: \
193 return &tx.constant; \
194 case ADJ_TICK: \
195 return &tx.tick; \
196 case ADJ_STATUS: \
197 return &tx.status; \
198 default: \
199 tst_brk(TBROK, "Invalid type: %d", timex->type); \
200 return NULL; \
201 } \
202 }
203
timex_get_field(struct tst_timex * timex,unsigned int field)204 static inline void *timex_get_field(struct tst_timex *timex, unsigned int field)
205 {
206 switch (timex->type) {
207 case TST_KERN_OLD_TIMEX:
208 SELECT_FIELD(timex->tx.kern_old_timex, field);
209 case TST_KERN_TIMEX:
210 SELECT_FIELD(timex->tx.kern_timex, field);
211 default:
212 tst_brk(TBROK, "Invalid type: %d", timex->type);
213 return NULL;
214 }
215 }
216
217 #undef SELECT_FIELD
218
219 #define TIMEX_GET_SET_FIELD_TYPE(type_libc, type_kern) \
220 static inline type_kern \
221 timex_get_field_##type_libc(struct tst_timex *timex, unsigned int field) \
222 { \
223 switch (timex->type) { \
224 case TST_KERN_OLD_TIMEX: \
225 return *((type_libc*)timex_get_field(timex, field)); \
226 case TST_KERN_TIMEX: \
227 return *((type_kern*)timex_get_field(timex, field)); \
228 default: \
229 tst_res(TFAIL, "Invalid type: %d", timex->type); \
230 return 0; \
231 } \
232 } \
233 \
234 static inline void \
235 timex_set_field_##type_libc(struct tst_timex *timex, unsigned int field, \
236 type_kern value) \
237 { \
238 switch (timex->type) { \
239 case TST_KERN_OLD_TIMEX: \
240 *((type_libc*)timex_get_field(timex, field)) = value; \
241 return; \
242 case TST_KERN_TIMEX: \
243 *((type_kern*)timex_get_field(timex, field)) = value; \
244 return; \
245 default: \
246 tst_res(TFAIL, "Invalid type: %d", timex->type); \
247 } \
248 }
249
250 TIMEX_GET_SET_FIELD_TYPE(uint, uint);
251 TIMEX_GET_SET_FIELD_TYPE(long, long long);
252
253 #undef TIMEX_GET_SET_FIELD_TYPE
254
255 #endif /* CLOCK_ADJTIME_H__ */
256