1 /* 2 * Copyright (c) 2012 Mike Frysinger <vapier (at) gentoo.org> 3 * Copyright (c) 2012-2017 The strace developers. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "defs.h" 29 30 #ifdef HAVE_STRUCT_MTD_WRITE_REQ 31 32 # include DEF_MPERS_TYPE(struct_mtd_oob_buf) 33 34 # include <linux/ioctl.h> 35 # include <mtd/mtd-abi.h> 36 37 typedef struct mtd_oob_buf struct_mtd_oob_buf; 38 39 #endif /* HAVE_STRUCT_MTD_WRITE_REQ */ 40 41 #include MPERS_DEFS 42 43 #ifdef HAVE_STRUCT_MTD_WRITE_REQ 44 45 # include "xlat/mtd_mode_options.h" 46 # include "xlat/mtd_file_mode_options.h" 47 # include "xlat/mtd_type_options.h" 48 # include "xlat/mtd_flags_options.h" 49 # include "xlat/mtd_otp_options.h" 50 # include "xlat/mtd_nandecc_options.h" 51 52 static void 53 decode_erase_info_user(struct tcb *const tcp, const kernel_ulong_t addr) 54 { 55 struct erase_info_user einfo; 56 57 tprints(", "); 58 if (umove_or_printaddr(tcp, addr, &einfo)) 59 return; 60 61 tprintf("{start=%#x, length=%#x}", einfo.start, einfo.length); 62 } 63 64 static void 65 decode_erase_info_user64(struct tcb *const tcp, const kernel_ulong_t addr) 66 { 67 struct erase_info_user64 einfo64; 68 69 tprints(", "); 70 if (umove_or_printaddr(tcp, addr, &einfo64)) 71 return; 72 73 tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}", 74 (uint64_t) einfo64.start, (uint64_t) einfo64.length); 75 } 76 77 static void 78 decode_mtd_oob_buf(struct tcb *const tcp, const kernel_ulong_t addr) 79 { 80 struct_mtd_oob_buf mbuf; 81 82 tprints(", "); 83 if (umove_or_printaddr(tcp, addr, &mbuf)) 84 return; 85 86 tprintf("{start=%#x, length=%#x, ptr=", mbuf.start, mbuf.length); 87 printaddr(ptr_to_kulong(mbuf.ptr)); 88 tprints("}"); 89 } 90 91 static void 92 decode_mtd_oob_buf64(struct tcb *const tcp, const kernel_ulong_t addr) 93 { 94 struct mtd_oob_buf64 mbuf64; 95 96 tprints(", "); 97 if (umove_or_printaddr(tcp, addr, &mbuf64)) 98 return; 99 100 tprintf("{start=%#" PRIx64 ", length=%#x, usr_ptr=%#" PRIx64 "}", 101 (uint64_t) mbuf64.start, mbuf64.length, 102 (uint64_t) mbuf64.usr_ptr); 103 } 104 105 static void 106 decode_otp_info(struct tcb *const tcp, const kernel_ulong_t addr) 107 { 108 struct otp_info oinfo; 109 110 tprints(", "); 111 if (umove_or_printaddr(tcp, addr, &oinfo)) 112 return; 113 114 tprintf("{start=%#x, length=%#x, locked=%u}", 115 oinfo.start, oinfo.length, oinfo.locked); 116 } 117 118 static void 119 decode_otp_select(struct tcb *const tcp, const kernel_ulong_t addr) 120 { 121 unsigned int i; 122 123 tprints(", "); 124 if (umove_or_printaddr(tcp, addr, &i)) 125 return; 126 127 tprints("["); 128 printxval(mtd_otp_options, i, "MTD_OTP_???"); 129 tprints("]"); 130 } 131 132 static void 133 decode_mtd_write_req(struct tcb *const tcp, const kernel_ulong_t addr) 134 { 135 struct mtd_write_req mreq; 136 137 tprints(", "); 138 if (umove_or_printaddr(tcp, addr, &mreq)) 139 return; 140 141 tprintf("{start=%#" PRIx64 ", len=%#" PRIx64 142 ", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64 143 ", usr_oob=%#" PRIx64 ", mode=", 144 (uint64_t) mreq.start, (uint64_t) mreq.len, 145 (uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data, 146 (uint64_t) mreq.usr_oob); 147 printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???"); 148 tprints("}"); 149 } 150 151 static void 152 decode_mtd_info_user(struct tcb *const tcp, const kernel_ulong_t addr) 153 { 154 struct mtd_info_user minfo; 155 156 tprints(", "); 157 if (umove_or_printaddr(tcp, addr, &minfo)) 158 return; 159 160 tprints("{type="); 161 printxval(mtd_type_options, minfo.type, "MTD_???"); 162 tprints(", flags="); 163 printflags(mtd_flags_options, minfo.flags, "MTD_???"); 164 tprintf(", size=%#x, erasesize=%#x, writesize=%#x, oobsize=%#x" 165 ", padding=%#" PRIx64 "}", 166 minfo.size, minfo.erasesize, minfo.writesize, minfo.oobsize, 167 (uint64_t) minfo.padding); 168 } 169 170 static void 171 decode_nand_oobinfo(struct tcb *const tcp, const kernel_ulong_t addr) 172 { 173 struct nand_oobinfo ninfo; 174 unsigned int i, j; 175 176 tprints(", "); 177 if (umove_or_printaddr(tcp, addr, &ninfo)) 178 return; 179 180 tprints("{useecc="); 181 printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???"); 182 tprintf(", eccbytes=%#x", ninfo.eccbytes); 183 184 tprints(", oobfree={"); 185 for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) { 186 if (i) 187 tprints("}, "); 188 tprints("{"); 189 for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) { 190 if (j) 191 tprints(", "); 192 tprintf("%#x", ninfo.oobfree[i][j]); 193 } 194 } 195 196 tprints("}}, eccpos={"); 197 for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) { 198 if (i) 199 tprints(", "); 200 tprintf("%#x", ninfo.eccpos[i]); 201 } 202 203 tprints("}"); 204 } 205 206 static void 207 decode_nand_ecclayout_user(struct tcb *const tcp, const kernel_ulong_t addr) 208 { 209 struct nand_ecclayout_user nlay; 210 unsigned int i; 211 212 tprints(", "); 213 if (umove_or_printaddr(tcp, addr, &nlay)) 214 return; 215 216 tprintf("{eccbytes=%#x, eccpos={", nlay.eccbytes); 217 for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) { 218 if (i) 219 tprints(", "); 220 tprintf("%#x", nlay.eccpos[i]); 221 } 222 tprintf("}, oobavail=%#x, oobfree={", nlay.oobavail); 223 for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) { 224 if (i) 225 tprints(", "); 226 tprintf("{offset=%#x, length=%#x}", 227 nlay.oobfree[i].offset, nlay.oobfree[i].length); 228 } 229 tprints("}"); 230 } 231 232 static void 233 decode_mtd_ecc_stats(struct tcb *const tcp, const kernel_ulong_t addr) 234 { 235 struct mtd_ecc_stats es; 236 237 tprints(", "); 238 if (umove_or_printaddr(tcp, addr, &es)) 239 return; 240 241 tprintf("{corrected=%#x, failed=%#x, badblocks=%#x, bbtblocks=%#x}", 242 es.corrected, es.failed, es.badblocks, es.bbtblocks); 243 } 244 245 MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp, 246 const unsigned int code, const kernel_ulong_t arg) 247 { 248 switch (code) { 249 case MEMERASE: 250 case MEMLOCK: 251 case MEMUNLOCK: 252 case MEMISLOCKED: 253 decode_erase_info_user(tcp, arg); 254 break; 255 256 case MEMERASE64: 257 decode_erase_info_user64(tcp, arg); 258 break; 259 260 case MEMWRITEOOB: 261 case MEMREADOOB: 262 decode_mtd_oob_buf(tcp, arg); 263 break; 264 265 case MEMWRITEOOB64: 266 case MEMREADOOB64: 267 decode_mtd_oob_buf64(tcp, arg); 268 break; 269 270 case MEMWRITE: 271 decode_mtd_write_req(tcp, arg); 272 break; 273 274 case OTPGETREGIONINFO: 275 if (entering(tcp)) 276 return 0; 277 /* fall through */ 278 case OTPLOCK: 279 decode_otp_info(tcp, arg); 280 break; 281 282 case OTPSELECT: 283 decode_otp_select(tcp, arg); 284 break; 285 286 case MTDFILEMODE: 287 tprints(", "); 288 printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???"); 289 break; 290 291 case MEMGETBADBLOCK: 292 case MEMSETBADBLOCK: 293 tprints(", "); 294 printnum_int64(tcp, arg, "%" PRIu64); 295 break; 296 297 case MEMGETINFO: 298 if (entering(tcp)) 299 return 0; 300 decode_mtd_info_user(tcp, arg); 301 break; 302 303 case MEMGETOOBSEL: 304 if (entering(tcp)) 305 return 0; 306 decode_nand_oobinfo(tcp, arg); 307 break; 308 309 case ECCGETLAYOUT: 310 if (entering(tcp)) 311 return 0; 312 decode_nand_ecclayout_user(tcp, arg); 313 break; 314 315 case ECCGETSTATS: 316 if (entering(tcp)) 317 return 0; 318 decode_mtd_ecc_stats(tcp, arg); 319 break; 320 321 case OTPGETREGIONCOUNT: 322 if (entering(tcp)) 323 return 0; 324 tprints(", "); 325 printnum_int(tcp, arg, "%u"); 326 break; 327 328 case MEMGETREGIONCOUNT: 329 if (entering(tcp)) 330 return 0; 331 tprints(", "); 332 printnum_int(tcp, arg, "%d"); 333 break; 334 335 case MEMGETREGIONINFO: 336 if (entering(tcp)) { 337 struct region_info_user rinfo; 338 339 tprints(", "); 340 if (umove_or_printaddr(tcp, arg, &rinfo)) 341 break; 342 tprintf("{regionindex=%#x", rinfo.regionindex); 343 return 0; 344 } else { 345 struct region_info_user rinfo; 346 347 if (!syserror(tcp) && !umove(tcp, arg, &rinfo)) 348 tprintf(", offset=%#x" 349 ", erasesize=%#x" 350 ", numblocks=%#x}", 351 rinfo.offset, 352 rinfo.erasesize, 353 rinfo.numblocks); 354 tprints("}"); 355 break; 356 } 357 358 default: 359 return RVAL_DECODED; 360 } 361 362 return RVAL_IOCTL_DECODED; 363 } 364 365 #endif /* HAVE_STRUCT_MTD_WRITE_REQ */ 366