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