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 #include DEF_MPERS_TYPE(struct_mtd_oob_buf) 31 32 #include <linux/ioctl.h> 33 34 /* The mtd api changes quickly, so we have to keep a local copy */ 35 #include <linux/version.h> 36 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) 37 # include "mtd-abi.h" 38 #else 39 # include <mtd/mtd-abi.h> 40 #endif 41 42 typedef struct mtd_oob_buf struct_mtd_oob_buf; 43 44 #include MPERS_DEFS 45 46 #include "xlat/mtd_mode_options.h" 47 #include "xlat/mtd_file_mode_options.h" 48 #include "xlat/mtd_type_options.h" 49 #include "xlat/mtd_flags_options.h" 50 #include "xlat/mtd_otp_options.h" 51 #include "xlat/mtd_nandecc_options.h" 52 53 static void 54 decode_erase_info_user(struct tcb *const tcp, const kernel_ulong_t addr) 55 { 56 struct erase_info_user einfo; 57 58 tprints(", "); 59 if (umove_or_printaddr(tcp, addr, &einfo)) 60 return; 61 62 tprintf("{start=%#x, length=%#x}", einfo.start, einfo.length); 63 } 64 65 static void 66 decode_erase_info_user64(struct tcb *const tcp, const kernel_ulong_t addr) 67 { 68 struct erase_info_user64 einfo64; 69 70 tprints(", "); 71 if (umove_or_printaddr(tcp, addr, &einfo64)) 72 return; 73 74 tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}", 75 (uint64_t) einfo64.start, (uint64_t) einfo64.length); 76 } 77 78 static void 79 decode_mtd_oob_buf(struct tcb *const tcp, const kernel_ulong_t addr) 80 { 81 struct_mtd_oob_buf mbuf; 82 83 tprints(", "); 84 if (umove_or_printaddr(tcp, addr, &mbuf)) 85 return; 86 87 tprintf("{start=%#x, length=%#x, ptr=", mbuf.start, mbuf.length); 88 printaddr(ptr_to_kulong(mbuf.ptr)); 89 tprints("}"); 90 } 91 92 static void 93 decode_mtd_oob_buf64(struct tcb *const tcp, const kernel_ulong_t addr) 94 { 95 struct mtd_oob_buf64 mbuf64; 96 97 tprints(", "); 98 if (umove_or_printaddr(tcp, addr, &mbuf64)) 99 return; 100 101 tprintf("{start=%#" PRIx64 ", length=%#x, usr_ptr=%#" PRIx64 "}", 102 (uint64_t) mbuf64.start, mbuf64.length, 103 (uint64_t) mbuf64.usr_ptr); 104 } 105 106 static void 107 decode_otp_info(struct tcb *const tcp, const kernel_ulong_t addr) 108 { 109 struct otp_info oinfo; 110 111 tprints(", "); 112 if (umove_or_printaddr(tcp, addr, &oinfo)) 113 return; 114 115 tprintf("{start=%#x, length=%#x, locked=%u}", 116 oinfo.start, oinfo.length, oinfo.locked); 117 } 118 119 static void 120 decode_otp_select(struct tcb *const tcp, const kernel_ulong_t addr) 121 { 122 unsigned int i; 123 124 tprints(", "); 125 if (umove_or_printaddr(tcp, addr, &i)) 126 return; 127 128 tprints("["); 129 printxval(mtd_otp_options, i, "MTD_OTP_???"); 130 tprints("]"); 131 } 132 133 static void 134 decode_mtd_write_req(struct tcb *const tcp, const kernel_ulong_t addr) 135 { 136 struct mtd_write_req mreq; 137 138 tprints(", "); 139 if (umove_or_printaddr(tcp, addr, &mreq)) 140 return; 141 142 tprintf("{start=%#" PRIx64 ", len=%#" PRIx64 143 ", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64 144 ", usr_oob=%#" PRIx64 ", mode=", 145 (uint64_t) mreq.start, (uint64_t) mreq.len, 146 (uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data, 147 (uint64_t) mreq.usr_oob); 148 printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???"); 149 tprints("}"); 150 } 151 152 static void 153 decode_mtd_info_user(struct tcb *const tcp, const kernel_ulong_t addr) 154 { 155 struct mtd_info_user minfo; 156 157 tprints(", "); 158 if (umove_or_printaddr(tcp, addr, &minfo)) 159 return; 160 161 tprints("{type="); 162 printxval(mtd_type_options, minfo.type, "MTD_???"); 163 tprints(", flags="); 164 printflags(mtd_flags_options, minfo.flags, "MTD_???"); 165 tprintf(", size=%#x, erasesize=%#x, writesize=%#x, oobsize=%#x" 166 ", padding=%#" PRIx64 "}", 167 minfo.size, minfo.erasesize, minfo.writesize, minfo.oobsize, 168 (uint64_t) minfo.padding); 169 } 170 171 static void 172 decode_nand_oobinfo(struct tcb *const tcp, const kernel_ulong_t addr) 173 { 174 struct nand_oobinfo ninfo; 175 unsigned int i, j; 176 177 tprints(", "); 178 if (umove_or_printaddr(tcp, addr, &ninfo)) 179 return; 180 181 tprints("{useecc="); 182 printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???"); 183 tprintf(", eccbytes=%#x", ninfo.eccbytes); 184 185 tprints(", oobfree={"); 186 for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) { 187 if (i) 188 tprints("}, "); 189 tprints("{"); 190 for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) { 191 if (j) 192 tprints(", "); 193 tprintf("%#x", ninfo.oobfree[i][j]); 194 } 195 } 196 197 tprints("}}, eccpos={"); 198 for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) { 199 if (i) 200 tprints(", "); 201 tprintf("%#x", ninfo.eccpos[i]); 202 } 203 204 tprints("}"); 205 } 206 207 static void 208 decode_nand_ecclayout_user(struct tcb *const tcp, const kernel_ulong_t addr) 209 { 210 struct nand_ecclayout_user nlay; 211 unsigned int i; 212 213 tprints(", "); 214 if (umove_or_printaddr(tcp, addr, &nlay)) 215 return; 216 217 tprintf("{eccbytes=%#x, eccpos={", nlay.eccbytes); 218 for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) { 219 if (i) 220 tprints(", "); 221 tprintf("%#x", nlay.eccpos[i]); 222 } 223 tprintf("}, oobavail=%#x, oobfree={", nlay.oobavail); 224 for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) { 225 if (i) 226 tprints(", "); 227 tprintf("{offset=%#x, length=%#x}", 228 nlay.oobfree[i].offset, nlay.oobfree[i].length); 229 } 230 tprints("}"); 231 } 232 233 static void 234 decode_mtd_ecc_stats(struct tcb *const tcp, const kernel_ulong_t addr) 235 { 236 struct mtd_ecc_stats es; 237 238 tprints(", "); 239 if (umove_or_printaddr(tcp, addr, &es)) 240 return; 241 242 tprintf("{corrected=%#x, failed=%#x, badblocks=%#x, bbtblocks=%#x}", 243 es.corrected, es.failed, es.badblocks, es.bbtblocks); 244 } 245 246 MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp, 247 const unsigned int code, const kernel_ulong_t arg) 248 { 249 switch (code) { 250 case MEMERASE: 251 case MEMLOCK: 252 case MEMUNLOCK: 253 case MEMISLOCKED: 254 decode_erase_info_user(tcp, arg); 255 break; 256 257 case MEMERASE64: 258 decode_erase_info_user64(tcp, arg); 259 break; 260 261 case MEMWRITEOOB: 262 case MEMREADOOB: 263 decode_mtd_oob_buf(tcp, arg); 264 break; 265 266 case MEMWRITEOOB64: 267 case MEMREADOOB64: 268 decode_mtd_oob_buf64(tcp, arg); 269 break; 270 271 case MEMWRITE: 272 decode_mtd_write_req(tcp, arg); 273 break; 274 275 case OTPGETREGIONINFO: 276 if (entering(tcp)) 277 return 0; 278 /* fall through */ 279 case OTPLOCK: 280 decode_otp_info(tcp, arg); 281 break; 282 283 case OTPSELECT: 284 decode_otp_select(tcp, arg); 285 break; 286 287 case MTDFILEMODE: 288 tprints(", "); 289 printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???"); 290 break; 291 292 case MEMGETBADBLOCK: 293 case MEMSETBADBLOCK: 294 tprints(", "); 295 printnum_int64(tcp, arg, "%" PRIu64); 296 break; 297 298 case MEMGETINFO: 299 if (entering(tcp)) 300 return 0; 301 decode_mtd_info_user(tcp, arg); 302 break; 303 304 case MEMGETOOBSEL: 305 if (entering(tcp)) 306 return 0; 307 decode_nand_oobinfo(tcp, arg); 308 break; 309 310 case ECCGETLAYOUT: 311 if (entering(tcp)) 312 return 0; 313 decode_nand_ecclayout_user(tcp, arg); 314 break; 315 316 case ECCGETSTATS: 317 if (entering(tcp)) 318 return 0; 319 decode_mtd_ecc_stats(tcp, arg); 320 break; 321 322 case OTPGETREGIONCOUNT: 323 if (entering(tcp)) 324 return 0; 325 tprints(", "); 326 printnum_int(tcp, arg, "%u"); 327 break; 328 329 case MEMGETREGIONCOUNT: 330 if (entering(tcp)) 331 return 0; 332 tprints(", "); 333 printnum_int(tcp, arg, "%d"); 334 break; 335 336 case MEMGETREGIONINFO: 337 if (entering(tcp)) { 338 struct region_info_user rinfo; 339 340 tprints(", "); 341 if (umove_or_printaddr(tcp, arg, &rinfo)) 342 break; 343 tprintf("{regionindex=%#x", rinfo.regionindex); 344 return 0; 345 } else { 346 struct region_info_user rinfo; 347 348 if (!syserror(tcp) && !umove(tcp, arg, &rinfo)) 349 tprintf(", offset=%#x" 350 ", erasesize=%#x" 351 ", numblocks=%#x}", 352 rinfo.offset, 353 rinfo.erasesize, 354 rinfo.numblocks); 355 tprints("}"); 356 break; 357 } 358 359 default: 360 return RVAL_DECODED; 361 } 362 363 return RVAL_DECODED | 1; 364 } 365