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