1 /*
2 * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
3 * Copyright (c) 2012-2021 The strace developers.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7
8 #include "defs.h"
9
10 #include DEF_MPERS_TYPE(struct_mtd_oob_buf)
11
12 #include <linux/ioctl.h>
13 #include <mtd/mtd-abi.h>
14
15 typedef struct mtd_oob_buf struct_mtd_oob_buf;
16
17 #include MPERS_DEFS
18
19 #include "xlat/mtd_mode_options.h"
20 #include "xlat/mtd_file_mode_options.h"
21 #include "xlat/mtd_type_options.h"
22 #include "xlat/mtd_flags_options.h"
23 #include "xlat/mtd_otp_options.h"
24 #include "xlat/mtd_nandecc_options.h"
25
26 static void
27 decode_erase_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
28 {
29 struct erase_info_user einfo;
30
31 if (umove_or_printaddr(tcp, addr, &einfo))
32 return;
33
34 tprint_struct_begin();
35 PRINT_FIELD_X(einfo, start);
36 tprint_struct_next();
37 PRINT_FIELD_X(einfo, length);
38 tprint_struct_end();
39 }
40
41 static void
42 decode_erase_info_user64(struct tcb *const tcp, const kernel_ulong_t addr)
43 {
44 struct erase_info_user64 einfo64;
45
46 if (umove_or_printaddr(tcp, addr, &einfo64))
47 return;
48
49 tprint_struct_begin();
50 PRINT_FIELD_X(einfo64, start);
51 tprint_struct_next();
52 PRINT_FIELD_X(einfo64, length);
53 tprint_struct_end();
54 }
55
56 static void
57 decode_mtd_oob_buf(struct tcb *const tcp, const kernel_ulong_t addr)
58 {
59 struct_mtd_oob_buf mbuf;
60
61 if (umove_or_printaddr(tcp, addr, &mbuf))
62 return;
63 tprint_struct_begin();
64 PRINT_FIELD_X(mbuf, start);
65 tprint_struct_next();
66 PRINT_FIELD_X(mbuf, length);
67 tprint_struct_next();
68 PRINT_FIELD_PTR(mbuf, ptr);
69 tprint_struct_end();
70 }
71
72 static void
73 decode_mtd_oob_buf64(struct tcb *const tcp, const kernel_ulong_t addr)
74 {
75 struct mtd_oob_buf64 mbuf64;
76
77 if (umove_or_printaddr(tcp, addr, &mbuf64))
78 return;
79
80 tprint_struct_begin();
81 PRINT_FIELD_X(mbuf64, start);
82 tprint_struct_next();
83 PRINT_FIELD_X(mbuf64, length);
84 tprint_struct_next();
85 PRINT_FIELD_ADDR64(mbuf64, usr_ptr);
86 tprint_struct_end();
87 }
88
89 static void
90 decode_otp_info(struct tcb *const tcp, const kernel_ulong_t addr)
91 {
92 struct otp_info oinfo;
93
94 if (umove_or_printaddr(tcp, addr, &oinfo))
95 return;
96
97 tprint_struct_begin();
98 PRINT_FIELD_X(oinfo, start);
99 tprint_struct_next();
100 PRINT_FIELD_X(oinfo, length);
101 tprint_struct_next();
102 PRINT_FIELD_U(oinfo, locked);
103 tprint_struct_end();
104 }
105
106 static void
107 decode_otp_select(struct tcb *const tcp, const kernel_ulong_t addr)
108 {
109 unsigned int i;
110
111 if (umove_or_printaddr(tcp, addr, &i))
112 return;
113
114 tprint_indirect_begin();
115 printxval(mtd_otp_options, i, "MTD_OTP_???");
116 tprint_indirect_end();
117 }
118
119 static void
120 decode_mtd_write_req(struct tcb *const tcp, const kernel_ulong_t addr)
121 {
122 struct mtd_write_req mreq;
123
124 if (umove_or_printaddr(tcp, addr, &mreq))
125 return;
126
127 tprint_struct_begin();
128 PRINT_FIELD_X(mreq, start);
129 tprint_struct_next();
130 PRINT_FIELD_X(mreq, len);
131 tprint_struct_next();
132 PRINT_FIELD_X(mreq, ooblen);
133 tprint_struct_next();
134 PRINT_FIELD_ADDR64(mreq, usr_data);
135 tprint_struct_next();
136 PRINT_FIELD_ADDR64(mreq, usr_oob);
137 tprint_struct_next();
138 PRINT_FIELD_XVAL(mreq, mode, mtd_mode_options, "MTD_OPS_???");
139 tprint_struct_end();
140 }
141
142 static void
143 decode_mtd_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
144 {
145 struct mtd_info_user minfo;
146
147 if (umove_or_printaddr(tcp, addr, &minfo))
148 return;
149
150 tprint_struct_begin();
151 PRINT_FIELD_XVAL(minfo, type, mtd_type_options, "MTD_???");
152 tprint_struct_next();
153 PRINT_FIELD_FLAGS(minfo, flags, mtd_flags_options, "MTD_???");
154 tprint_struct_next();
155 PRINT_FIELD_X(minfo, size);
156 tprint_struct_next();
157 PRINT_FIELD_X(minfo, erasesize);
158 tprint_struct_next();
159 PRINT_FIELD_X(minfo, writesize);
160 tprint_struct_next();
161 PRINT_FIELD_X(minfo, oobsize);
162 tprint_struct_next();
163 PRINT_FIELD_X(minfo, padding);
164 tprint_struct_end();
165 }
166
167 static bool
168 print_xint32x2_array_member(struct tcb *tcp, void *elem_buf, size_t elem_size,
169 void *data)
170 {
171 print_local_array_ex(tcp, elem_buf, 2, sizeof(int),
172 print_xint_array_member, NULL, 0, NULL, NULL);
173 return true;
174 }
175
176 static void
177 decode_nand_oobinfo(struct tcb *const tcp, const kernel_ulong_t addr)
178 {
179 struct nand_oobinfo ninfo;
180
181 if (umove_or_printaddr(tcp, addr, &ninfo))
182 return;
183
184 tprint_struct_begin();
185 PRINT_FIELD_XVAL(ninfo, useecc, mtd_nandecc_options, "MTD_NANDECC_???");
186 tprint_struct_next();
187 PRINT_FIELD_X(ninfo, eccbytes);
188 tprint_struct_next();
189 PRINT_FIELD_ARRAY(ninfo, oobfree, tcp, print_xint32x2_array_member);
190 tprint_struct_next();
191 PRINT_FIELD_ARRAY(ninfo, eccpos, tcp, print_xint_array_member);
192 tprint_struct_end();
193 }
194
195 static bool
196 print_nand_oobfree_array_member(struct tcb *tcp, void *elem_buf,
197 size_t elem_size, void *data)
198 {
199 const struct nand_oobfree *p = elem_buf;
200 tprint_struct_begin();
201 PRINT_FIELD_X(*p, offset);
202 tprint_struct_next();
203 PRINT_FIELD_X(*p, length);
204 tprint_struct_end();
205 return true;
206 }
207
208 static void
209 decode_nand_ecclayout_user(struct tcb *const tcp, const kernel_ulong_t addr)
210 {
211 struct nand_ecclayout_user nlay;
212
213 if (umove_or_printaddr(tcp, addr, &nlay))
214 return;
215
216 tprint_struct_begin();
217 PRINT_FIELD_X(nlay, eccbytes);
218 tprint_struct_next();
219 PRINT_FIELD_ARRAY(nlay, eccpos, tcp, print_xint_array_member);
220 tprint_struct_next();
221 PRINT_FIELD_X(nlay, oobavail);
222 tprint_struct_next();
223 PRINT_FIELD_ARRAY(nlay, oobfree, tcp, print_nand_oobfree_array_member);
224 tprint_struct_end();
225 }
226
227 static void
228 decode_mtd_ecc_stats(struct tcb *const tcp, const kernel_ulong_t addr)
229 {
230 struct mtd_ecc_stats es;
231
232 if (umove_or_printaddr(tcp, addr, &es))
233 return;
234
235 tprint_struct_begin();
236 PRINT_FIELD_X(es, corrected);
237 tprint_struct_next();
238 PRINT_FIELD_X(es, failed);
239 tprint_struct_next();
240 PRINT_FIELD_X(es, badblocks);
241 tprint_struct_next();
242 PRINT_FIELD_X(es, bbtblocks);
243 tprint_struct_end();
244 }
245
246 MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp,
247 const unsigned int code, const kernel_ulong_t arg)
248 {
249 switch (code) {
250 case MEMERASE:
251 case MEMLOCK:
252 case MEMUNLOCK:
253 case MEMISLOCKED:
254 tprint_arg_next();
255 decode_erase_info_user(tcp, arg);
256 break;
257
258 case MEMERASE64:
259 tprint_arg_next();
260 decode_erase_info_user64(tcp, arg);
261 break;
262
263 case MEMWRITEOOB:
264 case MEMREADOOB:
265 tprint_arg_next();
266 decode_mtd_oob_buf(tcp, arg);
267 break;
268
269 case MEMWRITEOOB64:
270 case MEMREADOOB64:
271 tprint_arg_next();
272 decode_mtd_oob_buf64(tcp, arg);
273 break;
274
275 case MEMWRITE:
276 tprint_arg_next();
277 decode_mtd_write_req(tcp, arg);
278 break;
279
280 case OTPGETREGIONINFO:
281 if (entering(tcp))
282 return 0;
283 ATTRIBUTE_FALLTHROUGH;
284 case OTPLOCK:
285 tprint_arg_next();
286 decode_otp_info(tcp, arg);
287 break;
288
289 case OTPSELECT:
290 tprint_arg_next();
291 decode_otp_select(tcp, arg);
292 break;
293
294 case MTDFILEMODE:
295 tprint_arg_next();
296 printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
297 break;
298
299 case MEMGETBADBLOCK:
300 case MEMSETBADBLOCK:
301 tprint_arg_next();
302 printnum_int64(tcp, arg, "%" PRIu64);
303 break;
304
305 case MEMGETINFO:
306 if (entering(tcp))
307 return 0;
308 tprint_arg_next();
309 decode_mtd_info_user(tcp, arg);
310 break;
311
312 case MEMGETOOBSEL:
313 if (entering(tcp))
314 return 0;
315 tprint_arg_next();
316 decode_nand_oobinfo(tcp, arg);
317 break;
318
319 case ECCGETLAYOUT:
320 if (entering(tcp))
321 return 0;
322 tprint_arg_next();
323 decode_nand_ecclayout_user(tcp, arg);
324 break;
325
326 case ECCGETSTATS:
327 if (entering(tcp))
328 return 0;
329 tprint_arg_next();
330 decode_mtd_ecc_stats(tcp, arg);
331 break;
332
333 case OTPGETREGIONCOUNT:
334 if (entering(tcp))
335 return 0;
336 tprint_arg_next();
337 printnum_int(tcp, arg, "%u");
338 break;
339
340 case MEMGETREGIONCOUNT:
341 if (entering(tcp))
342 return 0;
343 tprint_arg_next();
344 printnum_int(tcp, arg, "%d");
345 break;
346
347 case MEMGETREGIONINFO:
348 if (entering(tcp)) {
349 struct region_info_user rinfo;
350
351 tprint_arg_next();
352 if (umove_or_printaddr(tcp, arg, &rinfo))
353 break;
354 tprint_struct_begin();
355 PRINT_FIELD_X(rinfo, regionindex);
356 return 0;
357 } else {
358 struct region_info_user rinfo;
359
360 if (!syserror(tcp) && !umove(tcp, arg, &rinfo)) {
361 tprint_struct_next();
362 PRINT_FIELD_X(rinfo, offset);
363 tprint_struct_next();
364 PRINT_FIELD_X(rinfo, erasesize);
365 tprint_struct_next();
366 PRINT_FIELD_X(rinfo, numblocks);
367 }
368 tprint_struct_end();
369 break;
370 }
371
372 default:
373 return RVAL_DECODED;
374 }
375
376 return RVAL_IOCTL_DECODED;
377 }