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 DEF_MPERS_TYPE(struct_mtd_oob_buf) 30 31#include <linux/ioctl.h> 32 33/* The mtd api changes quickly, so we have to keep a local copy */ 34#include <linux/version.h> 35#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) 36# include "mtd-abi.h" 37#else 38# include <mtd/mtd-abi.h> 39#endif 40 41typedef struct mtd_oob_buf struct_mtd_oob_buf; 42 43#include MPERS_DEFS 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 52static void 53decode_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 64static void 65decode_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 77static void 78decode_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 91static void 92decode_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 105static void 106decode_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 118static void 119decode_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 132static void 133decode_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 151static void 152decode_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 170static void 171decode_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 206static void 207decode_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 232static void 233decode_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 245MPERS_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_DECODED | 1; 363} 364