mmc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /*
  2. * This program is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU General Public
  4. * License v2 as published by the Free Software Foundation.
  5. *
  6. * This program is distributed in the hope that it will be useful,
  7. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  9. * General Public License for more details.
  10. *
  11. * You should have received a copy of the GNU General Public
  12. * License along with this program; if not, write to the
  13. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. * Boston, MA 021110-1307, USA.
  15. *
  16. * Modified to add field firmware update support,
  17. * those modifications are Copyright (c) 2016 SanDisk Corp.
  18. *
  19. * (This code is based on btrfs-progs/btrfs.c.)
  20. */
  21. #define _GNU_SOURCE
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "mmc_cmds.h"
  26. #define MMC_VERSION "0.1"
  27. #define BASIC_HELP 0
  28. #define ADVANCED_HELP 1
  29. typedef int (*CommandFunction)(int argc, char **argv);
  30. struct Command {
  31. CommandFunction func; /* function which implements the command */
  32. int nargs; /* if == 999, any number of arguments
  33. if >= 0, number of arguments,
  34. if < 0, _minimum_ number of arguments */
  35. char *verb; /* verb */
  36. char *help; /* help lines; from the 2nd line onward they
  37. are automatically indented */
  38. char *adv_help; /* advanced help message; from the 2nd line
  39. onward they are automatically indented */
  40. /* the following fields are run-time filled by the program */
  41. char **cmds; /* array of subcommands */
  42. int ncmds; /* number of subcommand */
  43. };
  44. static struct Command commands[] = {
  45. /*
  46. * avoid short commands different for the case only
  47. */
  48. { do_read_extcsd, -1,
  49. "extcsd read", "<device>\n"
  50. "Print extcsd data from <device>.",
  51. NULL
  52. },
  53. { do_writeprotect_boot_get, -1,
  54. "writeprotect boot get", "<device>\n"
  55. "Print the boot partitions write protect status for <device>.",
  56. NULL
  57. },
  58. { do_writeprotect_boot_set, -1,
  59. "writeprotect boot set", "<device>\n"
  60. "Set the boot partitions write protect status for <device>.\nThis sets the eMMC boot partitions to be write-protected until\nthe next boot.",
  61. NULL
  62. },
  63. { do_writeprotect_user_set, -4,
  64. "writeprotect user set", "<type>" "<start block>" "<blocks>" "<device>\n"
  65. #ifdef DANGEROUS_COMMANDS_ENABLED
  66. "Set the write protect configuration for the specified region\nof the user area for <device>.\n<type> must be \"none|temp|pwron|perm\".\n \"none\" - Clear temporary write protection.\n \"temp\" - Set temporary write protection.\n \"pwron\" - Set write protection until the next poweron.\n \"perm\" - Set permanent write protection.\n<start block> specifies the first block of the protected area.\n<blocks> specifies the size of the protected area in blocks.\nNOTE! The area must start and end on Write Protect Group\nboundries, Use the \"writeprotect user get\" command to get the\nWrite Protect Group size.\nNOTE! \"perm\" is a one-time programmable (unreversible) change.",
  67. #else
  68. "Set the write protect configuration for the specified region\nof the user area for <device>.\n<type> must be \"none|temp|pwron\".\n \"none\" - Clear temporary write protection.\n \"temp\" - Set temporary write protection.\n \"pwron\" - Set write protection until the next poweron.\n<start block> specifies the first block of the protected area.\n<blocks> specifies the size of the protected area in blocks.\nNOTE! The area must start and end on Write Protect Group\nboundries, Use the \"writeprotect user get\" command to get the\nWrite Protect Group size.",
  69. #endif /* DANGEROUS_COMMANDS_ENABLED */
  70. NULL
  71. },
  72. { do_writeprotect_user_get, -1,
  73. "writeprotect user get", "<device>\n"
  74. "Print the user areas write protect configuration for <device>.",
  75. NULL
  76. },
  77. { do_disable_512B_emulation, -1,
  78. "disable 512B emulation", "<device>\n"
  79. "Set the eMMC data sector size to 4KB by disabling emulation on\n<device>.",
  80. NULL
  81. },
  82. { do_create_gp_partition, -6,
  83. "gp create", "<-y|-n|-c> " "<length KiB> " "<partition> " "<enh_attr> " "<ext_attr> " "<device>\n"
  84. "Create general purpose partition for the <device>.\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE! This is a one-time programmable (unreversible) change.\nTo set enhanced attribute to general partition being created set\n <enh_attr> to 1 else set it to 0.\nTo set extended attribute to general partition\n set <ext_attr> to 1,2 else set it to 0",
  85. NULL
  86. },
  87. { do_enh_area_set, -4,
  88. "enh_area set", "<-y|-n|-c> " "<start KiB> " "<length KiB> " "<device>\n"
  89. "Enable the enhanced user area for the <device>.\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE! This is a one-time programmable (unreversible) change.",
  90. NULL
  91. },
  92. { do_write_reliability_set, -2,
  93. "write_reliability set", "<-y|-n|-c> " "<partition> " "<device>\n"
  94. "Enable write reliability per partition for the <device>.\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE! This is a one-time programmable (unreversible) change.",
  95. NULL
  96. },
  97. { do_status_get, -1,
  98. "status get", "<device>\n"
  99. "Print the response to STATUS_SEND (CMD13).",
  100. NULL
  101. },
  102. { do_write_boot_en, -3,
  103. "bootpart enable", "<boot_partition> " "<send_ack> " "<device>\n"
  104. "Enable the boot partition for the <device>.\nDisable the boot partition for the <device> if <boot_partition> is set to 0.\nTo receive acknowledgment of boot from the card set <send_ack>\nto 1, else set it to 0.",
  105. NULL
  106. },
  107. { do_boot_bus_conditions_set, -4,
  108. "bootbus set", "<boot_mode> " "<reset_boot_bus_conditions> " "<boot_bus_width> " "<device>\n"
  109. "Set Boot Bus Conditions.\n"
  110. "<boot_mode> must be \"single_backward|single_hs|dual\"\n"
  111. "<reset_boot_bus_conditions> must be \"x1|retain\"\n"
  112. "<boot_bus_width> must be \"x1|x4|x8\"",
  113. NULL
  114. },
  115. { do_write_bkops_en, -1,
  116. "bkops enable", "<device>\n"
  117. "Enable the eMMC BKOPS feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.",
  118. NULL
  119. },
  120. { do_hwreset_en, -1,
  121. "hwreset enable", "<device>\n"
  122. "Permanently enable the eMMC H/W Reset feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.",
  123. NULL
  124. },
  125. { do_hwreset_dis, -1,
  126. "hwreset disable", "<device>\n"
  127. "Permanently disable the eMMC H/W Reset feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.",
  128. NULL
  129. },
  130. { do_sanitize, -1,
  131. "sanitize", "<device>\n"
  132. "Send Sanitize command to the <device>.\nThis will delete the unmapped memory region of the device.",
  133. NULL
  134. },
  135. { do_rpmb_write_key, -1,
  136. "rpmb write-key", "<rpmb device> <key file>\n"
  137. "Program authentication key which is 32 bytes length and stored\n"
  138. "in the specified file. Also you can specify '-' instead of\n"
  139. "key file path to read the key from stdin.\n"
  140. "NOTE! This is a one-time programmable (unreversible) change.\n"
  141. "Example:\n"
  142. " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n"
  143. " mmc rpmb write-key /dev/mmcblk0rpmb -",
  144. NULL
  145. },
  146. { do_rpmb_read_counter, -1,
  147. "rpmb read-counter", "<rpmb device>\n"
  148. "Counter value for the <rpmb device> will be read to stdout.",
  149. NULL
  150. },
  151. { do_rpmb_read_block, -1,
  152. "rpmb read-block", "<rpmb device> <address> <blocks count> <output file> [key file]\n"
  153. "Blocks of 256 bytes will be read from <rpmb device> to output\n"
  154. "file or stdout if '-' is specified. If key is specified - read\n"
  155. "data will be verified. Instead of regular path you can specify\n"
  156. "'-' to read key from stdin.\n"
  157. "Example:\n"
  158. " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n"
  159. " mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block -\n"
  160. "or read two blocks without verification\n"
  161. " $ mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block",
  162. NULL
  163. },
  164. { do_rpmb_write_block, -1,
  165. "rpmb write-block", "<rpmb device> <address> <256 byte data file> <key file>\n"
  166. "Block of 256 bytes will be written from data file to\n"
  167. "<rpmb device>. Also you can specify '-' instead of key\n"
  168. "file path or data file to read the data from stdin.\n"
  169. "Example:\n"
  170. " $ (awk 'BEGIN {while (c++<256) printf \"a\"}' | \\\n"
  171. " echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | \\\n"
  172. " mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - -",
  173. NULL
  174. },
  175. { do_cache_en, -1,
  176. "cache enable", "<device>\n"
  177. "Enable the eMMC cache feature on <device>.\n"
  178. "NOTE! The cache is an optional feature on devices >= eMMC4.5.",
  179. NULL
  180. },
  181. { do_cache_dis, -1,
  182. "cache disable", "<device>\n"
  183. "Disable the eMMC cache feature on <device>.\n"
  184. "NOTE! The cache is an optional feature on devices >= eMMC4.5.",
  185. NULL
  186. },
  187. { do_read_csd, -1,
  188. "csd read", "<device path>\n"
  189. "Print CSD data from <device path>.\n"
  190. "The device path should specify the csd file directory.",
  191. NULL
  192. },
  193. { do_read_cid, -1,
  194. "cid read", "<device path>\n"
  195. "Print CID data from <device path>.\n"
  196. "The device path should specify the cid file directory.",
  197. NULL
  198. },
  199. { do_read_scr, -1,
  200. "scr read", "<device path>\n"
  201. "Print SCR data from <device path>.\n"
  202. "The device path should specify the scr file directory.",
  203. NULL
  204. },
  205. { do_ffu, -2,
  206. "ffu", "<image name> <device>\n"
  207. "Run Field Firmware Update with <image name> on <device>.\n",
  208. NULL
  209. },
  210. { 0, 0, 0, 0 }
  211. };
  212. static char *get_prgname(char *programname)
  213. {
  214. char *np;
  215. np = strrchr(programname,'/');
  216. if(!np)
  217. np = programname;
  218. else
  219. np++;
  220. return np;
  221. }
  222. static void print_help(char *programname, struct Command *cmd, int helptype)
  223. {
  224. char *pc;
  225. printf("\t%s %s ", programname, cmd->verb );
  226. if (helptype == ADVANCED_HELP && cmd->adv_help)
  227. for(pc = cmd->adv_help; *pc; pc++){
  228. putchar(*pc);
  229. if(*pc == '\n')
  230. printf("\t\t");
  231. }
  232. else
  233. for(pc = cmd->help; *pc; pc++){
  234. putchar(*pc);
  235. if(*pc == '\n')
  236. printf("\t\t");
  237. }
  238. putchar('\n');
  239. }
  240. static void help(char *np)
  241. {
  242. struct Command *cp;
  243. printf("Usage:\n");
  244. for( cp = commands; cp->verb; cp++ )
  245. print_help(np, cp, BASIC_HELP);
  246. printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np);
  247. printf("\n\t%s <cmd> --help\n\t\tShow detailed help for a command or subset of commands.\n",np);
  248. printf("\n%s\n", MMC_VERSION);
  249. }
  250. static int split_command(char *cmd, char ***commands)
  251. {
  252. int c, l;
  253. char *p, *s;
  254. for( *commands = 0, l = c = 0, p = s = cmd ; ; p++, l++ ){
  255. if ( *p && *p != ' ' )
  256. continue;
  257. /* c + 2 so that we have room for the null */
  258. (*commands) = realloc( (*commands), sizeof(char *)*(c + 2));
  259. (*commands)[c] = strndup(s, l);
  260. c++;
  261. l = 0;
  262. s = p+1;
  263. if( !*p ) break;
  264. }
  265. (*commands)[c] = 0;
  266. return c;
  267. }
  268. /*
  269. This function checks if the passed command is ambiguous
  270. */
  271. static int check_ambiguity(struct Command *cmd, char **argv){
  272. int i;
  273. struct Command *cp;
  274. /* check for ambiguity */
  275. for( i = 0 ; i < cmd->ncmds ; i++ ){
  276. int match;
  277. for( match = 0, cp = commands; cp->verb; cp++ ){
  278. int j, skip;
  279. char *s1, *s2;
  280. if( cp->ncmds < i )
  281. continue;
  282. for( skip = 0, j = 0 ; j < i ; j++ )
  283. if( strcmp(cmd->cmds[j], cp->cmds[j])){
  284. skip=1;
  285. break;
  286. }
  287. if(skip)
  288. continue;
  289. if( !strcmp(cmd->cmds[i], cp->cmds[i]))
  290. continue;
  291. for(s2 = cp->cmds[i], s1 = argv[i+1];
  292. *s1 == *s2 && *s1; s1++, s2++ ) ;
  293. if( !*s1 )
  294. match++;
  295. }
  296. if(match){
  297. int j;
  298. fprintf(stderr, "ERROR: in command '");
  299. for( j = 0 ; j <= i ; j++ )
  300. fprintf(stderr, "%s%s",j?" ":"", argv[j+1]);
  301. fprintf(stderr, "', '%s' is ambiguous\n",argv[j]);
  302. return -2;
  303. }
  304. }
  305. return 0;
  306. }
  307. /*
  308. * This function, compacts the program name and the command in the first
  309. * element of the '*av' array
  310. */
  311. static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){
  312. char **ret;
  313. int i;
  314. char *newname;
  315. ret = (char **)malloc(sizeof(char*)*(*ac+1));
  316. newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2);
  317. if( !ret || !newname ){
  318. free(ret);
  319. free(newname);
  320. return -1;
  321. }
  322. ret[0] = newname;
  323. for(i=0; i < *ac ; i++ )
  324. ret[i+1] = (*av)[i];
  325. strcpy(newname, prgname);
  326. strcat(newname, " ");
  327. strcat(newname, cmd->verb);
  328. (*ac)++;
  329. *av = ret;
  330. return 0;
  331. }
  332. /*
  333. This function performs the following jobs:
  334. - show the help if '--help' or 'help' or '-h' are passed
  335. - verify that a command is not ambiguous, otherwise show which
  336. part of the command is ambiguous
  337. - if after a (even partial) command there is '--help' show detailed help
  338. for all the matching commands
  339. - if the command doesn't match show an error
  340. - finally, if a command matches, they return which command matched and
  341. the arguments
  342. The function return 0 in case of help is requested; <0 in case
  343. of uncorrect command; >0 in case of matching commands
  344. argc, argv are the arg-counter and arg-vector (input)
  345. *nargs_ is the number of the arguments after the command (output)
  346. **cmd_ is the invoked command (output)
  347. ***args_ are the arguments after the command
  348. */
  349. static int parse_args(int argc, char **argv,
  350. CommandFunction *func_,
  351. int *nargs_, char **cmd_, char ***args_ )
  352. {
  353. struct Command *cp;
  354. struct Command *matchcmd=0;
  355. char *prgname = get_prgname(argv[0]);
  356. int i=0, helprequested=0;
  357. if( argc < 2 || !strcmp(argv[1], "help") ||
  358. !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
  359. help(prgname);
  360. return 0;
  361. }
  362. for( cp = commands; cp->verb; cp++ )
  363. if( !cp->ncmds)
  364. cp->ncmds = split_command(cp->verb, &(cp->cmds));
  365. for( cp = commands; cp->verb; cp++ ){
  366. int match;
  367. if( argc-1 < cp->ncmds )
  368. continue;
  369. for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){
  370. char *s1, *s2;
  371. s1 = cp->cmds[i];
  372. s2 = argv[i+1];
  373. for(s2 = cp->cmds[i], s1 = argv[i+1];
  374. *s1 == *s2 && *s1;
  375. s1++, s2++ ) ;
  376. if( *s1 ){
  377. match=0;
  378. break;
  379. }
  380. }
  381. /* If you understand why this code works ...
  382. you are a genious !! */
  383. if(argc>i+1 && !strcmp(argv[i+1],"--help")){
  384. if(!helprequested)
  385. printf("Usage:\n");
  386. print_help(prgname, cp, ADVANCED_HELP);
  387. helprequested=1;
  388. continue;
  389. }
  390. if(!match)
  391. continue;
  392. matchcmd = cp;
  393. *nargs_ = argc-matchcmd->ncmds-1;
  394. *cmd_ = matchcmd->verb;
  395. *args_ = argv+matchcmd->ncmds+1;
  396. *func_ = cp->func;
  397. break;
  398. }
  399. if(helprequested){
  400. printf("\n%s\n", MMC_VERSION);
  401. return 0;
  402. }
  403. if(!matchcmd){
  404. fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]);
  405. help(prgname);
  406. return -1;
  407. }
  408. if(check_ambiguity(matchcmd, argv))
  409. return -2;
  410. /* check the number of argument */
  411. if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){
  412. fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n",
  413. matchcmd->verb, -matchcmd->nargs);
  414. return -2;
  415. }
  416. if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){
  417. fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n",
  418. matchcmd->verb, matchcmd->nargs);
  419. return -2;
  420. }
  421. if (prepare_args( nargs_, args_, prgname, matchcmd )){
  422. fprintf(stderr, "ERROR: not enough memory\\n");
  423. return -20;
  424. }
  425. return 1;
  426. }
  427. int cmd_main(int ac, char **av )
  428. {
  429. char *cmd=0, **args=0;
  430. int nargs=0, r;
  431. CommandFunction func=0;
  432. r = parse_args(ac, av, &func, &nargs, &cmd, &args);
  433. if( r <= 0 ){
  434. /* error or no command to parse*/
  435. exit(-r);
  436. }
  437. exit(func(nargs, args));
  438. }