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 <sys/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_type_options.h"
46 #include "xlat/mtd_flags_options.h"
47 #include "xlat/mtd_otp_options.h"
48 #include "xlat/mtd_nandecc_options.h"
49 
50 int
mtd_ioctl(struct tcb * tcp,const unsigned int code,long arg)51 mtd_ioctl(struct tcb *tcp, const unsigned int code, long arg)
52 {
53 	struct mtd_info_user minfo;
54 	struct erase_info_user einfo;
55 	struct erase_info_user64 einfo64;
56 	struct mtd_oob_buf mbuf;
57 	struct mtd_oob_buf64 mbuf64;
58 	struct region_info_user rinfo;
59 	struct otp_info oinfo;
60 	struct mtd_ecc_stats estat;
61 	struct mtd_write_req mreq;
62 	struct nand_oobinfo ninfo;
63 	struct nand_ecclayout_user nlay;
64 	unsigned int i, j;
65 
66 	if (entering(tcp))
67 		return 0;
68 
69 	switch (code) {
70 
71 	case MEMGETINFO:
72 		if (!verbose(tcp) || umove(tcp, arg, &minfo) < 0)
73 			return 0;
74 
75 		tprints(", {type=");
76 		printxval(mtd_type_options, minfo.type, "MTD_???");
77 		tprints(", flags=");
78 		printflags(mtd_flags_options, minfo.flags, "MTD_???");
79 		tprintf(", size=%#" PRIx32 ", erasesize=%#" PRIx32,
80 			minfo.size, minfo.erasesize);
81 		tprintf(", writesize=%#" PRIx32 ", oobsize=%#" PRIx32,
82 			minfo.writesize, minfo.oobsize);
83 		tprintf(", padding=%#" PRIx64 "}",
84 			(uint64_t) minfo.padding);
85 		return 1;
86 
87 	case MEMERASE:
88 	case MEMLOCK:
89 	case MEMUNLOCK:
90 	case MEMISLOCKED:
91 		if (!verbose(tcp) || umove(tcp, arg, &einfo) < 0)
92 			return 0;
93 
94 		tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 "}",
95 			einfo.start, einfo.length);
96 		return 1;
97 
98 	case MEMERASE64:
99 		if (!verbose(tcp) || umove(tcp, arg, &einfo64) < 0)
100 			return 0;
101 
102 		tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 "}",
103 			(uint64_t) einfo64.start, (uint64_t) einfo64.length);
104 		return 1;
105 
106 	case MEMWRITEOOB:
107 	case MEMREADOOB:
108 		if (!verbose(tcp) || umove(tcp, arg, &mbuf) < 0)
109 			return 0;
110 
111 		tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", ptr=...}",
112 			mbuf.start, mbuf.length);
113 		return 1;
114 
115 	case MEMWRITEOOB64:
116 	case MEMREADOOB64:
117 		if (!verbose(tcp) || umove(tcp, arg, &mbuf64) < 0)
118 			return 0;
119 
120 		tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 ", ptr=...}",
121 			(uint64_t) mbuf64.start, (uint64_t) mbuf64.length);
122 		return 1;
123 
124 	case MEMGETREGIONINFO:
125 		if (!verbose(tcp) || umove(tcp, arg, &rinfo) < 0)
126 			return 0;
127 
128 		tprintf(", {offset=%#" PRIx32 ", erasesize=%#" PRIx32,
129 			rinfo.offset, rinfo.erasesize);
130 		tprintf(", numblocks=%#" PRIx32 ", regionindex=%#" PRIx32 "}",
131 			rinfo.numblocks, rinfo.regionindex);
132 		return 1;
133 
134 	case MEMGETOOBSEL:
135 		if (!verbose(tcp) || umove(tcp, arg, &ninfo) < 0)
136 			return 0;
137 
138 		tprints(", {useecc=");
139 		printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
140 		tprintf(", eccbytes=%#" PRIx32, ninfo.eccbytes);
141 
142 		tprints(", oobfree={");
143 		for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
144 			if (i)
145 				tprints("}, ");
146 			tprints("{");
147 			for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
148 				if (j)
149 					tprints(", ");
150 				tprintf("%#" PRIx32, ninfo.oobfree[i][j]);
151 			}
152 		}
153 
154 		tprints("}}, eccpos={");
155 		for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
156 			if (i)
157 				tprints(", ");
158 			tprintf("%#" PRIx32, ninfo.eccpos[i]);
159 		}
160 
161 		tprints("}");
162 		return 1;
163 
164 	case OTPGETREGIONINFO:
165 	case OTPLOCK:
166 		if (!verbose(tcp) || umove(tcp, arg, &oinfo) < 0)
167 			return 0;
168 
169 		tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
170 			oinfo.start, oinfo.length, oinfo.locked);
171 		return 1;
172 
173 	case ECCGETLAYOUT:
174 		if (!verbose(tcp) || umove(tcp, arg, &nlay) < 0)
175 			return 0;
176 
177 		tprintf(", {eccbytes=%#" PRIx32 ", eccpos={", nlay.eccbytes);
178 		for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
179 			if (i)
180 				tprints(", ");
181 			tprintf("%#" PRIx32, nlay.eccpos[i]);
182 		}
183 		tprintf("}, oobavail=%#" PRIx32 ", oobfree={", nlay.oobavail);
184 		for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
185 			if (i)
186 				tprints(", ");
187 			tprintf("{offset=%#" PRIx32 ", length=%#" PRIx32 "}",
188 				nlay.oobfree[i].offset, nlay.oobfree[i].length);
189 		}
190 		tprints("}");
191 		return 1;
192 
193 	case ECCGETSTATS:
194 		if (!verbose(tcp) || umove(tcp, arg, &estat) < 0)
195 			return 0;
196 
197 		tprintf(", {corrected=%#" PRIx32 ", failed=%#" PRIx32,
198 			estat.corrected, estat.failed);
199 		tprintf(", badblocks=%#" PRIx32 ", bbtblocks=%#" PRIx32 "}",
200 			estat.badblocks, estat.bbtblocks);
201 		return 1;
202 
203 	case MEMWRITE:
204 		if (!verbose(tcp) || umove(tcp, arg, &mreq) < 0)
205 			return 0;
206 
207 		tprintf(", {start=%#" PRIx64 ", len=%#" PRIx64,
208 			(uint64_t) mreq.start, (uint64_t) mreq.len);
209 		tprintf(", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64,
210 			(uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data);
211 		tprintf(", usr_oob=%#" PRIx64 ", mode=",
212 			(uint64_t) mreq.usr_oob);
213 		printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
214 		tprints(", padding=...}");
215 		return 1;
216 
217 	case OTPSELECT:
218 		if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
219 			return 0;
220 
221 		tprints(", [");
222 		printxval(mtd_otp_options, i, "MTD_OTP_???");
223 		tprints("]");
224 		return 1;
225 
226 	case MEMGETBADBLOCK:
227 	case MEMSETBADBLOCK:
228 		if (!verbose(tcp))
229 			return 0;
230 
231 		tprints(", ");
232 		print_loff_t(tcp, arg);
233 		return 1;
234 
235 	case OTPGETREGIONCOUNT:
236 		if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
237 			return 0;
238 
239 		tprintf(", [%u]", i);
240 		return 1;
241 
242 	case MTDFILEMODE:
243 		/* XXX: process return value as enum mtd_file_modes */
244 
245 	case MEMGETREGIONCOUNT:
246 		/* These ones take simple args, so let default printer handle it */
247 
248 	default:
249 		return 0;
250 	}
251 }
252 
253 #include "xlat/ubi_volume_types.h"
254 #include "xlat/ubi_volume_props.h"
255 
256 int
ubi_ioctl(struct tcb * tcp,const unsigned int code,long arg)257 ubi_ioctl(struct tcb *tcp, const unsigned int code, long arg)
258 {
259 	struct ubi_mkvol_req mkvol;
260 	struct ubi_rsvol_req rsvol;
261 	struct ubi_rnvol_req rnvol;
262 	struct ubi_attach_req attach;
263 	struct ubi_map_req map;
264 	struct ubi_set_vol_prop_req prop;
265 
266 	if (entering(tcp))
267 		return 0;
268 
269 	switch (code) {
270 	case UBI_IOCMKVOL:
271 		if (!verbose(tcp) || umove(tcp, arg, &mkvol) < 0)
272 			return 0;
273 
274 		tprintf(", {vol_id=%" PRIi32 ", alignment=%" PRIi32
275 			", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id,
276 			mkvol.alignment, (int64_t)mkvol.bytes);
277 		printxval(ubi_volume_types, mkvol.vol_type, "UBI_???_VOLUME");
278 		tprintf(", name_len=%" PRIi16 ", name=", mkvol.name_len);
279 		if (print_quoted_string(mkvol.name,
280 				CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME),
281 				QUOTE_0_TERMINATED) > 0) {
282 			tprints("...");
283 		}
284 		tprints("}");
285 		return 1;
286 
287 	case UBI_IOCRSVOL:
288 		if (!verbose(tcp) || umove(tcp, arg, &rsvol) < 0)
289 			return 0;
290 
291 		tprintf(", {vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
292 			rsvol.vol_id, (int64_t)rsvol.bytes);
293 		return 1;
294 
295 	case UBI_IOCRNVOL: {
296 		__s32 c;
297 
298 		if (!verbose(tcp) || umove(tcp, arg, &rnvol) < 0)
299 			return 0;
300 
301 		tprintf(", {count=%" PRIi32 ", ents=[", rnvol.count);
302 		for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) {
303 			if (c)
304 				tprints(", ");
305 			tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16
306 				", name=", rnvol.ents[c].vol_id,
307 				rnvol.ents[c].name_len);
308 			if (print_quoted_string(rnvol.ents[c].name,
309 					CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME),
310 					QUOTE_0_TERMINATED) > 0) {
311 				tprints("...");
312 			}
313 			tprints("}");
314 		}
315 		tprints("]}");
316 		return 1;
317 	}
318 
319 	case UBI_IOCVOLUP: {
320 		__s64 bytes;
321 
322 		if (!verbose(tcp) || umove(tcp, arg, &bytes) < 0)
323 			return 0;
324 
325 		tprintf(", %" PRIi64, (int64_t)bytes);
326 		return 1;
327 	}
328 
329 	case UBI_IOCATT:
330 		if (!verbose(tcp) || umove(tcp, arg, &attach) < 0)
331 			return 0;
332 
333 		tprintf(", {ubi_num=%" PRIi32 ", mtd_num=%" PRIi32
334 			", vid_hdr_offset=%" PRIi32
335 			", max_beb_per1024=%" PRIi16 "}",
336 			attach.ubi_num, attach.mtd_num,
337 			attach.vid_hdr_offset, attach.max_beb_per1024);
338 		return 1;
339 
340 	case UBI_IOCEBMAP:
341 		if (!verbose(tcp) || umove(tcp, arg, &map) < 0)
342 			return 0;
343 
344 		tprintf(", {lnum=%" PRIi32 ", dtype=%" PRIi8 "}",
345 			map.lnum, map.dtype);
346 		return 1;
347 
348 	case UBI_IOCSETVOLPROP:
349 		if (!verbose(tcp) || umove(tcp, arg, &prop) < 0)
350 			return 0;
351 
352 		tprints(", {property=");
353 		printxval(ubi_volume_props, prop.property, "UBI_VOL_PROP_???");
354 		tprintf(", value=%#" PRIx64 "}", (uint64_t)prop.value);
355 		return 1;
356 
357 	case UBI_IOCRMVOL:
358 	case UBI_IOCDET:
359 	case UBI_IOCEBER:
360 	case UBI_IOCEBCH:
361 	case UBI_IOCEBUNMAP:
362 	case UBI_IOCEBISMAP:
363 		/* These ones take simple args, so let default printer handle it */
364 
365 	default:
366 		return 0;
367 	}
368 }
369