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 
51 int
mtd_ioctl(struct tcb * tcp,const unsigned int code,const long arg)52 mtd_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 
338 int
ubi_ioctl(struct tcb * tcp,const unsigned int code,const long arg)339 ubi_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