1/*
2 * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 *    derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "defs.h"
28
29#include <linux/ioctl.h>
30
31/* The mtd api changes quickly, so we have to keep a local copy */
32#include <linux/version.h>
33#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
34# include "mtd-abi.h"
35#else
36# include <mtd/mtd-abi.h>
37#endif
38#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
39# include "ubi-user.h"
40#else
41# include <mtd/ubi-user.h>
42#endif
43
44#include "xlat/mtd_mode_options.h"
45#include "xlat/mtd_file_mode_options.h"
46#include "xlat/mtd_type_options.h"
47#include "xlat/mtd_flags_options.h"
48#include "xlat/mtd_otp_options.h"
49#include "xlat/mtd_nandecc_options.h"
50
51int
52mtd_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
53{
54	if (!verbose(tcp))
55		return RVAL_DECODED;
56
57	switch (code) {
58	case MEMERASE:
59	case MEMLOCK:
60	case MEMUNLOCK:
61	case MEMISLOCKED: {
62		struct erase_info_user einfo;
63
64		tprints(", ");
65		if (umove_or_printaddr(tcp, arg, &einfo))
66			break;
67
68		tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 "}",
69			einfo.start, einfo.length);
70		break;
71	}
72
73	case MEMERASE64: {
74		struct erase_info_user64 einfo64;
75
76		tprints(", ");
77		if (umove_or_printaddr(tcp, arg, &einfo64))
78			break;
79
80		tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}",
81			(uint64_t) einfo64.start, (uint64_t) einfo64.length);
82		break;
83	}
84
85	case MEMWRITEOOB:
86	case MEMREADOOB: {
87		struct mtd_oob_buf mbuf;
88
89		tprints(", ");
90		if (umove_or_printaddr(tcp, arg, &mbuf))
91			break;
92
93		tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 ", ptr=...}",
94			mbuf.start, mbuf.length);
95		break;
96	}
97
98	case MEMWRITEOOB64:
99	case MEMREADOOB64: {
100		struct mtd_oob_buf64 mbuf64;
101
102		tprints(", ");
103		if (umove_or_printaddr(tcp, arg, &mbuf64))
104			break;
105
106		tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 ", ptr=...}",
107			(uint64_t) mbuf64.start, (uint64_t) mbuf64.length);
108		break;
109	}
110
111	case MEMGETREGIONINFO: {
112		struct region_info_user rinfo;
113
114		if (entering(tcp)) {
115			tprints(", ");
116			if (umove_or_printaddr(tcp, arg, &rinfo))
117				break;
118			tprintf("{regionindex=%#x", rinfo.regionindex);
119			return 1;
120		} else {
121			if (syserror(tcp)) {
122				tprints("}");
123				break;
124			}
125			if (umove(tcp, arg, &rinfo) < 0) {
126				tprints(", ???}");
127				break;
128			}
129			tprintf(", offset=%#x, erasesize=%#x, numblocks=%#x}",
130				rinfo.offset, rinfo.erasesize, rinfo.numblocks);
131			break;
132		}
133	}
134
135	case OTPLOCK: {
136		struct otp_info oinfo;
137
138		tprints(", ");
139		if (umove_or_printaddr(tcp, arg, &oinfo))
140			break;
141
142		tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
143			oinfo.start, oinfo.length, oinfo.locked);
144		break;
145	}
146
147	case MEMWRITE: {
148		struct mtd_write_req mreq;
149
150		tprints(", ");
151		if (umove_or_printaddr(tcp, arg, &mreq))
152			break;
153
154		tprintf("{start=%#" PRIx64 ", len=%#" PRIx64,
155			(uint64_t) mreq.start, (uint64_t) mreq.len);
156		tprintf(", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64,
157			(uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data);
158		tprintf(", usr_oob=%#" PRIx64 ", mode=",
159			(uint64_t) mreq.usr_oob);
160		printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
161		tprints(", padding=...}");
162		break;
163	}
164
165	case OTPSELECT: {
166		unsigned int i;
167
168		tprints(", ");
169		if (umove_or_printaddr(tcp, arg, &i))
170			break;
171
172		tprints("[");
173		printxval(mtd_otp_options, i, "MTD_OTP_???");
174		tprints("]");
175		break;
176	}
177
178	case MTDFILEMODE:
179		tprints(", ");
180		printxval(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
181		break;
182
183	case MEMGETBADBLOCK:
184	case MEMSETBADBLOCK:
185		tprints(", ");
186		printnum_int64(tcp, arg, "%" PRIu64);
187		break;
188
189	case MEMGETINFO: {
190		struct mtd_info_user minfo;
191
192		if (entering(tcp))
193			return 0;
194
195		tprints(", ");
196		if (umove_or_printaddr(tcp, arg, &minfo))
197			break;
198
199		tprints("{type=");
200		printxval(mtd_type_options, minfo.type, "MTD_???");
201		tprints(", flags=");
202		printflags(mtd_flags_options, minfo.flags, "MTD_???");
203		tprintf(", size=%#" PRIx32 ", erasesize=%#" PRIx32,
204			minfo.size, minfo.erasesize);
205		tprintf(", writesize=%#" PRIx32 ", oobsize=%#" PRIx32,
206			minfo.writesize, minfo.oobsize);
207		tprintf(", padding=%#" PRIx64 "}",
208			(uint64_t) minfo.padding);
209		break;
210	}
211
212	case MEMGETOOBSEL: {
213		struct nand_oobinfo ninfo;
214		unsigned int i;
215
216		if (entering(tcp))
217			return 0;
218
219		tprints(", ");
220		if (umove_or_printaddr(tcp, arg, &ninfo))
221			break;
222
223		tprints("{useecc=");
224		printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
225		tprintf(", eccbytes=%#" PRIx32, ninfo.eccbytes);
226
227		tprints(", oobfree={");
228		for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
229			unsigned int j;
230
231			if (i)
232				tprints("}, ");
233			tprints("{");
234			for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
235				if (j)
236					tprints(", ");
237				tprintf("%#" PRIx32, ninfo.oobfree[i][j]);
238			}
239		}
240
241		tprints("}}, eccpos={");
242		for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
243			if (i)
244				tprints(", ");
245			tprintf("%#" PRIx32, ninfo.eccpos[i]);
246		}
247
248		tprints("}");
249		break;
250	}
251
252	case OTPGETREGIONINFO: {
253		struct otp_info oinfo;
254
255		if (entering(tcp))
256			return 0;
257
258		tprints(", ");
259		if (umove_or_printaddr(tcp, arg, &oinfo))
260			break;
261
262		tprintf("{start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
263			oinfo.start, oinfo.length, oinfo.locked);
264		break;
265	}
266
267	case ECCGETLAYOUT: {
268		struct nand_ecclayout_user nlay;
269		unsigned int i;
270
271		if (entering(tcp))
272			return 0;
273
274		tprints(", ");
275		if (umove_or_printaddr(tcp, arg, &nlay))
276			break;
277
278		tprintf("{eccbytes=%#" PRIx32 ", eccpos={", nlay.eccbytes);
279		for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
280			if (i)
281				tprints(", ");
282			tprintf("%#" PRIx32, nlay.eccpos[i]);
283		}
284		tprintf("}, oobavail=%#" PRIx32 ", oobfree={", nlay.oobavail);
285		for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
286			if (i)
287				tprints(", ");
288			tprintf("{offset=%#" PRIx32 ", length=%#" PRIx32 "}",
289				nlay.oobfree[i].offset, nlay.oobfree[i].length);
290		}
291		tprints("}");
292		break;
293	}
294
295	case ECCGETSTATS: {
296		struct mtd_ecc_stats estat;
297
298		if (entering(tcp))
299			return 0;
300
301		tprints(", ");
302		if (umove_or_printaddr(tcp, arg, &estat))
303			break;
304
305		tprintf("{corrected=%#" PRIx32 ", failed=%#" PRIx32,
306			estat.corrected, estat.failed);
307		tprintf(", badblocks=%#" PRIx32 ", bbtblocks=%#" PRIx32 "}",
308			estat.badblocks, estat.bbtblocks);
309		break;
310	}
311
312	case OTPGETREGIONCOUNT:
313		if (entering(tcp))
314			return 0;
315
316		tprints(", ");
317		printnum_int(tcp, arg, "%u");
318		break;
319
320	case MEMGETREGIONCOUNT:
321		if (entering(tcp))
322			return 0;
323
324		tprints(", ");
325		printnum_int(tcp, arg, "%d");
326		break;
327
328	default:
329		return RVAL_DECODED;
330	}
331
332	return RVAL_DECODED | 1;
333}
334
335#include "xlat/ubi_volume_types.h"
336#include "xlat/ubi_volume_props.h"
337
338int
339ubi_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
340{
341	if (!verbose(tcp))
342		return RVAL_DECODED;
343
344	switch (code) {
345	case UBI_IOCMKVOL:
346		if (entering(tcp)) {
347			struct ubi_mkvol_req mkvol;
348
349			tprints(", ");
350			if (umove_or_printaddr(tcp, arg, &mkvol))
351				break;
352
353			tprintf("{vol_id=%" PRIi32 ", alignment=%" PRIi32
354				", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id,
355				mkvol.alignment, (int64_t)mkvol.bytes);
356			printxval(ubi_volume_types, mkvol.vol_type, "UBI_???_VOLUME");
357			tprintf(", name_len=%" PRIi16 ", name=", mkvol.name_len);
358			if (print_quoted_string(mkvol.name,
359					CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME),
360					QUOTE_0_TERMINATED) > 0) {
361				tprints("...");
362			}
363			tprints("}");
364			return 1;
365		}
366		if (!syserror(tcp)) {
367			tprints(" => ");
368			printnum_int(tcp, arg, "%d");
369		}
370		break;
371
372	case UBI_IOCRSVOL: {
373		struct ubi_rsvol_req rsvol;
374
375		tprints(", ");
376		if (umove_or_printaddr(tcp, arg, &rsvol))
377			break;
378
379		tprintf("{vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
380			rsvol.vol_id, (int64_t)rsvol.bytes);
381		break;
382	}
383
384	case UBI_IOCRNVOL: {
385		struct ubi_rnvol_req rnvol;
386		int c;
387
388		tprints(", ");
389		if (umove_or_printaddr(tcp, arg, &rnvol))
390			break;
391
392		tprintf("{count=%" PRIi32 ", ents=[", rnvol.count);
393		for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) {
394			if (c)
395				tprints(", ");
396			tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16
397				", name=", rnvol.ents[c].vol_id,
398				rnvol.ents[c].name_len);
399			if (print_quoted_string(rnvol.ents[c].name,
400					CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME),
401					QUOTE_0_TERMINATED) > 0) {
402				tprints("...");
403			}
404			tprints("}");
405		}
406		tprints("]}");
407		break;
408	}
409
410	case UBI_IOCEBCH: {
411		struct ubi_leb_change_req leb;
412
413		tprints(", ");
414		if (umove_or_printaddr(tcp, arg, &leb))
415			break;
416
417		tprintf("{lnum=%d, bytes=%d}", leb.lnum, leb.bytes);
418		break;
419	}
420
421	case UBI_IOCATT:
422		if (entering(tcp)) {
423			struct ubi_attach_req attach;
424
425			tprints(", ");
426			if (umove_or_printaddr(tcp, arg, &attach))
427				break;
428
429			tprintf("{ubi_num=%" PRIi32 ", mtd_num=%" PRIi32
430				", vid_hdr_offset=%" PRIi32
431				", max_beb_per1024=%" PRIi16 "}",
432				attach.ubi_num, attach.mtd_num,
433				attach.vid_hdr_offset, attach.max_beb_per1024);
434			return 1;
435		}
436		if (!syserror(tcp)) {
437			tprints(" => ");
438			printnum_int(tcp, arg, "%d");
439		}
440		break;
441
442	case UBI_IOCEBMAP: {
443		struct ubi_map_req map;
444
445		tprints(", ");
446		if (umove_or_printaddr(tcp, arg, &map))
447			break;
448
449		tprintf("{lnum=%" PRIi32 ", dtype=%" PRIi8 "}",
450			map.lnum, map.dtype);
451		break;
452	}
453
454	case UBI_IOCSETVOLPROP: {
455		struct ubi_set_vol_prop_req prop;
456
457		tprints(", ");
458		if (umove_or_printaddr(tcp, arg, &prop))
459			break;
460
461		tprints("{property=");
462		printxval(ubi_volume_props, prop.property, "UBI_VOL_PROP_???");
463		tprintf(", value=%#" PRIx64 "}", (uint64_t)prop.value);
464		break;
465	}
466
467
468	case UBI_IOCVOLUP:
469		tprints(", ");
470		printnum_int64(tcp, arg, "%" PRIi64);
471		break;
472
473	case UBI_IOCDET:
474	case UBI_IOCEBER:
475	case UBI_IOCEBISMAP:
476	case UBI_IOCEBUNMAP:
477	case UBI_IOCRMVOL:
478		tprints(", ");
479		printnum_int(tcp, arg, "%d");
480		break;
481
482#ifdef UBI_IOCVOLCRBLK
483	case UBI_IOCVOLCRBLK:
484#endif
485#ifdef UBI_IOCVOLRMBLK
486	case UBI_IOCVOLRMBLK:
487#endif
488		/* no arguments */
489		break;
490
491	default:
492		return RVAL_DECODED;
493	}
494
495	return RVAL_DECODED | 1;
496}
497