mmc_cmds.c 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659
  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. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <unistd.h>
  26. #include <fcntl.h>
  27. #include <errno.h>
  28. #include <stdint.h>
  29. #include <assert.h>
  30. #include <linux/fs.h> /* for BLKGETSIZE */
  31. #include "mmc.h"
  32. #include "mmc_cmds.h"
  33. #include "3rdparty/hmac_sha/hmac_sha2.h"
  34. #ifndef offsetof
  35. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  36. #endif
  37. #define WP_BLKS_PER_QUERY 32
  38. #define USER_WP_PERM_PSWD_DIS 0x80
  39. #define USER_WP_CD_PERM_WP_DIS 0x40
  40. #define USER_WP_US_PERM_WP_DIS 0x10
  41. #define USER_WP_US_PWR_WP_DIS 0x08
  42. #define USER_WP_US_PERM_WP_EN 0x04
  43. #define USER_WP_US_PWR_WP_EN 0x01
  44. #define USER_WP_CLEAR (USER_WP_US_PERM_WP_DIS | USER_WP_US_PWR_WP_DIS \
  45. | USER_WP_US_PERM_WP_EN | USER_WP_US_PWR_WP_EN)
  46. #define WPTYPE_NONE 0
  47. #define WPTYPE_TEMP 1
  48. #define WPTYPE_PWRON 2
  49. #define WPTYPE_PERM 3
  50. int read_extcsd(int fd, __u8 *ext_csd)
  51. {
  52. int ret = 0;
  53. struct mmc_ioc_cmd idata;
  54. memset(&idata, 0, sizeof(idata));
  55. memset(ext_csd, 0, sizeof(__u8) * 512);
  56. idata.write_flag = 0;
  57. idata.opcode = MMC_SEND_EXT_CSD;
  58. idata.arg = 0;
  59. idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
  60. idata.blksz = 512;
  61. idata.blocks = 1;
  62. mmc_ioc_cmd_set_data(idata, ext_csd);
  63. ret = ioctl(fd, MMC_IOC_CMD, &idata);
  64. if (ret)
  65. perror("ioctl");
  66. return ret;
  67. }
  68. int write_extcsd_value(int fd, __u8 index, __u8 value)
  69. {
  70. int ret = 0;
  71. struct mmc_ioc_cmd idata;
  72. memset(&idata, 0, sizeof(idata));
  73. idata.write_flag = 1;
  74. idata.opcode = MMC_SWITCH;
  75. idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
  76. (index << 16) |
  77. (value << 8) |
  78. EXT_CSD_CMD_SET_NORMAL;
  79. idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
  80. ret = ioctl(fd, MMC_IOC_CMD, &idata);
  81. if (ret)
  82. perror("ioctl");
  83. return ret;
  84. }
  85. int send_status(int fd, __u32 *response)
  86. {
  87. int ret = 0;
  88. struct mmc_ioc_cmd idata;
  89. memset(&idata, 0, sizeof(idata));
  90. idata.opcode = MMC_SEND_STATUS;
  91. idata.arg = (1 << 16);
  92. idata.flags = MMC_RSP_R1 | MMC_CMD_AC;
  93. ret = ioctl(fd, MMC_IOC_CMD, &idata);
  94. if (ret)
  95. perror("ioctl");
  96. *response = idata.response[0];
  97. return ret;
  98. }
  99. static __u32 get_size_in_blks(int fd)
  100. {
  101. int res;
  102. int size;
  103. res = ioctl(fd, BLKGETSIZE, &size);
  104. if (res) {
  105. fprintf(stderr, "Error getting device size, errno: %d\n",
  106. errno);
  107. perror("");
  108. return -1;
  109. }
  110. return size;
  111. }
  112. static int set_write_protect(int fd, __u32 blk_addr, int on_off)
  113. {
  114. int ret = 0;
  115. struct mmc_ioc_cmd idata;
  116. memset(&idata, 0, sizeof(idata));
  117. idata.write_flag = 1;
  118. if (on_off)
  119. idata.opcode = MMC_SET_WRITE_PROT;
  120. else
  121. idata.opcode = MMC_CLEAR_WRITE_PROT;
  122. idata.arg = blk_addr;
  123. idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
  124. ret = ioctl(fd, MMC_IOC_CMD, &idata);
  125. if (ret)
  126. perror("ioctl");
  127. return ret;
  128. }
  129. static int send_write_protect_type(int fd, __u32 blk_addr, __u64 *group_bits)
  130. {
  131. int ret = 0;
  132. struct mmc_ioc_cmd idata;
  133. __u8 buf[8];
  134. __u64 bits = 0;
  135. int x;
  136. memset(&idata, 0, sizeof(idata));
  137. idata.write_flag = 0;
  138. idata.opcode = MMC_SEND_WRITE_PROT_TYPE;
  139. idata.blksz = 8,
  140. idata.blocks = 1,
  141. idata.arg = blk_addr;
  142. idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
  143. mmc_ioc_cmd_set_data(idata, buf);
  144. ret = ioctl(fd, MMC_IOC_CMD, &idata);
  145. if (ret)
  146. perror("ioctl");
  147. for (x = 0; x < sizeof(buf); x++)
  148. bits |= (__u64)(buf[7 - x]) << (x * 8);
  149. *group_bits = bits;
  150. return ret;
  151. }
  152. static void print_writeprotect_boot_status(__u8 *ext_csd)
  153. {
  154. __u8 reg;
  155. __u8 ext_csd_rev = ext_csd[EXT_CSD_REV];
  156. /* A43: reserved [174:0] */
  157. if (ext_csd_rev >= 5) {
  158. printf("Boot write protection status registers"
  159. " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
  160. reg = ext_csd[EXT_CSD_BOOT_WP];
  161. printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
  162. printf(" Power ro locking: ");
  163. if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
  164. printf("not possible\n");
  165. else
  166. printf("possible\n");
  167. printf(" Permanent ro locking: ");
  168. if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
  169. printf("not possible\n");
  170. else
  171. printf("possible\n");
  172. printf(" ro lock status: ");
  173. if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
  174. printf("locked until next power on\n");
  175. else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
  176. printf("locked permanently\n");
  177. else
  178. printf("not locked\n");
  179. }
  180. }
  181. static int get_wp_group_size_in_blks(__u8 *ext_csd, __u32 *size)
  182. {
  183. __u8 ext_csd_rev = ext_csd[EXT_CSD_REV];
  184. if ((ext_csd_rev < 5) || (ext_csd[EXT_CSD_ERASE_GROUP_DEF] == 0))
  185. return 1;
  186. *size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
  187. ext_csd[EXT_CSD_HC_WP_GRP_SIZE] * 1024;
  188. return 0;
  189. }
  190. int do_writeprotect_boot_get(int nargs, char **argv)
  191. {
  192. __u8 ext_csd[512];
  193. int fd, ret;
  194. char *device;
  195. if (nargs != 2) {
  196. fprintf(stderr, "Usage: mmc writeprotect boot get </path/to/mmcblkX>\n");
  197. exit(1);
  198. }
  199. device = argv[1];
  200. fd = open(device, O_RDWR);
  201. if (fd < 0) {
  202. perror("open");
  203. exit(1);
  204. }
  205. ret = read_extcsd(fd, ext_csd);
  206. if (ret) {
  207. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  208. exit(1);
  209. }
  210. print_writeprotect_boot_status(ext_csd);
  211. return ret;
  212. }
  213. int do_writeprotect_boot_set(int nargs, char **argv)
  214. {
  215. __u8 ext_csd[512], value;
  216. int fd, ret;
  217. char *device;
  218. if (nargs != 2) {
  219. fprintf(stderr, "Usage: mmc writeprotect boot set </path/to/mmcblkX>\n");
  220. exit(1);
  221. }
  222. device = argv[1];
  223. fd = open(device, O_RDWR);
  224. if (fd < 0) {
  225. perror("open");
  226. exit(1);
  227. }
  228. ret = read_extcsd(fd, ext_csd);
  229. if (ret) {
  230. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  231. exit(1);
  232. }
  233. value = ext_csd[EXT_CSD_BOOT_WP] |
  234. EXT_CSD_BOOT_WP_B_PWR_WP_EN;
  235. ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
  236. if (ret) {
  237. fprintf(stderr, "Could not write 0x%02x to "
  238. "EXT_CSD[%d] in %s\n",
  239. value, EXT_CSD_BOOT_WP, device);
  240. exit(1);
  241. }
  242. return ret;
  243. }
  244. static char *prot_desc[] = {
  245. "No",
  246. "Temporary",
  247. "Power-on",
  248. "Permanent"
  249. };
  250. static void print_wp_status(__u32 wp_sizeblks, __u32 start_group,
  251. __u32 end_group, int rptype)
  252. {
  253. printf("Write Protect Groups %d-%d (Blocks %d-%d), ",
  254. start_group, end_group,
  255. start_group * wp_sizeblks, ((end_group + 1) * wp_sizeblks) - 1);
  256. printf("%s Write Protection\n", prot_desc[rptype]);
  257. }
  258. int do_writeprotect_user_get(int nargs, char **argv)
  259. {
  260. __u8 ext_csd[512];
  261. int fd, ret;
  262. char *device;
  263. int x;
  264. int y = 0;
  265. __u32 wp_sizeblks;
  266. __u32 dev_sizeblks;
  267. __u32 cnt;
  268. __u64 bits;
  269. __u32 wpblk;
  270. __u32 last_wpblk = 0;
  271. __u32 prot;
  272. __u32 last_prot = -1;
  273. int remain;
  274. if (nargs != 2) {
  275. fprintf(stderr, "Usage: mmc writeprotect user get </path/to/mmcblkX>\n");
  276. exit(1);
  277. }
  278. device = argv[1];
  279. fd = open(device, O_RDWR);
  280. if (fd < 0) {
  281. perror("open");
  282. exit(1);
  283. }
  284. ret = read_extcsd(fd, ext_csd);
  285. if (ret) {
  286. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  287. exit(1);
  288. }
  289. ret = get_wp_group_size_in_blks(ext_csd, &wp_sizeblks);
  290. if (ret)
  291. exit(1);
  292. printf("Write Protect Group size in blocks/bytes: %d/%d\n",
  293. wp_sizeblks, wp_sizeblks * 512);
  294. dev_sizeblks = get_size_in_blks(fd);
  295. cnt = dev_sizeblks / wp_sizeblks;
  296. for (x = 0; x < cnt; x += WP_BLKS_PER_QUERY) {
  297. ret = send_write_protect_type(fd, x * wp_sizeblks, &bits);
  298. if (ret)
  299. break;
  300. remain = cnt - x;
  301. if (remain > WP_BLKS_PER_QUERY)
  302. remain = WP_BLKS_PER_QUERY;
  303. for (y = 0; y < remain; y++) {
  304. prot = (bits >> (y * 2)) & 0x3;
  305. if (prot != last_prot) {
  306. /* not first time */
  307. if (last_prot != -1) {
  308. wpblk = x + y;
  309. print_wp_status(wp_sizeblks,
  310. last_wpblk,
  311. wpblk - 1,
  312. last_prot);
  313. last_wpblk = wpblk;
  314. }
  315. last_prot = prot;
  316. }
  317. }
  318. }
  319. if (last_wpblk != (x + y - 1))
  320. print_wp_status(wp_sizeblks, last_wpblk, cnt - 1, last_prot);
  321. return ret;
  322. }
  323. int do_writeprotect_user_set(int nargs, char **argv)
  324. {
  325. __u8 ext_csd[512];
  326. int fd, ret;
  327. char *device;
  328. int blk_start;
  329. int blk_cnt;
  330. __u32 wp_blks;
  331. __u8 user_wp;
  332. int x;
  333. int wptype;
  334. if (nargs != 5)
  335. goto usage;
  336. device = argv[4];
  337. fd = open(device, O_RDWR);
  338. if (fd < 0) {
  339. perror("open");
  340. exit(1);
  341. }
  342. if (!strcmp(argv[1], "none")) {
  343. wptype = WPTYPE_NONE;
  344. } else if (!strcmp(argv[1], "temp")) {
  345. wptype = WPTYPE_TEMP;
  346. } else if (!strcmp(argv[1], "pwron")) {
  347. wptype = WPTYPE_PWRON;
  348. #ifdef DANGEROUS_COMMANDS_ENABLED
  349. } else if (!strcmp(argv[1], "perm")) {
  350. wptype = WPTYPE_PERM;
  351. #endif /* DANGEROUS_COMMANDS_ENABLED */
  352. } else {
  353. fprintf(stderr, "Error, invalid \"type\"\n");
  354. goto usage;
  355. }
  356. ret = read_extcsd(fd, ext_csd);
  357. if (ret) {
  358. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  359. exit(1);
  360. }
  361. ret = get_wp_group_size_in_blks(ext_csd, &wp_blks);
  362. if (ret) {
  363. fprintf(stderr, "Operation not supported for this device\n");
  364. exit(1);
  365. }
  366. blk_start = strtol(argv[2], NULL, 0);
  367. blk_cnt = strtol(argv[3], NULL, 0);
  368. if ((blk_start % wp_blks) || (blk_cnt % wp_blks)) {
  369. fprintf(stderr, "<start block> and <blocks> must be a ");
  370. fprintf(stderr, "multiple of the Write Protect Group (%d)\n",
  371. wp_blks);
  372. exit(1);
  373. }
  374. if (wptype != WPTYPE_NONE) {
  375. user_wp = ext_csd[EXT_CSD_USER_WP];
  376. user_wp &= ~USER_WP_CLEAR;
  377. switch (wptype) {
  378. case WPTYPE_TEMP:
  379. break;
  380. case WPTYPE_PWRON:
  381. user_wp |= USER_WP_US_PWR_WP_EN;
  382. break;
  383. case WPTYPE_PERM:
  384. user_wp |= USER_WP_US_PERM_WP_EN;
  385. break;
  386. }
  387. if (user_wp != ext_csd[EXT_CSD_USER_WP]) {
  388. ret = write_extcsd_value(fd, EXT_CSD_USER_WP, user_wp);
  389. if (ret) {
  390. fprintf(stderr, "Error setting EXT_CSD\n");
  391. exit(1);
  392. }
  393. }
  394. }
  395. for (x = 0; x < blk_cnt; x += wp_blks) {
  396. ret = set_write_protect(fd, blk_start + x,
  397. wptype != WPTYPE_NONE);
  398. if (ret) {
  399. fprintf(stderr,
  400. "Could not set write protect for %s\n", device);
  401. exit(1);
  402. }
  403. }
  404. if (wptype != WPTYPE_NONE) {
  405. ret = write_extcsd_value(fd, EXT_CSD_USER_WP,
  406. ext_csd[EXT_CSD_USER_WP]);
  407. if (ret) {
  408. fprintf(stderr, "Error restoring EXT_CSD\n");
  409. exit(1);
  410. }
  411. }
  412. return ret;
  413. usage:
  414. fprintf(stderr,
  415. "Usage: mmc writeprotect user set <type><start block><blocks><device>\n");
  416. exit(1);
  417. }
  418. int do_disable_512B_emulation(int nargs, char **argv)
  419. {
  420. __u8 ext_csd[512], native_sector_size, data_sector_size, wr_rel_param;
  421. int fd, ret;
  422. char *device;
  423. if (nargs != 2) {
  424. fprintf(stderr, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n");
  425. exit(1);
  426. }
  427. device = argv[1];
  428. fd = open(device, O_RDWR);
  429. if (fd < 0) {
  430. perror("open");
  431. exit(1);
  432. }
  433. ret = read_extcsd(fd, ext_csd);
  434. if (ret) {
  435. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  436. exit(1);
  437. }
  438. wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
  439. native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE];
  440. data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE];
  441. if (native_sector_size && !data_sector_size &&
  442. (wr_rel_param & EN_REL_WR)) {
  443. ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1);
  444. if (ret) {
  445. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  446. 1, EXT_CSD_NATIVE_SECTOR_SIZE, device);
  447. exit(1);
  448. }
  449. printf("MMC disable 512B emulation successful. Now reset the device to switch to 4KB native sector mode.\n");
  450. } else if (native_sector_size && data_sector_size) {
  451. printf("MMC 512B emulation mode is already disabled; doing nothing.\n");
  452. } else {
  453. printf("MMC does not support disabling 512B emulation mode.\n");
  454. }
  455. return ret;
  456. }
  457. int do_write_boot_en(int nargs, char **argv)
  458. {
  459. __u8 ext_csd[512];
  460. __u8 value = 0;
  461. int fd, ret;
  462. char *device;
  463. int boot_area, send_ack;
  464. if (nargs != 4) {
  465. fprintf(stderr, "Usage: mmc bootpart enable <partition_number> <send_ack> </path/to/mmcblkX>\n");
  466. exit(1);
  467. }
  468. /*
  469. * If <send_ack> is 1, the device will send acknowledgment
  470. * pattern "010" to the host when boot operation begins.
  471. * If <send_ack> is 0, it won't.
  472. */
  473. boot_area = strtol(argv[1], NULL, 10);
  474. send_ack = strtol(argv[2], NULL, 10);
  475. device = argv[3];
  476. fd = open(device, O_RDWR);
  477. if (fd < 0) {
  478. perror("open");
  479. exit(1);
  480. }
  481. ret = read_extcsd(fd, ext_csd);
  482. if (ret) {
  483. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  484. exit(1);
  485. }
  486. value = ext_csd[EXT_CSD_PART_CONFIG];
  487. switch (boot_area) {
  488. case EXT_CSD_PART_CONFIG_ACC_NONE:
  489. value &= ~(7 << 3);
  490. break;
  491. case EXT_CSD_PART_CONFIG_ACC_BOOT0:
  492. value |= (1 << 3);
  493. value &= ~(3 << 4);
  494. break;
  495. case EXT_CSD_PART_CONFIG_ACC_BOOT1:
  496. value |= (1 << 4);
  497. value &= ~(1 << 3);
  498. value &= ~(1 << 5);
  499. break;
  500. case EXT_CSD_PART_CONFIG_ACC_USER_AREA:
  501. value |= (boot_area << 3);
  502. break;
  503. default:
  504. fprintf(stderr, "Cannot enable the boot area\n");
  505. exit(1);
  506. }
  507. if (send_ack)
  508. value |= EXT_CSD_PART_CONFIG_ACC_ACK;
  509. else
  510. value &= ~EXT_CSD_PART_CONFIG_ACC_ACK;
  511. ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value);
  512. if (ret) {
  513. fprintf(stderr, "Could not write 0x%02x to "
  514. "EXT_CSD[%d] in %s\n",
  515. value, EXT_CSD_PART_CONFIG, device);
  516. exit(1);
  517. }
  518. return ret;
  519. }
  520. int do_boot_bus_conditions_set(int nargs, char **argv)
  521. {
  522. __u8 ext_csd[512];
  523. __u8 value = 0;
  524. int fd, ret;
  525. char *device;
  526. if (nargs != 5) {
  527. fprintf(stderr, "Usage: mmc: bootbus set <boot_mode> <reset_boot_bus_conditions> <boot_bus_width> <device>\n");
  528. exit(1);
  529. }
  530. if (strcmp(argv[1], "single_backward") == 0)
  531. value |= 0;
  532. else if (strcmp(argv[1], "single_hs") == 0)
  533. value |= 0x8;
  534. else if (strcmp(argv[1], "dual") == 0)
  535. value |= 0x10;
  536. else {
  537. fprintf(stderr, "illegal <boot_mode> specified\n");
  538. exit(1);
  539. }
  540. if (strcmp(argv[2], "x1") == 0)
  541. value |= 0;
  542. else if (strcmp(argv[2], "retain") == 0)
  543. value |= 0x4;
  544. else {
  545. fprintf(stderr,
  546. "illegal <reset_boot_bus_conditions> specified\n");
  547. exit(1);
  548. }
  549. if (strcmp(argv[3], "x1") == 0)
  550. value |= 0;
  551. else if (strcmp(argv[3], "x4") == 0)
  552. value |= 0x1;
  553. else if (strcmp(argv[3], "x8") == 0)
  554. value |= 0x2;
  555. else {
  556. fprintf(stderr, "illegal <boot_bus_width> specified\n");
  557. exit(1);
  558. }
  559. device = argv[4];
  560. fd = open(device, O_RDWR);
  561. if (fd < 0) {
  562. perror("open");
  563. exit(1);
  564. }
  565. ret = read_extcsd(fd, ext_csd);
  566. if (ret) {
  567. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  568. exit(1);
  569. }
  570. printf("Changing ext_csd[BOOT_BUS_CONDITIONS] from 0x%02x to 0x%02x\n",
  571. ext_csd[EXT_CSD_BOOT_BUS_CONDITIONS], value);
  572. ret = write_extcsd_value(fd, EXT_CSD_BOOT_BUS_CONDITIONS, value);
  573. if (ret) {
  574. fprintf(stderr, "Could not write 0x%02x to "
  575. "EXT_CSD[%d] in %s\n",
  576. value, EXT_CSD_BOOT_BUS_CONDITIONS, device);
  577. exit(1);
  578. }
  579. close(fd);
  580. return ret;
  581. }
  582. int do_hwreset(int value, int nargs, char **argv)
  583. {
  584. __u8 ext_csd[512];
  585. int fd, ret;
  586. char *device;
  587. if (nargs != 2) {
  588. fprintf(stderr, "Usage: mmc hwreset enable </path/to/mmcblkX>\n");
  589. exit(1);
  590. }
  591. device = argv[1];
  592. fd = open(device, O_RDWR);
  593. if (fd < 0) {
  594. perror("open");
  595. exit(1);
  596. }
  597. ret = read_extcsd(fd, ext_csd);
  598. if (ret) {
  599. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  600. exit(1);
  601. }
  602. if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
  603. EXT_CSD_HW_RESET_EN) {
  604. fprintf(stderr,
  605. "H/W Reset is already permanently enabled on %s\n",
  606. device);
  607. exit(1);
  608. }
  609. if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
  610. EXT_CSD_HW_RESET_DIS) {
  611. fprintf(stderr,
  612. "H/W Reset is already permanently disabled on %s\n",
  613. device);
  614. exit(1);
  615. }
  616. ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value);
  617. if (ret) {
  618. fprintf(stderr,
  619. "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  620. value, EXT_CSD_RST_N_FUNCTION, device);
  621. exit(1);
  622. }
  623. return ret;
  624. }
  625. int do_hwreset_en(int nargs, char **argv)
  626. {
  627. return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv);
  628. }
  629. int do_hwreset_dis(int nargs, char **argv)
  630. {
  631. return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv);
  632. }
  633. int do_write_bkops_en(int nargs, char **argv)
  634. {
  635. __u8 ext_csd[512], value = 0;
  636. int fd, ret;
  637. char *device;
  638. if (nargs != 2) {
  639. fprintf(stderr, "Usage: mmc bkops enable </path/to/mmcblkX>\n");
  640. exit(1);
  641. }
  642. device = argv[1];
  643. fd = open(device, O_RDWR);
  644. if (fd < 0) {
  645. perror("open");
  646. exit(1);
  647. }
  648. ret = read_extcsd(fd, ext_csd);
  649. if (ret) {
  650. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  651. exit(1);
  652. }
  653. if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
  654. fprintf(stderr, "%s doesn't support BKOPS\n", device);
  655. exit(1);
  656. }
  657. ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_ENABLE);
  658. if (ret) {
  659. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  660. value, EXT_CSD_BKOPS_EN, device);
  661. exit(1);
  662. }
  663. return ret;
  664. }
  665. int do_status_get(int nargs, char **argv)
  666. {
  667. __u32 response;
  668. int fd, ret;
  669. char *device;
  670. if (nargs != 2) {
  671. fprintf(stderr, "Usage: mmc status get </path/to/mmcblkX>\n");
  672. exit(1);
  673. }
  674. device = argv[1];
  675. fd = open(device, O_RDWR);
  676. if (fd < 0) {
  677. perror("open");
  678. exit(1);
  679. }
  680. ret = send_status(fd, &response);
  681. if (ret) {
  682. fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device);
  683. exit(1);
  684. }
  685. printf("SEND_STATUS response: 0x%08x\n", response);
  686. return ret;
  687. }
  688. unsigned int get_sector_count(__u8 *ext_csd)
  689. {
  690. return (ext_csd[EXT_CSD_SEC_COUNT_3] << 24) |
  691. (ext_csd[EXT_CSD_SEC_COUNT_2] << 16) |
  692. (ext_csd[EXT_CSD_SEC_COUNT_1] << 8) |
  693. ext_csd[EXT_CSD_SEC_COUNT_0];
  694. }
  695. int is_blockaddresed(__u8 *ext_csd)
  696. {
  697. unsigned int sectors = get_sector_count(ext_csd);
  698. /* over 2GiB devices are block-addressed */
  699. return (sectors > (2u * 1024 * 1024 * 1024) / 512);
  700. }
  701. unsigned int get_hc_wp_grp_size(__u8 *ext_csd)
  702. {
  703. return ext_csd[221];
  704. }
  705. unsigned int get_hc_erase_grp_size(__u8 *ext_csd)
  706. {
  707. return ext_csd[224];
  708. }
  709. int set_partitioning_setting_completed(int dry_run, const char * const device,
  710. int fd)
  711. {
  712. int ret;
  713. if (dry_run == 1) {
  714. fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n");
  715. fprintf(stderr, "These changes will not take effect neither "
  716. "now nor after a power cycle\n");
  717. return 1;
  718. } else if (dry_run == 2) {
  719. printf("-c given, expecting more partition settings before "
  720. "writing PARTITION_SETTING_COMPLETED\n");
  721. return 0;
  722. }
  723. fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n");
  724. ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1);
  725. if (ret) {
  726. fprintf(stderr, "Could not write 0x1 to "
  727. "EXT_CSD[%d] in %s\n",
  728. EXT_CSD_PARTITION_SETTING_COMPLETED, device);
  729. return 1;
  730. }
  731. __u32 response;
  732. ret = send_status(fd, &response);
  733. if (ret) {
  734. fprintf(stderr, "Could not get response to SEND_STATUS "
  735. "from %s\n", device);
  736. return 1;
  737. }
  738. if (response & R1_SWITCH_ERROR) {
  739. fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED "
  740. "failed on %s\n", device);
  741. return 1;
  742. }
  743. fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on "
  744. "%s SUCCESS\n", device);
  745. fprintf(stderr, "Device power cycle needed for settings to "
  746. "take effect.\n"
  747. "Confirm that PARTITION_SETTING_COMPLETED bit is set "
  748. "using 'extcsd read' after power cycle\n");
  749. return 0;
  750. }
  751. int check_enhanced_area_total_limit(const char * const device, int fd)
  752. {
  753. __u8 ext_csd[512];
  754. __u32 regl;
  755. unsigned long max_enh_area_sz, user_area_sz, enh_area_sz = 0;
  756. unsigned long gp4_part_sz, gp3_part_sz, gp2_part_sz, gp1_part_sz;
  757. unsigned long total_sz, total_gp_user_sz;
  758. unsigned int wp_sz, erase_sz;
  759. int ret;
  760. ret = read_extcsd(fd, ext_csd);
  761. if (ret) {
  762. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  763. exit(1);
  764. }
  765. wp_sz = get_hc_wp_grp_size(ext_csd);
  766. erase_sz = get_hc_erase_grp_size(ext_csd);
  767. regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_4_2] << 16) |
  768. (ext_csd[EXT_CSD_GP_SIZE_MULT_4_1] << 8) |
  769. ext_csd[EXT_CSD_GP_SIZE_MULT_4_0];
  770. gp4_part_sz = 512l * regl * erase_sz * wp_sz;
  771. if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_4) {
  772. enh_area_sz += gp4_part_sz;
  773. printf("Enhanced GP4 Partition Size [GP_SIZE_MULT_4]: 0x%06x\n", regl);
  774. printf(" i.e. %lu KiB\n", gp4_part_sz);
  775. }
  776. regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_3_2] << 16) |
  777. (ext_csd[EXT_CSD_GP_SIZE_MULT_3_1] << 8) |
  778. ext_csd[EXT_CSD_GP_SIZE_MULT_3_0];
  779. gp3_part_sz = 512l * regl * erase_sz * wp_sz;
  780. if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_3) {
  781. enh_area_sz += gp3_part_sz;
  782. printf("Enhanced GP3 Partition Size [GP_SIZE_MULT_3]: 0x%06x\n", regl);
  783. printf(" i.e. %lu KiB\n", gp3_part_sz);
  784. }
  785. regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_2_2] << 16) |
  786. (ext_csd[EXT_CSD_GP_SIZE_MULT_2_1] << 8) |
  787. ext_csd[EXT_CSD_GP_SIZE_MULT_2_0];
  788. gp2_part_sz = 512l * regl * erase_sz * wp_sz;
  789. if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_2) {
  790. enh_area_sz += gp2_part_sz;
  791. printf("Enhanced GP2 Partition Size [GP_SIZE_MULT_2]: 0x%06x\n", regl);
  792. printf(" i.e. %lu KiB\n", gp2_part_sz);
  793. }
  794. regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_1_2] << 16) |
  795. (ext_csd[EXT_CSD_GP_SIZE_MULT_1_1] << 8) |
  796. ext_csd[EXT_CSD_GP_SIZE_MULT_1_0];
  797. gp1_part_sz = 512l * regl * erase_sz * wp_sz;
  798. if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_1) {
  799. enh_area_sz += gp1_part_sz;
  800. printf("Enhanced GP1 Partition Size [GP_SIZE_MULT_1]: 0x%06x\n", regl);
  801. printf(" i.e. %lu KiB\n", gp1_part_sz);
  802. }
  803. regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
  804. (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
  805. ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
  806. user_area_sz = 512l * regl * erase_sz * wp_sz;
  807. if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_USR) {
  808. enh_area_sz += user_area_sz;
  809. printf("Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x%06x\n", regl);
  810. printf(" i.e. %lu KiB\n", user_area_sz);
  811. }
  812. regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
  813. (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
  814. ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
  815. max_enh_area_sz = 512l * regl * erase_sz * wp_sz;
  816. printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n", regl);
  817. printf(" i.e. %lu KiB\n", max_enh_area_sz);
  818. if (enh_area_sz > max_enh_area_sz) {
  819. fprintf(stderr,
  820. "Programmed total enhanced size %lu KiB cannot exceed max enhanced area %lu KiB %s\n",
  821. enh_area_sz, max_enh_area_sz, device);
  822. return 1;
  823. }
  824. total_sz = get_sector_count(ext_csd) / 2;
  825. total_gp_user_sz = gp4_part_sz + gp3_part_sz + gp2_part_sz +
  826. gp1_part_sz + user_area_sz;
  827. if (total_gp_user_sz > total_sz) {
  828. fprintf(stderr,
  829. "requested total partition size %lu KiB cannot exceed card capacity %lu KiB %s\n",
  830. total_gp_user_sz, total_sz, device);
  831. return 1;
  832. }
  833. return 0;
  834. }
  835. int do_create_gp_partition(int nargs, char **argv)
  836. {
  837. __u8 value;
  838. __u8 ext_csd[512];
  839. __u8 address;
  840. int fd, ret;
  841. char *device;
  842. int dry_run = 1;
  843. int partition, enh_attr, ext_attr;
  844. unsigned int length_kib, gp_size_mult;
  845. unsigned long align;
  846. if (nargs != 7) {
  847. fprintf(stderr, "Usage: mmc gp create <-y|-n|-c> <length KiB> <partition> <enh_attr> <ext_attr> </path/to/mmcblkX>\n");
  848. exit(1);
  849. }
  850. if (!strcmp("-y", argv[1])) {
  851. dry_run = 0;
  852. } else if (!strcmp("-c", argv[1])) {
  853. dry_run = 2;
  854. }
  855. length_kib = strtol(argv[2], NULL, 10);
  856. partition = strtol(argv[3], NULL, 10);
  857. enh_attr = strtol(argv[4], NULL, 10);
  858. ext_attr = strtol(argv[5], NULL, 10);
  859. device = argv[6];
  860. if (partition < 1 || partition > 4) {
  861. printf("Invalid gp partition number; valid range [1-4].\n");
  862. exit(1);
  863. }
  864. if (enh_attr && ext_attr) {
  865. printf("Not allowed to set both enhanced attribute and extended attribute\n");
  866. exit(1);
  867. }
  868. fd = open(device, O_RDWR);
  869. if (fd < 0) {
  870. perror("open");
  871. exit(1);
  872. }
  873. ret = read_extcsd(fd, ext_csd);
  874. if (ret) {
  875. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  876. exit(1);
  877. }
  878. /* assert not PARTITION_SETTING_COMPLETED */
  879. if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) {
  880. printf(" Device is already partitioned\n");
  881. exit(1);
  882. }
  883. align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
  884. gp_size_mult = (length_kib + align/2l) / align;
  885. /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
  886. ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
  887. if (ret) {
  888. fprintf(stderr, "Could not write 0x1 to EXT_CSD[%d] in %s\n",
  889. EXT_CSD_ERASE_GROUP_DEF, device);
  890. exit(1);
  891. }
  892. value = (gp_size_mult >> 16) & 0xff;
  893. address = EXT_CSD_GP_SIZE_MULT_1_2 + (partition - 1) * 3;
  894. ret = write_extcsd_value(fd, address, value);
  895. if (ret) {
  896. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  897. value, address, device);
  898. exit(1);
  899. }
  900. value = (gp_size_mult >> 8) & 0xff;
  901. address = EXT_CSD_GP_SIZE_MULT_1_1 + (partition - 1) * 3;
  902. ret = write_extcsd_value(fd, address, value);
  903. if (ret) {
  904. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  905. value, address, device);
  906. exit(1);
  907. }
  908. value = gp_size_mult & 0xff;
  909. address = EXT_CSD_GP_SIZE_MULT_1_0 + (partition - 1) * 3;
  910. ret = write_extcsd_value(fd, address, value);
  911. if (ret) {
  912. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  913. value, address, device);
  914. exit(1);
  915. }
  916. value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
  917. if (enh_attr)
  918. value |= (1 << partition);
  919. else
  920. value &= ~(1 << partition);
  921. ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
  922. if (ret) {
  923. fprintf(stderr, "Could not write EXT_CSD_ENH_%x to EXT_CSD[%d] in %s\n",
  924. partition, EXT_CSD_PARTITIONS_ATTRIBUTE, device);
  925. exit(1);
  926. }
  927. address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 + (partition - 1) / 2;
  928. value = ext_csd[address];
  929. if (ext_attr)
  930. value |= (ext_attr << (4 * ((partition - 1) % 2)));
  931. else
  932. value &= (0xF << (4 * ((partition % 2))));
  933. ret = write_extcsd_value(fd, address, value);
  934. if (ret) {
  935. fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n",
  936. value, address, device);
  937. exit(1);
  938. }
  939. ret = check_enhanced_area_total_limit(device, fd);
  940. if (ret)
  941. exit(1);
  942. if (set_partitioning_setting_completed(dry_run, device, fd))
  943. exit(1);
  944. return 0;
  945. }
  946. int do_enh_area_set(int nargs, char **argv)
  947. {
  948. __u8 value;
  949. __u8 ext_csd[512];
  950. int fd, ret;
  951. char *device;
  952. int dry_run = 1;
  953. unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult;
  954. unsigned long align;
  955. if (nargs != 5) {
  956. fprintf(stderr, "Usage: mmc enh_area set <-y|-n|-c> <start KiB> <length KiB> </path/to/mmcblkX>\n");
  957. exit(1);
  958. }
  959. if (!strcmp("-y", argv[1])) {
  960. dry_run = 0;
  961. } else if (!strcmp("-c", argv[1])) {
  962. dry_run = 2;
  963. }
  964. start_kib = strtol(argv[2], NULL, 10);
  965. length_kib = strtol(argv[3], NULL, 10);
  966. device = argv[4];
  967. fd = open(device, O_RDWR);
  968. if (fd < 0) {
  969. perror("open");
  970. exit(1);
  971. }
  972. ret = read_extcsd(fd, ext_csd);
  973. if (ret) {
  974. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  975. exit(1);
  976. }
  977. /* assert ENH_ATTRIBUTE_EN */
  978. if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN))
  979. {
  980. printf(" Device cannot have enhanced tech.\n");
  981. exit(1);
  982. }
  983. /* assert not PARTITION_SETTING_COMPLETED */
  984. if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
  985. {
  986. printf(" Device is already partitioned\n");
  987. exit(1);
  988. }
  989. align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
  990. enh_size_mult = (length_kib + align/2l) / align;
  991. enh_start_addr = start_kib * (1024 / (is_blockaddresed(ext_csd) ? 512 : 1));
  992. enh_start_addr /= align;
  993. enh_start_addr *= align;
  994. /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
  995. ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
  996. if (ret) {
  997. fprintf(stderr, "Could not write 0x1 to "
  998. "EXT_CSD[%d] in %s\n",
  999. EXT_CSD_ERASE_GROUP_DEF, device);
  1000. exit(1);
  1001. }
  1002. /* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
  1003. value = (enh_start_addr >> 24) & 0xff;
  1004. ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
  1005. if (ret) {
  1006. fprintf(stderr, "Could not write 0x%02x to "
  1007. "EXT_CSD[%d] in %s\n", value,
  1008. EXT_CSD_ENH_START_ADDR_3, device);
  1009. exit(1);
  1010. }
  1011. value = (enh_start_addr >> 16) & 0xff;
  1012. ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value);
  1013. if (ret) {
  1014. fprintf(stderr, "Could not write 0x%02x to "
  1015. "EXT_CSD[%d] in %s\n", value,
  1016. EXT_CSD_ENH_START_ADDR_2, device);
  1017. exit(1);
  1018. }
  1019. value = (enh_start_addr >> 8) & 0xff;
  1020. ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value);
  1021. if (ret) {
  1022. fprintf(stderr, "Could not write 0x%02x to "
  1023. "EXT_CSD[%d] in %s\n", value,
  1024. EXT_CSD_ENH_START_ADDR_1, device);
  1025. exit(1);
  1026. }
  1027. value = enh_start_addr & 0xff;
  1028. ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value);
  1029. if (ret) {
  1030. fprintf(stderr, "Could not write 0x%02x to "
  1031. "EXT_CSD[%d] in %s\n", value,
  1032. EXT_CSD_ENH_START_ADDR_0, device);
  1033. exit(1);
  1034. }
  1035. value = (enh_size_mult >> 16) & 0xff;
  1036. ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value);
  1037. if (ret) {
  1038. fprintf(stderr, "Could not write 0x%02x to "
  1039. "EXT_CSD[%d] in %s\n", value,
  1040. EXT_CSD_ENH_SIZE_MULT_2, device);
  1041. exit(1);
  1042. }
  1043. value = (enh_size_mult >> 8) & 0xff;
  1044. ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value);
  1045. if (ret) {
  1046. fprintf(stderr, "Could not write 0x%02x to "
  1047. "EXT_CSD[%d] in %s\n", value,
  1048. EXT_CSD_ENH_SIZE_MULT_1, device);
  1049. exit(1);
  1050. }
  1051. value = enh_size_mult & 0xff;
  1052. ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value);
  1053. if (ret) {
  1054. fprintf(stderr, "Could not write 0x%02x to "
  1055. "EXT_CSD[%d] in %s\n", value,
  1056. EXT_CSD_ENH_SIZE_MULT_0, device);
  1057. exit(1);
  1058. }
  1059. value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR;
  1060. ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
  1061. if (ret) {
  1062. fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
  1063. "EXT_CSD[%d] in %s\n",
  1064. EXT_CSD_PARTITIONS_ATTRIBUTE, device);
  1065. exit(1);
  1066. }
  1067. ret = check_enhanced_area_total_limit(device, fd);
  1068. if (ret)
  1069. exit(1);
  1070. printf("Done setting ENH_USR area on %s\n", device);
  1071. if (set_partitioning_setting_completed(dry_run, device, fd))
  1072. exit(1);
  1073. return 0;
  1074. }
  1075. int do_write_reliability_set(int nargs, char **argv)
  1076. {
  1077. __u8 value;
  1078. __u8 ext_csd[512];
  1079. int fd, ret;
  1080. int dry_run = 1;
  1081. int partition;
  1082. char *device;
  1083. if (nargs != 4) {
  1084. fprintf(stderr,"Usage: mmc write_reliability set <-y|-n|-c> <partition> </path/to/mmcblkX>\n");
  1085. exit(1);
  1086. }
  1087. if (!strcmp("-y", argv[1])) {
  1088. dry_run = 0;
  1089. } else if (!strcmp("-c", argv[1])) {
  1090. dry_run = 2;
  1091. }
  1092. partition = strtol(argv[2], NULL, 10);
  1093. device = argv[3];
  1094. fd = open(device, O_RDWR);
  1095. if (fd < 0) {
  1096. perror("open");
  1097. exit(1);
  1098. }
  1099. ret = read_extcsd(fd, ext_csd);
  1100. if (ret) {
  1101. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  1102. exit(1);
  1103. }
  1104. /* assert not PARTITION_SETTING_COMPLETED */
  1105. if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
  1106. {
  1107. printf(" Device is already partitioned\n");
  1108. exit(1);
  1109. }
  1110. /* assert HS_CTRL_REL */
  1111. if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) {
  1112. printf("Cannot set write reliability parameters, WR_REL_SET is "
  1113. "read-only\n");
  1114. exit(1);
  1115. }
  1116. value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition);
  1117. ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value);
  1118. if (ret) {
  1119. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  1120. value, EXT_CSD_WR_REL_SET, device);
  1121. exit(1);
  1122. }
  1123. printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n",
  1124. value, device);
  1125. if (set_partitioning_setting_completed(dry_run, device, fd))
  1126. exit(1);
  1127. return 0;
  1128. }
  1129. int do_read_extcsd(int nargs, char **argv)
  1130. {
  1131. __u8 ext_csd[512], ext_csd_rev, reg;
  1132. __u32 regl;
  1133. int fd, ret;
  1134. char *device;
  1135. const char *str;
  1136. if (nargs != 2) {
  1137. fprintf(stderr, "Usage: mmc extcsd read </path/to/mmcblkX>\n");
  1138. exit(1);
  1139. }
  1140. device = argv[1];
  1141. fd = open(device, O_RDWR);
  1142. if (fd < 0) {
  1143. perror("open");
  1144. exit(1);
  1145. }
  1146. ret = read_extcsd(fd, ext_csd);
  1147. if (ret) {
  1148. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  1149. exit(1);
  1150. }
  1151. ext_csd_rev = ext_csd[EXT_CSD_REV];
  1152. switch (ext_csd_rev) {
  1153. case 8:
  1154. str = "5.1";
  1155. break;
  1156. case 7:
  1157. str = "5.0";
  1158. break;
  1159. case 6:
  1160. str = "4.5";
  1161. break;
  1162. case 5:
  1163. str = "4.41";
  1164. break;
  1165. case 3:
  1166. str = "4.3";
  1167. break;
  1168. case 2:
  1169. str = "4.2";
  1170. break;
  1171. case 1:
  1172. str = "4.1";
  1173. break;
  1174. case 0:
  1175. str = "4.0";
  1176. break;
  1177. default:
  1178. goto out_free;
  1179. }
  1180. printf("=============================================\n");
  1181. printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
  1182. printf("=============================================\n\n");
  1183. if (ext_csd_rev < 3)
  1184. goto out_free; /* No ext_csd */
  1185. /* Parse the Extended CSD registers.
  1186. * Reserved bit should be read as "0" in case of spec older
  1187. * than A441.
  1188. */
  1189. reg = ext_csd[EXT_CSD_S_CMD_SET];
  1190. printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
  1191. if (!reg)
  1192. printf(" - Standard MMC command sets\n");
  1193. reg = ext_csd[EXT_CSD_HPI_FEATURE];
  1194. printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
  1195. if (reg & EXT_CSD_HPI_SUPP) {
  1196. if (reg & EXT_CSD_HPI_IMPL)
  1197. printf("implementation based on CMD12\n");
  1198. else
  1199. printf("implementation based on CMD13\n");
  1200. }
  1201. printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
  1202. ext_csd[502]);
  1203. if (ext_csd_rev >= 6) {
  1204. printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
  1205. ext_csd[501]);
  1206. printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
  1207. ext_csd[500]);
  1208. printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
  1209. ext_csd[499]);
  1210. printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
  1211. ext_csd[498]);
  1212. printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
  1213. ext_csd[497]);
  1214. printf("Context Management Capabilities"
  1215. " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
  1216. printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
  1217. ext_csd[495]);
  1218. printf("Extended partition attribute support"
  1219. " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
  1220. printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
  1221. ext_csd[248]);
  1222. printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
  1223. ext_csd[247]);
  1224. printf("Cache Size [CACHE_SIZE] is %d KiB\n",
  1225. ext_csd[249] << 0 | (ext_csd[250] << 8) |
  1226. (ext_csd[251] << 16) | (ext_csd[252] << 24));
  1227. }
  1228. /* A441: Reserved [501:247]
  1229. A43: reserved [246:229] */
  1230. if (ext_csd_rev >= 5) {
  1231. printf("Background operations status"
  1232. " [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
  1233. /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
  1234. printf("1st Initialisation Time after programmed sector"
  1235. " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
  1236. /* A441: reserved [240] */
  1237. printf("Power class for 52MHz, DDR at 3.6V"
  1238. " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
  1239. printf("Power class for 52MHz, DDR at 1.95V"
  1240. " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
  1241. /* A441: reserved [237-236] */
  1242. if (ext_csd_rev >= 6) {
  1243. printf("Power class for 200MHz at 3.6V"
  1244. " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
  1245. printf("Power class for 200MHz, at 1.95V"
  1246. " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
  1247. }
  1248. printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
  1249. printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
  1250. printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
  1251. /* A441: reserved [233] */
  1252. printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
  1253. printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
  1254. ext_csd[231]);
  1255. }
  1256. if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
  1257. printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
  1258. ext_csd[230]);
  1259. printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
  1260. ext_csd[229]);
  1261. }
  1262. reg = ext_csd[EXT_CSD_BOOT_INFO];
  1263. printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
  1264. if (reg & EXT_CSD_BOOT_INFO_ALT)
  1265. printf(" Device supports alternative boot method\n");
  1266. if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
  1267. printf(" Device supports dual data rate during boot\n");
  1268. if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
  1269. printf(" Device supports high speed timing during boot\n");
  1270. /* A441/A43: reserved [227] */
  1271. printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
  1272. printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
  1273. reg = get_hc_erase_grp_size(ext_csd);
  1274. printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
  1275. reg);
  1276. printf(" i.e. %u KiB\n", 512 * reg);
  1277. printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
  1278. ext_csd[223]);
  1279. printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
  1280. ext_csd[222]);
  1281. reg = get_hc_wp_grp_size(ext_csd);
  1282. printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
  1283. reg);
  1284. printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
  1285. printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
  1286. printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
  1287. /* A441/A43: reserved [218] */
  1288. printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
  1289. /* A441/A43: reserved [216] */
  1290. unsigned int sectors = get_sector_count(ext_csd);
  1291. printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors);
  1292. if (is_blockaddresed(ext_csd))
  1293. printf(" Device is block-addressed\n");
  1294. else
  1295. printf(" Device is NOT block-addressed\n");
  1296. /* A441/A43: reserved [211] */
  1297. printf("Minimum Write Performance for 8bit:\n");
  1298. printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
  1299. printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
  1300. printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
  1301. printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
  1302. printf("Minimum Write Performance for 4bit:\n");
  1303. printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
  1304. printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
  1305. /* A441/A43: reserved [204] */
  1306. printf("Power classes registers:\n");
  1307. printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
  1308. printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
  1309. printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
  1310. printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
  1311. /* A43: reserved [199:198] */
  1312. if (ext_csd_rev >= 5) {
  1313. printf("Partition switching timing "
  1314. "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
  1315. printf("Out-of-interrupt busy timing"
  1316. " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
  1317. }
  1318. /* A441/A43: reserved [197] [195] [193] [190] [188]
  1319. * [186] [184] [182] [180] [176] */
  1320. if (ext_csd_rev >= 6)
  1321. printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
  1322. ext_csd[197]);
  1323. /* DEVICE_TYPE in A45, CARD_TYPE in A441 */
  1324. reg = ext_csd[196];
  1325. printf("Card Type [CARD_TYPE: 0x%02x]\n", reg);
  1326. if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
  1327. if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
  1328. if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
  1329. if (reg & 0x04) printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
  1330. if (reg & 0x02) printf(" HS eMMC @52MHz - at rated device voltage(s)\n");
  1331. if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n");
  1332. printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
  1333. /* ext_csd_rev = ext_csd[EXT_CSD_REV] (already done!!!) */
  1334. printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
  1335. printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
  1336. printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
  1337. printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
  1338. ext_csd[185]);
  1339. /* bus_width: ext_csd[183] not readable */
  1340. printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
  1341. ext_csd[181]);
  1342. reg = ext_csd[EXT_CSD_BOOT_CFG];
  1343. printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
  1344. switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
  1345. case 0x0:
  1346. printf(" Not boot enable\n");
  1347. break;
  1348. case 0x1:
  1349. printf(" Boot Partition 1 enabled\n");
  1350. break;
  1351. case 0x2:
  1352. printf(" Boot Partition 2 enabled\n");
  1353. break;
  1354. case 0x7:
  1355. printf(" User Area Enabled for boot\n");
  1356. break;
  1357. }
  1358. switch (reg & EXT_CSD_BOOT_CFG_ACC) {
  1359. case 0x0:
  1360. printf(" No access to boot partition\n");
  1361. break;
  1362. case 0x1:
  1363. printf(" R/W Boot Partition 1\n");
  1364. break;
  1365. case 0x2:
  1366. printf(" R/W Boot Partition 2\n");
  1367. break;
  1368. case 0x3:
  1369. printf(" R/W Replay Protected Memory Block (RPMB)\n");
  1370. break;
  1371. default:
  1372. printf(" Access to General Purpose partition %d\n",
  1373. (reg & EXT_CSD_BOOT_CFG_ACC) - 3);
  1374. break;
  1375. }
  1376. printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
  1377. ext_csd[178]);
  1378. printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
  1379. ext_csd[177]);
  1380. printf("High-density erase group definition"
  1381. " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
  1382. print_writeprotect_boot_status(ext_csd);
  1383. if (ext_csd_rev >= 5) {
  1384. /* A441]: reserved [172] */
  1385. printf("User area write protection register"
  1386. " [USER_WP]: 0x%02x\n", ext_csd[171]);
  1387. /* A441]: reserved [170] */
  1388. printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
  1389. printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
  1390. reg = ext_csd[EXT_CSD_WR_REL_SET];
  1391. const char * const fast = "existing data is at risk if a power "
  1392. "failure occurs during a write operation";
  1393. const char * const reliable = "the device protects existing "
  1394. "data if a power failure occurs during a write "
  1395. "operation";
  1396. printf("Write reliability setting register"
  1397. " [WR_REL_SET]: 0x%02x\n", reg);
  1398. printf(" user area: %s\n", reg & (1<<0) ? reliable : fast);
  1399. int i;
  1400. for (i = 1; i <= 4; i++) {
  1401. printf(" partition %d: %s\n", i,
  1402. reg & (1<<i) ? reliable : fast);
  1403. }
  1404. reg = ext_csd[EXT_CSD_WR_REL_PARAM];
  1405. printf("Write reliability parameter register"
  1406. " [WR_REL_PARAM]: 0x%02x\n", reg);
  1407. if (reg & 0x01)
  1408. printf(" Device supports writing EXT_CSD_WR_REL_SET\n");
  1409. if (reg & 0x04)
  1410. printf(" Device supports the enhanced def. of reliable "
  1411. "write\n");
  1412. /* sanitize_start ext_csd[165]]: not readable
  1413. * bkops_start ext_csd[164]]: only writable */
  1414. printf("Enable background operations handshake"
  1415. " [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
  1416. printf("H/W reset function"
  1417. " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
  1418. printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
  1419. reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
  1420. printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
  1421. reg);
  1422. if (reg & EXT_CSD_PARTITIONING_EN)
  1423. printf(" Device support partitioning feature\n");
  1424. else
  1425. printf(" Device NOT support partitioning feature\n");
  1426. if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
  1427. printf(" Device can have enhanced tech.\n");
  1428. else
  1429. printf(" Device cannot have enhanced tech.\n");
  1430. regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
  1431. (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
  1432. ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
  1433. printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
  1434. regl);
  1435. unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
  1436. unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
  1437. printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz);
  1438. printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
  1439. ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
  1440. reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
  1441. printf("Partitioning Setting"
  1442. " [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
  1443. reg);
  1444. if (reg)
  1445. printf(" Device partition setting complete\n");
  1446. else
  1447. printf(" Device partition setting NOT complete\n");
  1448. printf("General Purpose Partition Size\n"
  1449. " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
  1450. (ext_csd[153] << 8) | ext_csd[152]);
  1451. printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
  1452. (ext_csd[150] << 8) | ext_csd[149]);
  1453. printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
  1454. (ext_csd[147] << 8) | ext_csd[146]);
  1455. printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
  1456. (ext_csd[144] << 8) | ext_csd[143]);
  1457. regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
  1458. (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
  1459. ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
  1460. printf("Enhanced User Data Area Size"
  1461. " [ENH_SIZE_MULT]: 0x%06x\n", regl);
  1462. printf(" i.e. %lu KiB\n", 512l * regl *
  1463. get_hc_erase_grp_size(ext_csd) *
  1464. get_hc_wp_grp_size(ext_csd));
  1465. regl = (ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
  1466. (ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) |
  1467. (ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) |
  1468. ext_csd[EXT_CSD_ENH_START_ADDR_0];
  1469. printf("Enhanced User Data Start Address"
  1470. " [ENH_START_ADDR]: 0x%08x\n", regl);
  1471. printf(" i.e. %llu bytes offset\n", (is_blockaddresed(ext_csd) ?
  1472. 512ll : 1ll) * regl);
  1473. /* A441]: reserved [135] */
  1474. printf("Bad Block Management mode"
  1475. " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
  1476. /* A441: reserved [133:0] */
  1477. }
  1478. /* B45 */
  1479. if (ext_csd_rev >= 6) {
  1480. int j;
  1481. /* tcase_support ext_csd[132] not readable */
  1482. printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
  1483. ext_csd[131]);
  1484. printf("Program CID/CSD in DDR mode support"
  1485. " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
  1486. ext_csd[130]);
  1487. for (j = 127; j >= 64; j--)
  1488. printf("Vendor Specific Fields"
  1489. " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
  1490. j, ext_csd[j]);
  1491. printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
  1492. ext_csd[63]);
  1493. printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
  1494. ext_csd[62]);
  1495. printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
  1496. printf("1st initialization after disabling sector"
  1497. " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
  1498. ext_csd[60]);
  1499. printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
  1500. ext_csd[59]);
  1501. printf("Number of addressed group to be Released"
  1502. "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
  1503. printf("Exception events control"
  1504. " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
  1505. (ext_csd[57] << 8) | ext_csd[56]);
  1506. printf("Exception events status"
  1507. "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
  1508. (ext_csd[55] << 8) | ext_csd[54]);
  1509. printf("Extended Partitions Attribute"
  1510. " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
  1511. (ext_csd[53] << 8) | ext_csd[52]);
  1512. for (j = 51; j >= 37; j--)
  1513. printf("Context configuration"
  1514. " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
  1515. printf("Packed command status"
  1516. " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
  1517. printf("Packed command failure index"
  1518. " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
  1519. printf("Power Off Notification"
  1520. " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
  1521. printf("Control to turn the Cache ON/OFF"
  1522. " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
  1523. /* flush_cache ext_csd[32] not readable */
  1524. /*Reserved [31:0] */
  1525. }
  1526. if (ext_csd_rev >= 7) {
  1527. printf("eMMC Firmware Version: %s\n",
  1528. (char*)&ext_csd[EXT_CSD_FIRMWARE_VERSION]);
  1529. printf("eMMC Life Time Estimation A [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]: 0x%02x\n",
  1530. ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]);
  1531. printf("eMMC Life Time Estimation B [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]: 0x%02x\n",
  1532. ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]);
  1533. printf("eMMC Pre EOL information [EXT_CSD_PRE_EOL_INFO]: 0x%02x\n",
  1534. ext_csd[EXT_CSD_PRE_EOL_INFO]);
  1535. reg = ext_csd[EXT_CSD_SECURE_REMOVAL_TYPE];
  1536. printf("Secure Removal Type [SECURE_REMOVAL_TYPE]: 0x%02x\n", reg);
  1537. printf(" information is configured to be removed ");
  1538. /* Bit [5:4]: Configure Secure Removal Type */
  1539. switch ((reg & EXT_CSD_CONFIG_SECRM_TYPE) >> 4) {
  1540. case 0x0:
  1541. printf("by an erase of the physical memory\n");
  1542. break;
  1543. case 0x1:
  1544. printf("by an overwriting the addressed locations"
  1545. " with a character followed by an erase\n");
  1546. break;
  1547. case 0x2:
  1548. printf("by an overwriting the addressed locations"
  1549. " with a character, its complement, then a random character\n");
  1550. break;
  1551. case 0x3:
  1552. printf("using a vendor defined\n");
  1553. break;
  1554. }
  1555. /* Bit [3:0]: Supported Secure Removal Type */
  1556. printf(" Supported Secure Removal Type:\n");
  1557. if (reg & 0x01)
  1558. printf(" information removed by an erase of the physical memory\n");
  1559. if (reg & 0x02)
  1560. printf(" information removed by an overwriting the addressed locations"
  1561. " with a character followed by an erase\n");
  1562. if (reg & 0x04)
  1563. printf(" information removed by an overwriting the addressed locations"
  1564. " with a character, its complement, then a random character\n");
  1565. if (reg & 0x08)
  1566. printf(" information removed using a vendor defined\n");
  1567. }
  1568. if (ext_csd_rev >= 8) {
  1569. printf("Command Queue Support [CMDQ_SUPPORT]: 0x%02x\n",
  1570. ext_csd[EXT_CSD_CMDQ_SUPPORT]);
  1571. printf("Command Queue Depth [CMDQ_DEPTH]: %u\n",
  1572. (ext_csd[EXT_CSD_CMDQ_DEPTH] & 0x1f) + 1);
  1573. printf("Command Enabled [CMDQ_MODE_EN]: 0x%02x\n",
  1574. ext_csd[EXT_CSD_CMDQ_MODE_EN]);
  1575. }
  1576. out_free:
  1577. return ret;
  1578. }
  1579. int do_sanitize(int nargs, char **argv)
  1580. {
  1581. int fd, ret;
  1582. char *device;
  1583. if (nargs != 2) {
  1584. fprintf(stderr, "Usage: mmc sanitize </path/to/mmcblkX>\n");
  1585. exit(1);
  1586. }
  1587. device = argv[1];
  1588. fd = open(device, O_RDWR);
  1589. if (fd < 0) {
  1590. perror("open");
  1591. exit(1);
  1592. }
  1593. ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1);
  1594. if (ret) {
  1595. fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  1596. 1, EXT_CSD_SANITIZE_START, device);
  1597. exit(1);
  1598. }
  1599. return ret;
  1600. }
  1601. #define DO_IO(func, fd, buf, nbyte) \
  1602. ({ \
  1603. ssize_t ret = 0, r; \
  1604. do { \
  1605. r = func(fd, buf + ret, nbyte - ret); \
  1606. if (r < 0 && errno != EINTR) { \
  1607. ret = -1; \
  1608. break; \
  1609. } \
  1610. else if (r > 0) \
  1611. ret += r; \
  1612. } while (r != 0 && (size_t)ret != nbyte); \
  1613. \
  1614. ret; \
  1615. })
  1616. #define RPMB_MULTI_CMD_MAX_CMDS 3
  1617. enum rpmb_op_type {
  1618. MMC_RPMB_WRITE_KEY = 0x01,
  1619. MMC_RPMB_READ_CNT = 0x02,
  1620. MMC_RPMB_WRITE = 0x03,
  1621. MMC_RPMB_READ = 0x04,
  1622. /* For internal usage only, do not use it directly */
  1623. MMC_RPMB_READ_RESP = 0x05
  1624. };
  1625. struct rpmb_frame {
  1626. u_int8_t stuff[196];
  1627. u_int8_t key_mac[32];
  1628. u_int8_t data[256];
  1629. u_int8_t nonce[16];
  1630. u_int32_t write_counter;
  1631. u_int16_t addr;
  1632. u_int16_t block_count;
  1633. u_int16_t result;
  1634. u_int16_t req_resp;
  1635. };
  1636. static inline void set_single_cmd(struct mmc_ioc_cmd *ioc, __u32 opcode,
  1637. int write_flag, unsigned int blocks)
  1638. {
  1639. ioc->opcode = opcode;
  1640. ioc->write_flag = write_flag;
  1641. ioc->arg = 0x0;
  1642. ioc->blksz = 512;
  1643. ioc->blocks = blocks;
  1644. ioc->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
  1645. }
  1646. /* Performs RPMB operation.
  1647. *
  1648. * @fd: RPMB device on which we should perform ioctl command
  1649. * @frame_in: input RPMB frame, should be properly inited
  1650. * @frame_out: output (result) RPMB frame. Caller is responsible for checking
  1651. * result and req_resp for output frame.
  1652. * @out_cnt: count of outer frames. Used only for multiple blocks reading,
  1653. * in the other cases -EINVAL will be returned.
  1654. */
  1655. int do_rpmb_op(int fd,
  1656. const struct rpmb_frame *frame_in,
  1657. struct rpmb_frame *frame_out,
  1658. unsigned int out_cnt)
  1659. {
  1660. #ifndef MMC_IOC_MULTI_CMD
  1661. fprintf(stderr, "mmc-utils has been compiled without MMC_IOC_MULTI_CMD"
  1662. " support, needed by RPMB operation.\n");
  1663. exit(1);
  1664. #else
  1665. int err;
  1666. u_int16_t rpmb_type;
  1667. struct mmc_ioc_multi_cmd *mioc;
  1668. struct mmc_ioc_cmd *ioc;
  1669. struct rpmb_frame frame_status = {0};
  1670. if (!frame_in || !frame_out || !out_cnt)
  1671. return -EINVAL;
  1672. /* prepare arguments for MMC_IOC_MULTI_CMD ioctl */
  1673. mioc = (struct mmc_ioc_multi_cmd *)
  1674. malloc(sizeof (struct mmc_ioc_multi_cmd) +
  1675. RPMB_MULTI_CMD_MAX_CMDS * sizeof (struct mmc_ioc_cmd));
  1676. if (!mioc) {
  1677. return -ENOMEM;
  1678. }
  1679. rpmb_type = be16toh(frame_in->req_resp);
  1680. switch(rpmb_type) {
  1681. case MMC_RPMB_WRITE:
  1682. case MMC_RPMB_WRITE_KEY:
  1683. if (out_cnt != 1) {
  1684. err = -EINVAL;
  1685. goto out;
  1686. }
  1687. mioc->num_of_cmds = 3;
  1688. /* Write request */
  1689. ioc = &mioc->cmds[0];
  1690. set_single_cmd(ioc, MMC_WRITE_MULTIPLE_BLOCK, (1 << 31) | 1, 1);
  1691. mmc_ioc_cmd_set_data((*ioc), frame_in);
  1692. /* Result request */
  1693. ioc = &mioc->cmds[1];
  1694. frame_status.req_resp = htobe16(MMC_RPMB_READ_RESP);
  1695. set_single_cmd(ioc, MMC_WRITE_MULTIPLE_BLOCK, 1, 1);
  1696. mmc_ioc_cmd_set_data((*ioc), &frame_status);
  1697. /* Get response */
  1698. ioc = &mioc->cmds[2];
  1699. set_single_cmd(ioc, MMC_READ_MULTIPLE_BLOCK, 0, 1);
  1700. mmc_ioc_cmd_set_data((*ioc), frame_out);
  1701. break;
  1702. case MMC_RPMB_READ_CNT:
  1703. if (out_cnt != 1) {
  1704. err = -EINVAL;
  1705. goto out;
  1706. }
  1707. /* fall through */
  1708. case MMC_RPMB_READ:
  1709. mioc->num_of_cmds = 2;
  1710. /* Read request */
  1711. ioc = &mioc->cmds[0];
  1712. set_single_cmd(ioc, MMC_WRITE_MULTIPLE_BLOCK, 1, 1);
  1713. mmc_ioc_cmd_set_data((*ioc), frame_in);
  1714. /* Get response */
  1715. ioc = &mioc->cmds[1];
  1716. set_single_cmd(ioc, MMC_READ_MULTIPLE_BLOCK, 0, out_cnt);
  1717. mmc_ioc_cmd_set_data((*ioc), frame_out);
  1718. break;
  1719. default:
  1720. err = -EINVAL;
  1721. goto out;
  1722. }
  1723. err = ioctl(fd, MMC_IOC_MULTI_CMD, mioc);
  1724. out:
  1725. free(mioc);
  1726. return err;
  1727. #endif /* !MMC_IOC_MULTI_CMD */
  1728. }
  1729. int do_rpmb_write_key(int nargs, char **argv)
  1730. {
  1731. int ret, dev_fd, key_fd;
  1732. struct rpmb_frame frame_in = {
  1733. .req_resp = htobe16(MMC_RPMB_WRITE_KEY)
  1734. }, frame_out;
  1735. if (nargs != 3) {
  1736. fprintf(stderr, "Usage: mmc rpmb write-key </path/to/mmcblkXrpmb> </path/to/key>\n");
  1737. exit(1);
  1738. }
  1739. dev_fd = open(argv[1], O_RDWR);
  1740. if (dev_fd < 0) {
  1741. perror("device open");
  1742. exit(1);
  1743. }
  1744. if (0 == strcmp(argv[2], "-"))
  1745. key_fd = STDIN_FILENO;
  1746. else {
  1747. key_fd = open(argv[2], O_RDONLY);
  1748. if (key_fd < 0) {
  1749. perror("can't open key file");
  1750. exit(1);
  1751. }
  1752. }
  1753. /* Read the auth key */
  1754. ret = DO_IO(read, key_fd, frame_in.key_mac, sizeof(frame_in.key_mac));
  1755. if (ret < 0) {
  1756. perror("read the key");
  1757. exit(1);
  1758. } else if (ret != sizeof(frame_in.key_mac)) {
  1759. printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
  1760. (unsigned long)sizeof(frame_in.key_mac),
  1761. ret);
  1762. exit(1);
  1763. }
  1764. /* Execute RPMB op */
  1765. ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
  1766. if (ret != 0) {
  1767. perror("RPMB ioctl failed");
  1768. exit(1);
  1769. }
  1770. /* Check RPMB response */
  1771. if (frame_out.result != 0) {
  1772. printf("RPMB operation failed, retcode 0x%04x\n",
  1773. be16toh(frame_out.result));
  1774. exit(1);
  1775. }
  1776. close(dev_fd);
  1777. if (key_fd != STDIN_FILENO)
  1778. close(key_fd);
  1779. return ret;
  1780. }
  1781. int rpmb_read_counter(int dev_fd, unsigned int *cnt)
  1782. {
  1783. int ret;
  1784. struct rpmb_frame frame_in = {
  1785. .req_resp = htobe16(MMC_RPMB_READ_CNT)
  1786. }, frame_out;
  1787. /* Execute RPMB op */
  1788. ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
  1789. if (ret != 0) {
  1790. perror("RPMB ioctl failed");
  1791. exit(1);
  1792. }
  1793. /* Check RPMB response */
  1794. if (frame_out.result != 0)
  1795. return be16toh(frame_out.result);
  1796. *cnt = be32toh(frame_out.write_counter);
  1797. return 0;
  1798. }
  1799. int do_rpmb_read_counter(int nargs, char **argv)
  1800. {
  1801. int ret, dev_fd;
  1802. unsigned int cnt;
  1803. if (nargs != 2) {
  1804. fprintf(stderr, "Usage: mmc rpmb read-counter </path/to/mmcblkXrpmb>\n");
  1805. exit(1);
  1806. }
  1807. dev_fd = open(argv[1], O_RDWR);
  1808. if (dev_fd < 0) {
  1809. perror("device open");
  1810. exit(1);
  1811. }
  1812. ret = rpmb_read_counter(dev_fd, &cnt);
  1813. /* Check RPMB response */
  1814. if (ret != 0) {
  1815. printf("RPMB operation failed, retcode 0x%04x\n", ret);
  1816. exit(1);
  1817. }
  1818. close(dev_fd);
  1819. printf("Counter value: 0x%08x\n", cnt);
  1820. return ret;
  1821. }
  1822. int do_rpmb_read_block(int nargs, char **argv)
  1823. {
  1824. int i, ret, dev_fd, data_fd, key_fd = -1;
  1825. uint16_t addr;
  1826. /*
  1827. * for reading RPMB, number of blocks is set by CMD23 only, the packet
  1828. * frame field for that is set to 0. So, the type is not u16 but uint!
  1829. */
  1830. unsigned int blocks_cnt;
  1831. unsigned char key[32];
  1832. struct rpmb_frame frame_in = {
  1833. .req_resp = htobe16(MMC_RPMB_READ),
  1834. }, *frame_out_p;
  1835. if (nargs != 5 && nargs != 6) {
  1836. fprintf(stderr, "Usage: mmc rpmb read-block </path/to/mmcblkXrpmb> <address> <blocks count> </path/to/output_file> [/path/to/key]\n");
  1837. exit(1);
  1838. }
  1839. dev_fd = open(argv[1], O_RDWR);
  1840. if (dev_fd < 0) {
  1841. perror("device open");
  1842. exit(1);
  1843. }
  1844. /* Get block address */
  1845. errno = 0;
  1846. addr = strtol(argv[2], NULL, 0);
  1847. if (errno) {
  1848. perror("incorrect address");
  1849. exit(1);
  1850. }
  1851. frame_in.addr = htobe16(addr);
  1852. /* Get blocks count */
  1853. errno = 0;
  1854. blocks_cnt = strtol(argv[3], NULL, 0);
  1855. if (errno) {
  1856. perror("incorrect blocks count");
  1857. exit(1);
  1858. }
  1859. if (!blocks_cnt) {
  1860. printf("please, specify valid blocks count number\n");
  1861. exit(1);
  1862. }
  1863. frame_out_p = calloc(sizeof(*frame_out_p), blocks_cnt);
  1864. if (!frame_out_p) {
  1865. printf("can't allocate memory for RPMB outer frames\n");
  1866. exit(1);
  1867. }
  1868. /* Write 256b data */
  1869. if (0 == strcmp(argv[4], "-"))
  1870. data_fd = STDOUT_FILENO;
  1871. else {
  1872. data_fd = open(argv[4], O_WRONLY | O_CREAT | O_APPEND,
  1873. S_IRUSR | S_IWUSR);
  1874. if (data_fd < 0) {
  1875. perror("can't open output file");
  1876. exit(1);
  1877. }
  1878. }
  1879. /* Key is specified */
  1880. if (nargs == 6) {
  1881. if (0 == strcmp(argv[5], "-"))
  1882. key_fd = STDIN_FILENO;
  1883. else {
  1884. key_fd = open(argv[5], O_RDONLY);
  1885. if (key_fd < 0) {
  1886. perror("can't open input key file");
  1887. exit(1);
  1888. }
  1889. }
  1890. ret = DO_IO(read, key_fd, key, sizeof(key));
  1891. if (ret < 0) {
  1892. perror("read the key data");
  1893. exit(1);
  1894. } else if (ret != sizeof(key)) {
  1895. printf("Data must be %lu bytes length, but we read only %d, exit\n",
  1896. (unsigned long)sizeof(key),
  1897. ret);
  1898. exit(1);
  1899. }
  1900. }
  1901. /* Execute RPMB op */
  1902. ret = do_rpmb_op(dev_fd, &frame_in, frame_out_p, blocks_cnt);
  1903. if (ret != 0) {
  1904. perror("RPMB ioctl failed");
  1905. exit(1);
  1906. }
  1907. /* Check RPMB response */
  1908. if (frame_out_p[blocks_cnt - 1].result != 0) {
  1909. printf("RPMB operation failed, retcode 0x%04x\n",
  1910. be16toh(frame_out_p[blocks_cnt - 1].result));
  1911. exit(1);
  1912. }
  1913. /* Do we have to verify data against key? */
  1914. if (nargs == 6) {
  1915. unsigned char mac[32];
  1916. hmac_sha256_ctx ctx;
  1917. struct rpmb_frame *frame_out = NULL;
  1918. hmac_sha256_init(&ctx, key, sizeof(key));
  1919. for (i = 0; i < blocks_cnt; i++) {
  1920. frame_out = &frame_out_p[i];
  1921. hmac_sha256_update(&ctx, frame_out->data,
  1922. sizeof(*frame_out) -
  1923. offsetof(struct rpmb_frame, data));
  1924. }
  1925. hmac_sha256_final(&ctx, mac, sizeof(mac));
  1926. /* Impossible */
  1927. assert(frame_out);
  1928. /* Compare calculated MAC and MAC from last frame */
  1929. if (memcmp(mac, frame_out->key_mac, sizeof(mac))) {
  1930. printf("RPMB MAC missmatch\n");
  1931. exit(1);
  1932. }
  1933. }
  1934. /* Write data */
  1935. for (i = 0; i < blocks_cnt; i++) {
  1936. struct rpmb_frame *frame_out = &frame_out_p[i];
  1937. ret = DO_IO(write, data_fd, frame_out->data, sizeof(frame_out->data));
  1938. if (ret < 0) {
  1939. perror("write the data");
  1940. exit(1);
  1941. } else if (ret != sizeof(frame_out->data)) {
  1942. printf("Data must be %lu bytes length, but we wrote only %d, exit\n",
  1943. (unsigned long)sizeof(frame_out->data),
  1944. ret);
  1945. exit(1);
  1946. }
  1947. }
  1948. free(frame_out_p);
  1949. close(dev_fd);
  1950. if (data_fd != STDOUT_FILENO)
  1951. close(data_fd);
  1952. if (key_fd != -1 && key_fd != STDIN_FILENO)
  1953. close(key_fd);
  1954. return ret;
  1955. }
  1956. int do_rpmb_write_block(int nargs, char **argv)
  1957. {
  1958. int ret, dev_fd, key_fd, data_fd;
  1959. unsigned char key[32];
  1960. uint16_t addr;
  1961. unsigned int cnt;
  1962. struct rpmb_frame frame_in = {
  1963. .req_resp = htobe16(MMC_RPMB_WRITE),
  1964. .block_count = htobe16(1)
  1965. }, frame_out;
  1966. if (nargs != 5) {
  1967. fprintf(stderr, "Usage: mmc rpmb write-block </path/to/mmcblkXrpmb> <address> </path/to/input_file> </path/to/key>\n");
  1968. exit(1);
  1969. }
  1970. dev_fd = open(argv[1], O_RDWR);
  1971. if (dev_fd < 0) {
  1972. perror("device open");
  1973. exit(1);
  1974. }
  1975. ret = rpmb_read_counter(dev_fd, &cnt);
  1976. /* Check RPMB response */
  1977. if (ret != 0) {
  1978. printf("RPMB read counter operation failed, retcode 0x%04x\n", ret);
  1979. exit(1);
  1980. }
  1981. frame_in.write_counter = htobe32(cnt);
  1982. /* Get block address */
  1983. errno = 0;
  1984. addr = strtol(argv[2], NULL, 0);
  1985. if (errno) {
  1986. perror("incorrect address");
  1987. exit(1);
  1988. }
  1989. frame_in.addr = htobe16(addr);
  1990. /* Read 256b data */
  1991. if (0 == strcmp(argv[3], "-"))
  1992. data_fd = STDIN_FILENO;
  1993. else {
  1994. data_fd = open(argv[3], O_RDONLY);
  1995. if (data_fd < 0) {
  1996. perror("can't open input file");
  1997. exit(1);
  1998. }
  1999. }
  2000. ret = DO_IO(read, data_fd, frame_in.data, sizeof(frame_in.data));
  2001. if (ret < 0) {
  2002. perror("read the data");
  2003. exit(1);
  2004. } else if (ret != sizeof(frame_in.data)) {
  2005. printf("Data must be %lu bytes length, but we read only %d, exit\n",
  2006. (unsigned long)sizeof(frame_in.data),
  2007. ret);
  2008. exit(1);
  2009. }
  2010. /* Read the auth key */
  2011. if (0 == strcmp(argv[4], "-"))
  2012. key_fd = STDIN_FILENO;
  2013. else {
  2014. key_fd = open(argv[4], O_RDONLY);
  2015. if (key_fd < 0) {
  2016. perror("can't open key file");
  2017. exit(1);
  2018. }
  2019. }
  2020. ret = DO_IO(read, key_fd, key, sizeof(key));
  2021. if (ret < 0) {
  2022. perror("read the key");
  2023. exit(1);
  2024. } else if (ret != sizeof(key)) {
  2025. printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
  2026. (unsigned long)sizeof(key),
  2027. ret);
  2028. exit(1);
  2029. }
  2030. /* Calculate HMAC SHA256 */
  2031. hmac_sha256(
  2032. key, sizeof(key),
  2033. frame_in.data, sizeof(frame_in) - offsetof(struct rpmb_frame, data),
  2034. frame_in.key_mac, sizeof(frame_in.key_mac));
  2035. /* Execute RPMB op */
  2036. ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
  2037. if (ret != 0) {
  2038. perror("RPMB ioctl failed");
  2039. exit(1);
  2040. }
  2041. /* Check RPMB response */
  2042. if (frame_out.result != 0) {
  2043. printf("RPMB operation failed, retcode 0x%04x\n",
  2044. be16toh(frame_out.result));
  2045. exit(1);
  2046. }
  2047. close(dev_fd);
  2048. if (data_fd != STDIN_FILENO)
  2049. close(data_fd);
  2050. if (key_fd != STDIN_FILENO)
  2051. close(key_fd);
  2052. return ret;
  2053. }
  2054. int do_cache_ctrl(int value, int nargs, char **argv)
  2055. {
  2056. __u8 ext_csd[512];
  2057. int fd, ret;
  2058. char *device;
  2059. if (nargs != 2) {
  2060. fprintf(stderr, "Usage: mmc cache enable </path/to/mmcblkX>\n");
  2061. exit(1);
  2062. }
  2063. device = argv[1];
  2064. fd = open(device, O_RDWR);
  2065. if (fd < 0) {
  2066. perror("open");
  2067. exit(1);
  2068. }
  2069. ret = read_extcsd(fd, ext_csd);
  2070. if (ret) {
  2071. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  2072. exit(1);
  2073. }
  2074. if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V4_5) {
  2075. fprintf(stderr,
  2076. "The CACHE option is only availabe on devices >= "
  2077. "MMC 4.5 %s\n", device);
  2078. exit(1);
  2079. }
  2080. /* If the cache size is zero, this device does not have a cache */
  2081. if (!(ext_csd[EXT_CSD_CACHE_SIZE_3] ||
  2082. ext_csd[EXT_CSD_CACHE_SIZE_2] ||
  2083. ext_csd[EXT_CSD_CACHE_SIZE_1] ||
  2084. ext_csd[EXT_CSD_CACHE_SIZE_0])) {
  2085. fprintf(stderr,
  2086. "The CACHE option is not available on %s\n",
  2087. device);
  2088. exit(1);
  2089. }
  2090. ret = write_extcsd_value(fd, EXT_CSD_CACHE_CTRL, value);
  2091. if (ret) {
  2092. fprintf(stderr,
  2093. "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
  2094. value, EXT_CSD_CACHE_CTRL, device);
  2095. exit(1);
  2096. }
  2097. return ret;
  2098. }
  2099. int do_cache_en(int nargs, char **argv)
  2100. {
  2101. return do_cache_ctrl(1, nargs, argv);
  2102. }
  2103. int do_cache_dis(int nargs, char **argv)
  2104. {
  2105. return do_cache_ctrl(0, nargs, argv);
  2106. }
  2107. int do_ffu(int nargs, char **argv)
  2108. {
  2109. #ifndef MMC_IOC_MULTI_CMD
  2110. fprintf(stderr, "mmc-utils has been compiled without MMC_IOC_MULTI_CMD"
  2111. " support, needed by FFU.\n");
  2112. exit(1);
  2113. #else
  2114. int dev_fd, img_fd;
  2115. int sect_done = 0, retry = 3, ret = -EINVAL;
  2116. unsigned int sect_size;
  2117. __u8 ext_csd[512];
  2118. __u8 *buf;
  2119. __u32 arg;
  2120. off_t fw_size;
  2121. ssize_t chunk_size;
  2122. char *device;
  2123. struct mmc_ioc_multi_cmd *multi_cmd;
  2124. if (nargs != 3) {
  2125. fprintf(stderr, "Usage: ffu <image name> </path/to/mmcblkX> \n");
  2126. exit(1);
  2127. }
  2128. device = argv[2];
  2129. dev_fd = open(device, O_RDWR);
  2130. if (dev_fd < 0) {
  2131. perror("device open failed");
  2132. exit(1);
  2133. }
  2134. img_fd = open(argv[1], O_RDONLY);
  2135. if (img_fd < 0) {
  2136. perror("image open failed");
  2137. close(dev_fd);
  2138. exit(1);
  2139. }
  2140. buf = malloc(512);
  2141. multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) +
  2142. 3 * sizeof(struct mmc_ioc_cmd));
  2143. if (!buf || !multi_cmd) {
  2144. perror("failed to allocate memory");
  2145. goto out;
  2146. }
  2147. ret = read_extcsd(dev_fd, ext_csd);
  2148. if (ret) {
  2149. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  2150. goto out;
  2151. }
  2152. if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V5_0) {
  2153. fprintf(stderr,
  2154. "The FFU feature is only available on devices >= "
  2155. "MMC 5.0, not supported in %s\n", device);
  2156. goto out;
  2157. }
  2158. if (!(ext_csd[EXT_CSD_SUPPORTED_MODES] & EXT_CSD_FFU)) {
  2159. fprintf(stderr, "FFU is not supported in %s\n", device);
  2160. goto out;
  2161. }
  2162. if (ext_csd[EXT_CSD_FW_CONFIG] & EXT_CSD_UPDATE_DISABLE) {
  2163. fprintf(stderr, "Firmware update was disabled in %s\n", device);
  2164. goto out;
  2165. }
  2166. fw_size = lseek(img_fd, 0, SEEK_END);
  2167. if (fw_size == 0) {
  2168. fprintf(stderr, "Firmware image is empty");
  2169. goto out;
  2170. }
  2171. sect_size = (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 0) ? 512 : 4096;
  2172. if (fw_size % sect_size) {
  2173. fprintf(stderr, "Firmware data size (%jd) is not aligned!\n", (intmax_t)fw_size);
  2174. goto out;
  2175. }
  2176. /* set CMD ARG */
  2177. arg = ext_csd[EXT_CSD_FFU_ARG_0] |
  2178. ext_csd[EXT_CSD_FFU_ARG_1] << 8 |
  2179. ext_csd[EXT_CSD_FFU_ARG_2] << 16 |
  2180. ext_csd[EXT_CSD_FFU_ARG_3] << 24;
  2181. /* prepare multi_cmd to be sent */
  2182. multi_cmd->num_of_cmds = 3;
  2183. /* put device into ffu mode */
  2184. multi_cmd->cmds[0].opcode = MMC_SWITCH;
  2185. multi_cmd->cmds[0].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
  2186. (EXT_CSD_MODE_CONFIG << 16) |
  2187. (EXT_CSD_FFU_MODE << 8) |
  2188. EXT_CSD_CMD_SET_NORMAL;
  2189. multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
  2190. multi_cmd->cmds[0].write_flag = 1;
  2191. /* send image chunk */
  2192. multi_cmd->cmds[1].opcode = MMC_WRITE_BLOCK;
  2193. multi_cmd->cmds[1].blksz = sect_size;
  2194. multi_cmd->cmds[1].blocks = 1;
  2195. multi_cmd->cmds[1].arg = arg;
  2196. multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
  2197. multi_cmd->cmds[1].write_flag = 1;
  2198. mmc_ioc_cmd_set_data(multi_cmd->cmds[1], buf);
  2199. /* return device into normal mode */
  2200. multi_cmd->cmds[2].opcode = MMC_SWITCH;
  2201. multi_cmd->cmds[2].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
  2202. (EXT_CSD_MODE_CONFIG << 16) |
  2203. (EXT_CSD_NORMAL_MODE << 8) |
  2204. EXT_CSD_CMD_SET_NORMAL;
  2205. multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
  2206. multi_cmd->cmds[2].write_flag = 1;
  2207. do_retry:
  2208. /* read firmware chunk */
  2209. lseek(img_fd, 0, SEEK_SET);
  2210. chunk_size = read(img_fd, buf, 512);
  2211. while (chunk_size > 0) {
  2212. /* send ioctl with multi-cmd */
  2213. ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);
  2214. if (ret) {
  2215. perror("Multi-cmd ioctl");
  2216. /* In case multi-cmd ioctl failed before exiting from ffu mode */
  2217. ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[2]);
  2218. goto out;
  2219. }
  2220. ret = read_extcsd(dev_fd, ext_csd);
  2221. if (ret) {
  2222. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  2223. goto out;
  2224. }
  2225. /* Test if we need to restart the download */
  2226. sect_done = ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_0] |
  2227. ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_1] << 8 |
  2228. ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_2] << 16 |
  2229. ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_3] << 24;
  2230. /* By spec, host should re-start download from the first sector if sect_done is 0 */
  2231. if (sect_done == 0) {
  2232. if (retry > 0) {
  2233. retry--;
  2234. fprintf(stderr, "Programming failed. Retrying... (%d)\n", retry);
  2235. goto do_retry;
  2236. }
  2237. fprintf(stderr, "Programming failed! Aborting...\n");
  2238. goto out;
  2239. } else {
  2240. fprintf(stderr, "Programmed %d/%jd bytes\r", sect_done * sect_size, (intmax_t)fw_size);
  2241. }
  2242. /* read the next firmware chunk (if any) */
  2243. chunk_size = read(img_fd, buf, 512);
  2244. }
  2245. if ((sect_done * sect_size) == fw_size) {
  2246. fprintf(stderr, "Programmed %jd/%jd bytes\n", (intmax_t)fw_size, (intmax_t)fw_size);
  2247. fprintf(stderr, "Programming finished with status %d \n", ret);
  2248. }
  2249. else {
  2250. fprintf(stderr, "FW size and number of sectors written mismatch. Status return %d\n", ret);
  2251. goto out;
  2252. }
  2253. /* check mode operation for ffu install*/
  2254. if (!ext_csd[EXT_CSD_FFU_FEATURES]) {
  2255. fprintf(stderr, "Please reboot to complete firmware installation on %s\n", device);
  2256. } else {
  2257. fprintf(stderr, "Installing firmware on %s...\n", device);
  2258. /* Re-enter ffu mode and install the firmware */
  2259. multi_cmd->num_of_cmds = 2;
  2260. /* set ext_csd to install mode */
  2261. multi_cmd->cmds[1].opcode = MMC_SWITCH;
  2262. multi_cmd->cmds[1].blksz = 0;
  2263. multi_cmd->cmds[1].blocks = 0;
  2264. multi_cmd->cmds[1].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
  2265. (EXT_CSD_MODE_OPERATION_CODES << 16) |
  2266. (EXT_CSD_FFU_INSTALL << 8) |
  2267. EXT_CSD_CMD_SET_NORMAL;
  2268. multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
  2269. multi_cmd->cmds[1].write_flag = 1;
  2270. /* send ioctl with multi-cmd */
  2271. ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);
  2272. if (ret) {
  2273. perror("Multi-cmd ioctl failed setting install mode");
  2274. /* In case multi-cmd ioctl failed before exiting from ffu mode */
  2275. ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[2]);
  2276. goto out;
  2277. }
  2278. ret = read_extcsd(dev_fd, ext_csd);
  2279. if (ret) {
  2280. fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
  2281. goto out;
  2282. }
  2283. /* return status */
  2284. ret = ext_csd[EXT_CSD_FFU_STATUS];
  2285. if (ret) {
  2286. fprintf(stderr, "%s: error %d during FFU install:\n", device, ret);
  2287. goto out;
  2288. } else {
  2289. fprintf(stderr, "FFU finished successfully\n");
  2290. }
  2291. }
  2292. out:
  2293. free(buf);
  2294. free(multi_cmd);
  2295. close(img_fd);
  2296. close(dev_fd);
  2297. return ret;
  2298. #endif
  2299. }