1 /*
2 * Copyright (c) 2004 Ulrich Drepper <drepper@redhat.com>
3 * Copyright (c) 2004-2016 Dmitry V. Levin <ldv@strace.io>
4 * Copyright (c) 2015-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11
12 #include DEF_MPERS_TYPE(struct_rtc_pll_info)
13
14 #include <linux/ioctl.h>
15 #include <linux/rtc.h>
16
17 typedef struct rtc_pll_info struct_rtc_pll_info;
18
19 #include MPERS_DEFS
20
21 typedef struct {
22 uint64_t param;
23 union {
24 uint64_t uvalue;
25 int64_t svalue;
26 uint64_t ptr;
27 };
28 uint32_t index;
29 uint32_t __pad;
30 } struct_rtc_param;
31
32 #define XLAT_MACROS_ONLY
33 # include "xlat/rtc_ioctl_cmds.h"
34 # include "xlat/rtc_feature_bits.h"
35 #undef XLAT_MACROS_ONLY
36
37 #include "xlat/rtc_vl_flags.h"
38 #include "xlat/rtc_params.h"
39 #include "xlat/rtc_features.h"
40 #include "xlat/rtc_backup_switch_modes.h"
41
42 static void
43 print_rtc_time(struct tcb *tcp, const struct rtc_time *rt)
44 {
45 tprint_struct_begin();
46 PRINT_FIELD_D(*rt, tm_sec);
47 tprint_struct_next();
48 PRINT_FIELD_D(*rt, tm_min);
49 tprint_struct_next();
50 PRINT_FIELD_D(*rt, tm_hour);
51 tprint_struct_next();
52 PRINT_FIELD_D(*rt, tm_mday);
53 tprint_struct_next();
54 PRINT_FIELD_D(*rt, tm_mon);
55 tprint_struct_next();
56 PRINT_FIELD_D(*rt, tm_year);
57 if (abbrev(tcp)) {
58 tprint_struct_next();
59 tprint_more_data_follows();
60 } else {
61 tprint_struct_next();
62 PRINT_FIELD_D(*rt, tm_wday);
63 tprint_struct_next();
64 PRINT_FIELD_D(*rt, tm_yday);
65 tprint_struct_next();
66 PRINT_FIELD_D(*rt, tm_isdst);
67 }
68 tprint_struct_end();
69 }
70
71 static void
72 decode_rtc_time(struct tcb *const tcp, const kernel_ulong_t addr)
73 {
74 struct rtc_time rt;
75
76 if (!umove_or_printaddr(tcp, addr, &rt))
77 print_rtc_time(tcp, &rt);
78 }
79
80 static void
81 decode_rtc_wkalrm(struct tcb *const tcp, const kernel_ulong_t addr)
82 {
83 struct rtc_wkalrm wk;
84
85 if (umove_or_printaddr(tcp, addr, &wk))
86 return;
87
88 tprint_struct_begin();
89 PRINT_FIELD_U(wk, enabled);
90 tprint_struct_next();
91 PRINT_FIELD_U(wk, pending);
92 tprint_struct_next();
93 PRINT_FIELD_OBJ_TCB_PTR(wk, time, tcp, print_rtc_time);
94 tprint_struct_end();
95 }
96
97 static void
98 decode_rtc_pll_info(struct tcb *const tcp, const kernel_ulong_t addr)
99 {
100 struct_rtc_pll_info pll;
101
102 if (umove_or_printaddr(tcp, addr, &pll))
103 return;
104
105 tprint_struct_begin();
106 PRINT_FIELD_D(pll, pll_ctrl);
107 tprint_struct_next();
108 PRINT_FIELD_D(pll, pll_value);
109 tprint_struct_next();
110 PRINT_FIELD_D(pll, pll_max);
111 tprint_struct_next();
112 PRINT_FIELD_D(pll, pll_min);
113 tprint_struct_next();
114 PRINT_FIELD_D(pll, pll_posmult);
115 tprint_struct_next();
116 PRINT_FIELD_D(pll, pll_negmult);
117 tprint_struct_next();
118 PRINT_FIELD_D(pll, pll_clock);
119 tprint_struct_end();
120 }
121
122 static void
123 decode_rtc_vl(struct tcb *const tcp, const kernel_ulong_t addr)
124 {
125 unsigned int val;
126
127 if (umove_or_printaddr(tcp, addr, &val))
128 return;
129
130 tprint_indirect_begin();
131 printflags(rtc_vl_flags, val, "RTC_VL_???");
132 tprint_indirect_end();
133 }
134
135 static long
136 decode_rtc_param(struct tcb *const tcp, const kernel_ulong_t addr, const bool get)
137 {
138 struct_rtc_param param;
139
140 if (umove_or_printaddr(tcp, addr, ¶m))
141 return RVAL_IOCTL_DECODED;
142
143 tprint_struct_begin();
144 if (entering(tcp))
145 PRINT_FIELD_XVAL(param, param, rtc_params, "RTC_PARAM_???");
146 if (entering(tcp) ^ get) {
147 if (entering(tcp))
148 tprint_struct_next();
149 switch (param.param) {
150 case RTC_PARAM_FEATURES:
151 PRINT_FIELD_FLAGS(param, uvalue, rtc_features,
152 "1<<RTC_FEATURE_???");
153 break;
154 case RTC_PARAM_CORRECTION:
155 PRINT_FIELD_D(param, svalue);
156 break;
157 case RTC_PARAM_BACKUP_SWITCH_MODE:
158 PRINT_FIELD_XVAL(param, uvalue, rtc_backup_switch_modes,
159 "RTC_BSM_???");
160 break;
161 default:
162 PRINT_FIELD_X(param, uvalue);
163 }
164 }
165 if (entering(tcp)) {
166 tprint_struct_next();
167 PRINT_FIELD_U(param, index);
168 }
169 if (param.__pad) {
170 tprint_struct_next();
171 PRINT_FIELD_X(param, __pad);
172 }
173 tprint_struct_end();
174
175 return entering(tcp) && get ? 0 : RVAL_IOCTL_DECODED;
176 }
177
178 MPERS_PRINTER_DECL(int, rtc_ioctl, struct tcb *const tcp,
179 const unsigned int code, const kernel_ulong_t arg)
180 {
181 switch (code) {
182 case RTC_ALM_READ:
183 case RTC_RD_TIME:
184 if (entering(tcp))
185 return 0;
186 ATTRIBUTE_FALLTHROUGH;
187 case RTC_ALM_SET:
188 case RTC_SET_TIME:
189 tprint_arg_next();
190 decode_rtc_time(tcp, arg);
191 break;
192 case RTC_IRQP_SET:
193 case RTC_EPOCH_SET:
194 tprint_arg_next();
195 PRINT_VAL_U(arg);
196 break;
197 case RTC_IRQP_READ:
198 case RTC_EPOCH_READ:
199 if (entering(tcp))
200 return 0;
201 tprint_arg_next();
202 printnum_ulong(tcp, arg);
203 break;
204 case RTC_WKALM_RD:
205 if (entering(tcp))
206 return 0;
207 ATTRIBUTE_FALLTHROUGH;
208 case RTC_WKALM_SET:
209 tprint_arg_next();
210 decode_rtc_wkalrm(tcp, arg);
211 break;
212 case RTC_PLL_GET:
213 if (entering(tcp))
214 return 0;
215 ATTRIBUTE_FALLTHROUGH;
216 case RTC_PLL_SET:
217 tprint_arg_next();
218 decode_rtc_pll_info(tcp, arg);
219 break;
220 case RTC_VL_READ:
221 if (entering(tcp))
222 return 0;
223 tprint_arg_next();
224 decode_rtc_vl(tcp, arg);
225 break;
226 case RTC_PARAM_GET:
227 case RTC_PARAM_SET:
228 if (entering(tcp))
229 tprint_arg_next();
230 else
231 tprint_value_changed();
232 return decode_rtc_param(tcp, arg, code == RTC_PARAM_GET);
233 case RTC_AIE_ON:
234 case RTC_AIE_OFF:
235 case RTC_UIE_ON:
236 case RTC_UIE_OFF:
237 case RTC_PIE_ON:
238 case RTC_PIE_OFF:
239 case RTC_WIE_ON:
240 case RTC_WIE_OFF:
241 case RTC_VL_CLR:
242 /* no args */
243 break;
244 default:
245 return RVAL_DECODED;
246 }
247
248 return RVAL_IOCTL_DECODED;
249 }