blob: 4aa0a111f39cab4b279db9d0e807ad4070e349f1 [file] [log] [blame]
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -05001/*
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
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/ioctl.h>
21#include <sys/types.h>
22#include <dirent.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <libgen.h>
27#include <limits.h>
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050028#include <ctype.h>
Roman Peniaevc6cb0532014-08-12 23:25:45 +090029#include <errno.h>
30#include <stdint.h>
31#include <assert.h>
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050032
33#include "mmc.h"
34#include "mmc_cmds.h"
Roman Peniaevc6cb0532014-08-12 23:25:45 +090035#include "3rdparty/hmac_sha/hmac_sha2.h"
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -050036
37int read_extcsd(int fd, __u8 *ext_csd)
38{
39 int ret = 0;
40 struct mmc_ioc_cmd idata;
41 memset(&idata, 0, sizeof(idata));
42 memset(ext_csd, 0, sizeof(__u8) * 512);
43 idata.write_flag = 0;
44 idata.opcode = MMC_SEND_EXT_CSD;
45 idata.arg = 0;
46 idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
47 idata.blksz = 512;
48 idata.blocks = 1;
49 mmc_ioc_cmd_set_data(idata, ext_csd);
50
51 ret = ioctl(fd, MMC_IOC_CMD, &idata);
52 if (ret)
53 perror("ioctl");
54
55 return ret;
56}
57
58int write_extcsd_value(int fd, __u8 index, __u8 value)
59{
60 int ret = 0;
61 struct mmc_ioc_cmd idata;
62
63 memset(&idata, 0, sizeof(idata));
64 idata.write_flag = 1;
65 idata.opcode = MMC_SWITCH;
66 idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
67 (index << 16) |
68 (value << 8) |
69 EXT_CSD_CMD_SET_NORMAL;
70 idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
71
72 ret = ioctl(fd, MMC_IOC_CMD, &idata);
73 if (ret)
74 perror("ioctl");
75
76 return ret;
77}
78
Ben Gardiner27c357d2013-05-30 17:12:47 -040079int send_status(int fd, __u32 *response)
80{
81 int ret = 0;
82 struct mmc_ioc_cmd idata;
83
84 memset(&idata, 0, sizeof(idata));
85 idata.opcode = MMC_SEND_STATUS;
86 idata.arg = (1 << 16);
87 idata.flags = MMC_RSP_R1 | MMC_CMD_AC;
88
89 ret = ioctl(fd, MMC_IOC_CMD, &idata);
90 if (ret)
91 perror("ioctl");
92
93 *response = idata.response[0];
94
95 return ret;
96}
97
Chris Ballb9c7a172012-02-20 12:34:25 -050098void print_writeprotect_status(__u8 *ext_csd)
99{
100 __u8 reg;
Al Cooperd0b46442015-04-29 18:12:35 -0400101 __u8 ext_csd_rev = ext_csd[EXT_CSD_REV];
Chris Ballb9c7a172012-02-20 12:34:25 -0500102
103 /* A43: reserved [174:0] */
104 if (ext_csd_rev >= 5) {
105 printf("Boot write protection status registers"
106 " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
107
108 reg = ext_csd[EXT_CSD_BOOT_WP];
109 printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
110 printf(" Power ro locking: ");
111 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
112 printf("not possible\n");
113 else
114 printf("possible\n");
115
116 printf(" Permanent ro locking: ");
117 if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
118 printf("not possible\n");
119 else
120 printf("possible\n");
121
122 printf(" ro lock status: ");
123 if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
124 printf("locked until next power on\n");
125 else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
126 printf("locked permanently\n");
127 else
128 printf("not locked\n");
129 }
130}
131
132int do_writeprotect_get(int nargs, char **argv)
133{
134 __u8 ext_csd[512];
135 int fd, ret;
136 char *device;
137
Chris Ball8ba44662012-04-19 13:22:54 -0400138 CHECK(nargs != 2, "Usage: mmc writeprotect get </path/to/mmcblkX>\n",
139 exit(1));
Chris Ballb9c7a172012-02-20 12:34:25 -0500140
141 device = argv[1];
142
143 fd = open(device, O_RDWR);
144 if (fd < 0) {
145 perror("open");
146 exit(1);
147 }
148
149 ret = read_extcsd(fd, ext_csd);
150 if (ret) {
151 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
152 exit(1);
153 }
154
155 print_writeprotect_status(ext_csd);
156
157 return ret;
158}
159
160int do_writeprotect_set(int nargs, char **argv)
161{
162 __u8 ext_csd[512], value;
163 int fd, ret;
164 char *device;
165
Chris Ball8ba44662012-04-19 13:22:54 -0400166 CHECK(nargs != 2, "Usage: mmc writeprotect set </path/to/mmcblkX>\n",
167 exit(1));
Chris Ballb9c7a172012-02-20 12:34:25 -0500168
169 device = argv[1];
170
171 fd = open(device, O_RDWR);
172 if (fd < 0) {
173 perror("open");
174 exit(1);
175 }
176
177 ret = read_extcsd(fd, ext_csd);
178 if (ret) {
179 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
180 exit(1);
181 }
182
183 value = ext_csd[EXT_CSD_BOOT_WP] |
184 EXT_CSD_BOOT_WP_B_PWR_WP_EN;
185 ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
186 if (ret) {
187 fprintf(stderr, "Could not write 0x%02x to "
188 "EXT_CSD[%d] in %s\n",
189 value, EXT_CSD_BOOT_WP, device);
190 exit(1);
191 }
192
193 return ret;
194}
195
Saugata Dasb7e25992012-05-17 09:26:34 -0400196int do_disable_512B_emulation(int nargs, char **argv)
197{
198 __u8 ext_csd[512], native_sector_size, data_sector_size, wr_rel_param;
199 int fd, ret;
200 char *device;
201
202 CHECK(nargs != 2, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n", exit(1));
203 device = argv[1];
204
205 fd = open(device, O_RDWR);
206 if (fd < 0) {
207 perror("open");
208 exit(1);
209 }
210
211 ret = read_extcsd(fd, ext_csd);
212 if (ret) {
213 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
214 exit(1);
215 }
216
217 wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
218 native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE];
219 data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE];
220
221 if (native_sector_size && !data_sector_size &&
222 (wr_rel_param & EN_REL_WR)) {
223 ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1);
224
225 if (ret) {
226 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
227 1, EXT_CSD_BOOT_WP, device);
228 exit(1);
229 }
230 printf("MMC disable 512B emulation successful. Now reset the device to switch to 4KB native sector mode.\n");
231 } else if (native_sector_size && data_sector_size) {
232 printf("MMC 512B emulation mode is already disabled; doing nothing.\n");
233 } else {
234 printf("MMC does not support disabling 512B emulation mode.\n");
235 }
236
237 return ret;
238}
239
Giuseppe CAVALLARO7bd13202012-04-19 10:58:37 +0200240int do_write_boot_en(int nargs, char **argv)
241{
242 __u8 ext_csd[512];
243 __u8 value = 0;
244 int fd, ret;
245 char *device;
246 int boot_area, send_ack;
247
248 CHECK(nargs != 4, "Usage: mmc bootpart enable <partition_number> "
249 "<send_ack> </path/to/mmcblkX>\n", exit(1));
250
251 /*
252 * If <send_ack> is 1, the device will send acknowledgment
253 * pattern "010" to the host when boot operation begins.
254 * If <send_ack> is 0, it won't.
255 */
256 boot_area = strtol(argv[1], NULL, 10);
257 send_ack = strtol(argv[2], NULL, 10);
258 device = argv[3];
259
260 fd = open(device, O_RDWR);
261 if (fd < 0) {
262 perror("open");
263 exit(1);
264 }
265
266 ret = read_extcsd(fd, ext_csd);
267 if (ret) {
268 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
269 exit(1);
270 }
271
272 value = ext_csd[EXT_CSD_PART_CONFIG];
273
274 switch (boot_area) {
275 case EXT_CSD_PART_CONFIG_ACC_BOOT0:
276 value |= (1 << 3);
277 value &= ~(3 << 4);
278 break;
279 case EXT_CSD_PART_CONFIG_ACC_BOOT1:
280 value |= (1 << 4);
281 value &= ~(1 << 3);
282 value &= ~(1 << 5);
283 break;
284 case EXT_CSD_PART_CONFIG_ACC_USER_AREA:
285 value |= (boot_area << 3);
286 break;
287 default:
288 fprintf(stderr, "Cannot enable the boot area\n");
289 exit(1);
290 }
291 if (send_ack)
292 value |= EXT_CSD_PART_CONFIG_ACC_ACK;
293 else
294 value &= ~EXT_CSD_PART_CONFIG_ACC_ACK;
295
296 ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value);
297 if (ret) {
298 fprintf(stderr, "Could not write 0x%02x to "
299 "EXT_CSD[%d] in %s\n",
300 value, EXT_CSD_PART_CONFIG, device);
301 exit(1);
302 }
303 return ret;
304}
305
Al Cooper64c2de82015-05-01 08:24:37 -0400306int do_boot_bus_conditions_set(int nargs, char **argv)
307{
308 __u8 ext_csd[512];
309 __u8 value = 0;
310 int fd, ret;
311 char *device;
312
313 CHECK(nargs != 5, "Usage: mmc: bootbus set <boot_mode> "
314 "<reset_boot_bus_conditions> <boot_bus_width> <device>\n",
315 exit(1));
316
317 if (strcmp(argv[1], "single_backward") == 0)
318 value |= 0;
319 else if (strcmp(argv[1], "single_hs") == 0)
320 value |= 0x8;
321 else if (strcmp(argv[1], "dual") == 0)
322 value |= 0x10;
323 else {
324 fprintf(stderr, "illegal <boot_mode> specified\n");
325 exit(1);
326 }
327
328 if (strcmp(argv[2], "x1") == 0)
329 value |= 0;
330 else if (strcmp(argv[2], "retain") == 0)
331 value |= 0x4;
332 else {
333 fprintf(stderr,
334 "illegal <reset_boot_bus_conditions> specified\n");
335 exit(1);
336 }
337
338 if (strcmp(argv[3], "x1") == 0)
339 value |= 0;
340 else if (strcmp(argv[3], "x4") == 0)
341 value |= 0x1;
342 else if (strcmp(argv[3], "x8") == 0)
343 value |= 0x2;
344 else {
345 fprintf(stderr, "illegal <boot_bus_width> specified\n");
346 exit(1);
347 }
348
349 device = argv[4];
350 fd = open(device, O_RDWR);
351 if (fd < 0) {
352 perror("open");
353 exit(1);
354 }
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 printf("Changing ext_csd[BOOT_BUS_CONDITIONS] from 0x%02x to 0x%02x\n",
362 ext_csd[EXT_CSD_BOOT_BUS_CONDITIONS], value);
363
364 ret = write_extcsd_value(fd, EXT_CSD_BOOT_BUS_CONDITIONS, value);
365 if (ret) {
366 fprintf(stderr, "Could not write 0x%02x to "
367 "EXT_CSD[%d] in %s\n",
368 value, EXT_CSD_BOOT_BUS_CONDITIONS, device);
369 exit(1);
370 }
371 close(fd);
372 return ret;
373}
374
Chris Ballf74dfe22012-10-19 16:49:55 -0400375int do_hwreset(int value, int nargs, char **argv)
376{
377 __u8 ext_csd[512];
378 int fd, ret;
379 char *device;
380
381 CHECK(nargs != 2, "Usage: mmc hwreset enable </path/to/mmcblkX>\n",
382 exit(1));
383
384 device = argv[1];
385
386 fd = open(device, O_RDWR);
387 if (fd < 0) {
388 perror("open");
389 exit(1);
390 }
391
392 ret = read_extcsd(fd, ext_csd);
393 if (ret) {
394 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
395 exit(1);
396 }
397
398 if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
399 EXT_CSD_HW_RESET_EN) {
400 fprintf(stderr,
401 "H/W Reset is already permanently enabled on %s\n",
402 device);
403 exit(1);
404 }
405 if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
406 EXT_CSD_HW_RESET_DIS) {
407 fprintf(stderr,
408 "H/W Reset is already permanently disabled on %s\n",
409 device);
410 exit(1);
411 }
412
413 ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value);
414 if (ret) {
415 fprintf(stderr,
416 "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
417 value, EXT_CSD_RST_N_FUNCTION, device);
418 exit(1);
419 }
420
421 return ret;
422}
423
424int do_hwreset_en(int nargs, char **argv)
425{
426 return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv);
427}
428
429int do_hwreset_dis(int nargs, char **argv)
430{
431 return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv);
432}
433
Jaehoon Chung86496512012-09-21 10:08:05 +0000434int do_write_bkops_en(int nargs, char **argv)
435{
436 __u8 ext_csd[512], value = 0;
437 int fd, ret;
438 char *device;
439
440 CHECK(nargs != 2, "Usage: mmc bkops enable </path/to/mmcblkX>\n",
441 exit(1));
442
443 device = argv[1];
444
445 fd = open(device, O_RDWR);
446 if (fd < 0) {
447 perror("open");
448 exit(1);
449 }
450
451 ret = read_extcsd(fd, ext_csd);
452 if (ret) {
453 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
454 exit(1);
455 }
456
457 if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
458 fprintf(stderr, "%s doesn't support BKOPS\n", device);
459 exit(1);
460 }
461
462 ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_ENABLE);
463 if (ret) {
464 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
465 value, EXT_CSD_BKOPS_EN, device);
466 exit(1);
467 }
468
469 return ret;
470}
471
Ben Gardiner27c357d2013-05-30 17:12:47 -0400472int do_status_get(int nargs, char **argv)
473{
474 __u32 response;
475 int fd, ret;
476 char *device;
477
478 CHECK(nargs != 2, "Usage: mmc status get </path/to/mmcblkX>\n",
479 exit(1));
480
481 device = argv[1];
482
483 fd = open(device, O_RDWR);
484 if (fd < 0) {
485 perror("open");
486 exit(1);
487 }
488
489 ret = send_status(fd, &response);
490 if (ret) {
491 fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device);
492 exit(1);
493 }
494
495 printf("SEND_STATUS response: 0x%08x\n", response);
496
497 return ret;
498}
499
Ben Gardiner4e850232013-05-30 17:12:49 -0400500unsigned int get_sector_count(__u8 *ext_csd)
501{
502 return (ext_csd[EXT_CSD_SEC_COUNT_3] << 24) |
503 (ext_csd[EXT_CSD_SEC_COUNT_2] << 16) |
504 (ext_csd[EXT_CSD_SEC_COUNT_1] << 8) |
505 ext_csd[EXT_CSD_SEC_COUNT_0];
506}
507
508int is_blockaddresed(__u8 *ext_csd)
509{
510 unsigned int sectors = get_sector_count(ext_csd);
511
512 return (sectors > (2u * 1024 * 1024 * 1024) / 512);
513}
514
Ben Gardinerf82e27a2013-05-30 17:12:50 -0400515unsigned int get_hc_wp_grp_size(__u8 *ext_csd)
516{
517 return ext_csd[221];
518}
519
520unsigned int get_hc_erase_grp_size(__u8 *ext_csd)
521{
522 return ext_csd[224];
523}
524
Ben Gardinere6e84e92013-09-19 11:14:27 -0400525int set_partitioning_setting_completed(int dry_run, const char * const device,
526 int fd)
527{
528 int ret;
529
530 if (dry_run) {
531 fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n");
532 fprintf(stderr, "These changes will not take effect neither "
533 "now nor after a power cycle\n");
534 return 1;
535 }
536
537 fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n");
538 ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1);
539 if (ret) {
540 fprintf(stderr, "Could not write 0x1 to "
541 "EXT_CSD[%d] in %s\n",
542 EXT_CSD_PARTITION_SETTING_COMPLETED, device);
543 return 1;
544 }
545
546 __u32 response;
547 ret = send_status(fd, &response);
548 if (ret) {
549 fprintf(stderr, "Could not get response to SEND_STATUS "
550 "from %s\n", device);
551 return 1;
552 }
553
554 if (response & R1_SWITCH_ERROR) {
555 fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED "
556 "failed on %s\n", device);
557 return 1;
558 }
559
560 fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on "
561 "%s SUCCESS\n", device);
562 fprintf(stderr, "Device power cycle needed for settings to "
563 "take effect.\n"
564 "Confirm that PARTITION_SETTING_COMPLETED bit is set "
565 "using 'extcsd read' after power cycle\n");
566
567 return 0;
568}
569
Balaji T K4afc8c82015-04-29 18:12:32 -0400570int check_enhanced_area_total_limit(const char * const device, int fd)
571{
572 __u8 ext_csd[512];
573 __u32 regl;
574 unsigned long max_enh_area_sz, user_area_sz, enh_area_sz = 0;
575 unsigned long gp4_part_sz, gp3_part_sz, gp2_part_sz, gp1_part_sz;
Balaji T K78912362015-04-29 18:12:33 -0400576 unsigned long total_sz, total_gp_user_sz;
Balaji T K4afc8c82015-04-29 18:12:32 -0400577 unsigned int wp_sz, erase_sz;
578 int ret;
579
580 ret = read_extcsd(fd, ext_csd);
581 if (ret) {
582 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
583 exit(1);
584 }
585 wp_sz = get_hc_wp_grp_size(ext_csd);
586 erase_sz = get_hc_erase_grp_size(ext_csd);
587
588 regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_4_2] << 16) |
589 (ext_csd[EXT_CSD_GP_SIZE_MULT_4_1] << 8) |
590 ext_csd[EXT_CSD_GP_SIZE_MULT_4_0];
591 gp4_part_sz = 512l * regl * erase_sz * wp_sz;
592 if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_4) {
593 enh_area_sz += gp4_part_sz;
594 printf("Enhanced GP4 Partition Size [GP_SIZE_MULT_4]: 0x%06x\n", regl);
595 printf(" i.e. %lu KiB\n", gp4_part_sz);
596 }
597
598 regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_3_2] << 16) |
599 (ext_csd[EXT_CSD_GP_SIZE_MULT_3_1] << 8) |
600 ext_csd[EXT_CSD_GP_SIZE_MULT_3_0];
601 gp3_part_sz = 512l * regl * erase_sz * wp_sz;
602 if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_3) {
603 enh_area_sz += gp3_part_sz;
604 printf("Enhanced GP3 Partition Size [GP_SIZE_MULT_3]: 0x%06x\n", regl);
605 printf(" i.e. %lu KiB\n", gp3_part_sz);
606 }
607
608 regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_2_2] << 16) |
609 (ext_csd[EXT_CSD_GP_SIZE_MULT_2_1] << 8) |
610 ext_csd[EXT_CSD_GP_SIZE_MULT_2_0];
611 gp2_part_sz = 512l * regl * erase_sz * wp_sz;
612 if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_2) {
613 enh_area_sz += gp2_part_sz;
614 printf("Enhanced GP2 Partition Size [GP_SIZE_MULT_2]: 0x%06x\n", regl);
615 printf(" i.e. %lu KiB\n", gp2_part_sz);
616 }
617
618 regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_1_2] << 16) |
619 (ext_csd[EXT_CSD_GP_SIZE_MULT_1_1] << 8) |
620 ext_csd[EXT_CSD_GP_SIZE_MULT_1_0];
621 gp1_part_sz = 512l * regl * erase_sz * wp_sz;
622 if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_1) {
623 enh_area_sz += gp1_part_sz;
624 printf("Enhanced GP1 Partition Size [GP_SIZE_MULT_1]: 0x%06x\n", regl);
625 printf(" i.e. %lu KiB\n", gp1_part_sz);
626 }
627
628 regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
629 (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
630 ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
631 user_area_sz = 512l * regl * erase_sz * wp_sz;
632 if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_USR) {
633 enh_area_sz += user_area_sz;
634 printf("Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x%06x\n", regl);
635 printf(" i.e. %lu KiB\n", user_area_sz);
636 }
637
638 regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
639 (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
640 ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
641 max_enh_area_sz = 512l * regl * erase_sz * wp_sz;
642 printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n", regl);
643 printf(" i.e. %lu KiB\n", max_enh_area_sz);
644 if (enh_area_sz > max_enh_area_sz) {
645 fprintf(stderr,
646 "Programmed total enhanced size %lu KiB cannot exceed max enhanced area %lu KiB %s\n",
647 enh_area_sz, max_enh_area_sz, device);
648 return 1;
649 }
Balaji T K78912362015-04-29 18:12:33 -0400650 total_sz = get_sector_count(ext_csd) / 2;
651 total_gp_user_sz = gp4_part_sz + gp3_part_sz + gp2_part_sz +
652 gp1_part_sz + user_area_sz;
653 if (total_gp_user_sz > total_sz) {
654 fprintf(stderr,
655 "requested total partition size %lu KiB cannot exceed card capacity %lu KiB %s\n",
656 total_gp_user_sz, total_sz, device);
657 return 1;
658 }
659
660 return 0;
661}
662
663int do_create_gp_partition(int nargs, char **argv)
664{
665 __u8 value;
666 __u8 ext_csd[512];
667 __u8 address;
668 int fd, ret;
669 char *device;
670 int dry_run = 1;
671 int partition, enh_attr, ext_attr;
672 unsigned int length_kib, gp_size_mult;
673 unsigned long align;
674
675 CHECK(nargs != 7, "Usage: mmc gp create <-y|-n> <length KiB> "
676 "<partition> <enh_attr> <ext_attr> </path/to/mmcblkX>\n", exit(1));
677
678 if (!strcmp("-y", argv[1]))
679 dry_run = 0;
680
681 length_kib = strtol(argv[2], NULL, 10);
682 partition = strtol(argv[3], NULL, 10);
683 enh_attr = strtol(argv[4], NULL, 10);
684 ext_attr = strtol(argv[5], NULL, 10);
685 device = argv[6];
686
687 if (partition < 0 || partition > 4) {
688 printf("Invalid gp parition number valid range [1-4]\n");
689 exit(1);
690 }
691
692 if (enh_attr && ext_attr) {
693 printf("Not allowed to set both enhanced attribute and extended attribute\n");
694 exit(1);
695 }
696
697 fd = open(device, O_RDWR);
698 if (fd < 0) {
699 perror("open");
700 exit(1);
701 }
702
703 ret = read_extcsd(fd, ext_csd);
704 if (ret) {
705 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
706 exit(1);
707 }
708
709 /* assert not PARTITION_SETTING_COMPLETED */
710 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) {
711 printf(" Device is already partitioned\n");
712 exit(1);
713 }
714
715 align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
716 gp_size_mult = (length_kib + align/2l) / align;
717
718 /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
719 ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
720 if (ret) {
721 fprintf(stderr, "Could not write 0x1 to EXT_CSD[%d] in %s\n",
722 EXT_CSD_ERASE_GROUP_DEF, device);
723 exit(1);
724 }
725
726 value = (gp_size_mult >> 16) & 0xff;
727 address = EXT_CSD_GP_SIZE_MULT_1_2 + (partition - 1) * 3;
728 ret = write_extcsd_value(fd, address, value);
729 if (ret) {
730 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
731 value, address, device);
732 exit(1);
733 }
734 value = (gp_size_mult >> 8) & 0xff;
735 address = EXT_CSD_GP_SIZE_MULT_1_1 + (partition - 1) * 3;
736 ret = write_extcsd_value(fd, address, value);
737 if (ret) {
738 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
739 value, address, device);
740 exit(1);
741 }
742 value = gp_size_mult & 0xff;
743 address = EXT_CSD_GP_SIZE_MULT_1_0 + (partition - 1) * 3;
744 ret = write_extcsd_value(fd, address, value);
745 if (ret) {
746 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
747 value, address, device);
748 exit(1);
749 }
750
751 value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
752 if (enh_attr)
753 value |= (1 << partition);
754 else
755 value &= ~(1 << partition);
756
757 ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
758 if (ret) {
759 fprintf(stderr, "Could not write EXT_CSD_ENH_%x to EXT_CSD[%d] in %s\n",
760 partition, EXT_CSD_PARTITIONS_ATTRIBUTE, device);
761 exit(1);
762 }
763
764 address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 + (partition - 1) / 2;
765 value = ext_csd[address];
766 if (ext_attr)
767 value |= (ext_attr << (4 * ((partition - 1) % 2)));
768 else
769 value &= (0xF << (4 * ((partition % 2))));
770
771 ret = write_extcsd_value(fd, address, value);
772 if (ret) {
773 fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n",
774 value, address, device);
775 exit(1);
776 }
777
778 ret = check_enhanced_area_total_limit(device, fd);
779 if (ret)
780 exit(1);
781
782 if (!set_partitioning_setting_completed(dry_run, device, fd))
783 exit(1);
Balaji T K4afc8c82015-04-29 18:12:32 -0400784
785 return 0;
786}
787
Ben Gardinerd91d3692013-05-30 17:12:51 -0400788int do_enh_area_set(int nargs, char **argv)
789{
790 __u8 value;
791 __u8 ext_csd[512];
792 int fd, ret;
793 char *device;
794 int dry_run = 1;
795 unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult;
796 unsigned long align;
797
798 CHECK(nargs != 5, "Usage: mmc enh_area set <-y|-n> <start KiB> <length KiB> "
799 "</path/to/mmcblkX>\n", exit(1));
800
801 if (!strcmp("-y", argv[1]))
802 dry_run = 0;
803
804 start_kib = strtol(argv[2], NULL, 10);
805 length_kib = strtol(argv[3], NULL, 10);
806 device = argv[4];
807
808 fd = open(device, O_RDWR);
809 if (fd < 0) {
810 perror("open");
811 exit(1);
812 }
813
814 ret = read_extcsd(fd, ext_csd);
815 if (ret) {
816 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
817 exit(1);
818 }
819
820 /* assert ENH_ATTRIBUTE_EN */
821 if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN))
822 {
823 printf(" Device cannot have enhanced tech.\n");
824 exit(1);
825 }
826
827 /* assert not PARTITION_SETTING_COMPLETED */
828 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
829 {
830 printf(" Device is already partitioned\n");
831 exit(1);
832 }
833
834 align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
835
836 enh_size_mult = (length_kib + align/2l) / align;
837
838 enh_start_addr = start_kib * 1024 / (is_blockaddresed(ext_csd) ? 512 : 1);
839 enh_start_addr /= align;
840 enh_start_addr *= align;
841
842 /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
843 ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
844 if (ret) {
845 fprintf(stderr, "Could not write 0x1 to "
846 "EXT_CSD[%d] in %s\n",
847 EXT_CSD_ERASE_GROUP_DEF, device);
848 exit(1);
849 }
850
851 /* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
852 value = (enh_start_addr >> 24) & 0xff;
853 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
854 if (ret) {
855 fprintf(stderr, "Could not write 0x%02x to "
856 "EXT_CSD[%d] in %s\n", value,
857 EXT_CSD_ENH_START_ADDR_3, device);
858 exit(1);
859 }
860 value = (enh_start_addr >> 16) & 0xff;
861 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value);
862 if (ret) {
863 fprintf(stderr, "Could not write 0x%02x to "
864 "EXT_CSD[%d] in %s\n", value,
865 EXT_CSD_ENH_START_ADDR_2, device);
866 exit(1);
867 }
868 value = (enh_start_addr >> 8) & 0xff;
869 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value);
870 if (ret) {
871 fprintf(stderr, "Could not write 0x%02x to "
872 "EXT_CSD[%d] in %s\n", value,
873 EXT_CSD_ENH_START_ADDR_1, device);
874 exit(1);
875 }
876 value = enh_start_addr & 0xff;
877 ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value);
878 if (ret) {
879 fprintf(stderr, "Could not write 0x%02x to "
880 "EXT_CSD[%d] in %s\n", value,
881 EXT_CSD_ENH_START_ADDR_0, device);
882 exit(1);
883 }
884
885 value = (enh_size_mult >> 16) & 0xff;
886 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value);
887 if (ret) {
888 fprintf(stderr, "Could not write 0x%02x to "
889 "EXT_CSD[%d] in %s\n", value,
890 EXT_CSD_ENH_SIZE_MULT_2, device);
891 exit(1);
892 }
893 value = (enh_size_mult >> 8) & 0xff;
894 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value);
895 if (ret) {
896 fprintf(stderr, "Could not write 0x%02x to "
897 "EXT_CSD[%d] in %s\n", value,
898 EXT_CSD_ENH_SIZE_MULT_1, device);
899 exit(1);
900 }
901 value = enh_size_mult & 0xff;
902 ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value);
903 if (ret) {
904 fprintf(stderr, "Could not write 0x%02x to "
905 "EXT_CSD[%d] in %s\n", value,
906 EXT_CSD_ENH_SIZE_MULT_0, device);
907 exit(1);
908 }
Balaji T K4afc8c82015-04-29 18:12:32 -0400909 value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR;
910 ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400911 if (ret) {
912 fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
913 "EXT_CSD[%d] in %s\n",
914 EXT_CSD_PARTITIONS_ATTRIBUTE, device);
915 exit(1);
916 }
917
Balaji T K4afc8c82015-04-29 18:12:32 -0400918 ret = check_enhanced_area_total_limit(device, fd);
919 if (ret)
920 exit(1);
921
Ben Gardinere6e84e92013-09-19 11:14:27 -0400922 printf("Done setting ENH_USR area on %s\n", device);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400923
Ben Gardinere6e84e92013-09-19 11:14:27 -0400924 if (!set_partitioning_setting_completed(dry_run, device, fd))
Ben Gardinerd91d3692013-05-30 17:12:51 -0400925 exit(1);
Ben Gardinerd91d3692013-05-30 17:12:51 -0400926
927 return 0;
928}
929
Ben Gardiner196d0d22013-09-19 11:14:29 -0400930int do_write_reliability_set(int nargs, char **argv)
931{
932 __u8 value;
933 __u8 ext_csd[512];
934 int fd, ret;
935
936 int dry_run = 1;
937 int partition;
938 char *device;
939
940 CHECK(nargs != 4, "Usage: mmc write_reliability set <-y|-n> "
941 "<partition> </path/to/mmcblkX>\n", exit(1));
942
943 if (!strcmp("-y", argv[1]))
944 dry_run = 0;
945
946 partition = strtol(argv[2], NULL, 10);
947 device = argv[3];
948
949 fd = open(device, O_RDWR);
950 if (fd < 0) {
951 perror("open");
952 exit(1);
953 }
954
955 ret = read_extcsd(fd, ext_csd);
956 if (ret) {
957 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
958 exit(1);
959 }
960
961 /* assert not PARTITION_SETTING_COMPLETED */
962 if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
963 {
964 printf(" Device is already partitioned\n");
965 exit(1);
966 }
967
968 /* assert HS_CTRL_REL */
969 if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) {
970 printf("Cannot set write reliability parameters, WR_REL_SET is "
971 "read-only\n");
972 exit(1);
973 }
974
975 value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition);
976 ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value);
977 if (ret) {
978 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
979 value, EXT_CSD_WR_REL_SET, device);
980 exit(1);
981 }
982
983 printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n",
984 value, device);
985
986 if (!set_partitioning_setting_completed(dry_run, device, fd))
987 exit(1);
988
989 return 0;
990}
991
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500992int do_read_extcsd(int nargs, char **argv)
993{
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100994 __u8 ext_csd[512], ext_csd_rev, reg;
Oliver Metz11f2cea2013-09-23 08:40:52 +0200995 __u32 regl;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500996 int fd, ret;
997 char *device;
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +0100998 const char *str;
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -0500999
Chris Ball8ba44662012-04-19 13:22:54 -04001000 CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
1001 exit(1));
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -05001002
1003 device = argv[1];
1004
1005 fd = open(device, O_RDWR);
1006 if (fd < 0) {
1007 perror("open");
1008 exit(1);
1009 }
1010
1011 ret = read_extcsd(fd, ext_csd);
1012 if (ret) {
1013 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
1014 exit(1);
1015 }
1016
Al Cooperd0b46442015-04-29 18:12:35 -04001017 ext_csd_rev = ext_csd[EXT_CSD_REV];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001018
1019 switch (ext_csd_rev) {
Al Cooper64c2de82015-05-01 08:24:37 -04001020 case 7:
1021 str = "5.0";
1022 break;
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001023 case 6:
1024 str = "4.5";
1025 break;
1026 case 5:
1027 str = "4.41";
1028 break;
1029 case 3:
1030 str = "4.3";
1031 break;
1032 case 2:
1033 str = "4.2";
1034 break;
1035 case 1:
1036 str = "4.1";
1037 break;
1038 case 0:
1039 str = "4.0";
1040 break;
1041 default:
1042 goto out_free;
1043 }
1044 printf("=============================================\n");
1045 printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
1046 printf("=============================================\n\n");
1047
1048 if (ext_csd_rev < 3)
1049 goto out_free; /* No ext_csd */
1050
1051 /* Parse the Extended CSD registers.
1052 * Reserved bit should be read as "0" in case of spec older
1053 * than A441.
1054 */
1055 reg = ext_csd[EXT_CSD_S_CMD_SET];
1056 printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
1057 if (!reg)
Chris Ballb9c7a172012-02-20 12:34:25 -05001058 printf(" - Standard MMC command sets\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001059
1060 reg = ext_csd[EXT_CSD_HPI_FEATURE];
1061 printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
1062 if (reg & EXT_CSD_HPI_SUPP) {
1063 if (reg & EXT_CSD_HPI_IMPL)
Chris Ballb9c7a172012-02-20 12:34:25 -05001064 printf("implementation based on CMD12\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001065 else
1066 printf("implementation based on CMD13\n");
1067 }
1068
1069 printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
1070 ext_csd[502]);
1071
1072 if (ext_csd_rev >= 6) {
1073 printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
1074 ext_csd[501]);
1075 printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
1076 ext_csd[500]);
1077 printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
1078 ext_csd[499]);
1079
1080 printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
1081 ext_csd[498]);
1082 printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
1083 ext_csd[497]);
1084 printf("Context Management Capabilities"
1085 " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
1086 printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
1087 ext_csd[495]);
1088 printf("Extended partition attribute support"
1089 " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
1090 printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
1091 ext_csd[248]);
1092 printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
1093 ext_csd[247]);
1094 printf("Cache Size [CACHE_SIZE] is %d KiB\n",
1095 ext_csd[249] << 0 | (ext_csd[250] << 8) |
1096 (ext_csd[251] << 16) | (ext_csd[252] << 24));
1097 }
1098
1099 /* A441: Reserved [501:247]
1100 A43: reserved [246:229] */
1101 if (ext_csd_rev >= 5) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001102 printf("Background operations status"
Chris Ballb9c7a172012-02-20 12:34:25 -05001103 " [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001104
1105 /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
1106
1107 printf("1st Initialisation Time after programmed sector"
1108 " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
1109
1110 /* A441: reserved [240] */
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001111 printf("Power class for 52MHz, DDR at 3.6V"
1112 " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
1113 printf("Power class for 52MHz, DDR at 1.95V"
1114 " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
1115
1116 /* A441: reserved [237-236] */
1117
1118 if (ext_csd_rev >= 6) {
1119 printf("Power class for 200MHz at 3.6V"
1120 " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
1121 printf("Power class for 200MHz, at 1.95V"
1122 " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
1123 }
Chris Ballb9c7a172012-02-20 12:34:25 -05001124 printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001125 printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
1126 printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
1127 /* A441: reserved [233] */
1128 printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
1129 printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
1130 ext_csd[231]);
1131 }
1132 if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
1133 printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
1134 ext_csd[230]);
1135 printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
1136 ext_csd[229]);
1137 }
1138 reg = ext_csd[EXT_CSD_BOOT_INFO];
1139 printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
1140 if (reg & EXT_CSD_BOOT_INFO_ALT)
1141 printf(" Device supports alternative boot method\n");
1142 if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
1143 printf(" Device supports dual data rate during boot\n");
1144 if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
1145 printf(" Device supports high speed timing during boot\n");
1146
1147 /* A441/A43: reserved [227] */
1148 printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
1149 printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001150
1151 reg = get_hc_erase_grp_size(ext_csd);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001152 printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001153 reg);
1154 printf(" i.e. %u KiB\n", 512 * reg);
1155
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001156 printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
1157 ext_csd[223]);
1158 printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
1159 ext_csd[222]);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001160
1161 reg = get_hc_wp_grp_size(ext_csd);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001162 printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001163 reg);
1164 printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
1165
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001166 printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
1167 printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
1168 /* A441/A43: reserved [218] */
1169 printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
1170 /* A441/A43: reserved [216] */
Ben Gardiner4e850232013-05-30 17:12:49 -04001171
1172 unsigned int sectors = get_sector_count(ext_csd);
1173 printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors);
1174 if (is_blockaddresed(ext_csd))
1175 printf(" Device is block-addressed\n");
1176 else
1177 printf(" Device is NOT block-addressed\n");
1178
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001179 /* A441/A43: reserved [211] */
1180 printf("Minimum Write Performance for 8bit:\n");
1181 printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
1182 printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
1183 printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
1184 printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
1185 printf("Minimum Write Performance for 4bit:\n");
1186 printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
1187 printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
1188 /* A441/A43: reserved [204] */
1189 printf("Power classes registers:\n");
1190 printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
1191 printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
1192 printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
1193 printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
1194
1195 /* A43: reserved [199:198] */
1196 if (ext_csd_rev >= 5) {
1197 printf("Partition switching timing "
1198 "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
1199 printf("Out-of-interrupt busy timing"
1200 " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
1201 }
1202
1203 /* A441/A43: reserved [197] [195] [193] [190] [188]
1204 * [186] [184] [182] [180] [176] */
1205
1206 if (ext_csd_rev >= 6)
1207 printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
1208 ext_csd[197]);
1209
Oleg Matcovschi64f63a32013-05-23 17:11:07 -07001210 /* DEVICE_TYPE in A45, CARD_TYPE in A441 */
1211 reg = ext_csd[196];
1212 printf("Card Type [CARD_TYPE: 0x%02x]\n", reg);
1213 if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
1214 if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
1215 if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
1216 if (reg & 0x04) printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
1217 if (reg & 0x02) printf(" HS eMMC @52MHz - at rated device voltage(s)\n");
1218 if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n");
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001219
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001220 printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
Al Cooperd0b46442015-04-29 18:12:35 -04001221 /* ext_csd_rev = ext_csd[EXT_CSD_REV] (already done!!!) */
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001222 printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
1223 printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
1224 printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
1225 printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
1226 ext_csd[185]);
1227 /* bus_width: ext_csd[183] not readable */
1228 printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
1229 ext_csd[181]);
1230 reg = ext_csd[EXT_CSD_BOOT_CFG];
1231 printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001232 switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001233 case 0x0:
1234 printf(" Not boot enable\n");
1235 break;
1236 case 0x1:
1237 printf(" Boot Partition 1 enabled\n");
1238 break;
1239 case 0x2:
1240 printf(" Boot Partition 2 enabled\n");
1241 break;
1242 case 0x7:
1243 printf(" User Area Enabled for boot\n");
1244 break;
1245 }
1246 switch (reg & EXT_CSD_BOOT_CFG_ACC) {
1247 case 0x0:
1248 printf(" No access to boot partition\n");
1249 break;
1250 case 0x1:
1251 printf(" R/W Boot Partition 1\n");
1252 break;
1253 case 0x2:
1254 printf(" R/W Boot Partition 2\n");
1255 break;
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001256 case 0x3:
1257 printf(" R/W Replay Protected Memory Block (RPMB)\n");
1258 break;
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001259 default:
Mario Schuknecht8c0c40d2013-05-15 08:28:04 +02001260 printf(" Access to General Purpose partition %d\n",
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001261 (reg & EXT_CSD_BOOT_CFG_ACC) - 3);
1262 break;
1263 }
1264
1265 printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
1266 ext_csd[178]);
1267 printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
1268 ext_csd[177]);
1269 printf("High-density erase group definition"
Ben Gardinerd91d3692013-05-30 17:12:51 -04001270 " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001271
Chris Ballb9c7a172012-02-20 12:34:25 -05001272 print_writeprotect_status(ext_csd);
1273
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001274 if (ext_csd_rev >= 5) {
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001275 /* A441]: reserved [172] */
1276 printf("User area write protection register"
1277 " [USER_WP]: 0x%02x\n", ext_csd[171]);
1278 /* A441]: reserved [170] */
1279 printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
1280 printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001281
1282 reg = ext_csd[EXT_CSD_WR_REL_SET];
1283 const char * const fast = "existing data is at risk if a power "
1284 "failure occurs during a write operation";
1285 const char * const reliable = "the device protects existing "
1286 "data if a power failure occurs during a write "
1287 "operation";
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001288 printf("Write reliability setting register"
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001289 " [WR_REL_SET]: 0x%02x\n", reg);
1290
1291 printf(" user area: %s\n", reg & (1<<0) ? reliable : fast);
1292 int i;
1293 for (i = 1; i <= 4; i++) {
1294 printf(" partition %d: %s\n", i,
1295 reg & (1<<i) ? reliable : fast);
1296 }
1297
1298 reg = ext_csd[EXT_CSD_WR_REL_PARAM];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001299 printf("Write reliability parameter register"
Ben Gardiner4da1c0d2013-09-19 11:14:28 -04001300 " [WR_REL_PARAM]: 0x%02x\n", reg);
1301 if (reg & 0x01)
1302 printf(" Device supports writing EXT_CSD_WR_REL_SET\n");
1303 if (reg & 0x04)
1304 printf(" Device supports the enhanced def. of reliable "
1305 "write\n");
1306
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001307 /* sanitize_start ext_csd[165]]: not readable
1308 * bkops_start ext_csd[164]]: only writable */
1309 printf("Enable background operations handshake"
1310 " [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
1311 printf("H/W reset function"
1312 " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
1313 printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
Ben Gardiner82bd9502013-06-27 11:04:10 -04001314 reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001315 printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
1316 reg);
Ben Gardiner82bd9502013-06-27 11:04:10 -04001317 if (reg & EXT_CSD_PARTITIONING_EN)
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001318 printf(" Device support partitioning feature\n");
1319 else
1320 printf(" Device NOT support partitioning feature\n");
Ben Gardiner82bd9502013-06-27 11:04:10 -04001321 if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001322 printf(" Device can have enhanced tech.\n");
1323 else
1324 printf(" Device cannot have enhanced tech.\n");
1325
Oliver Metz11f2cea2013-09-23 08:40:52 +02001326 regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
Oliver Metz22f26412013-09-23 08:40:51 +02001327 (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
1328 ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
1329
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001330 printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
Oliver Metz11f2cea2013-09-23 08:40:52 +02001331 regl);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001332 unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
1333 unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
Oliver Metz11f2cea2013-09-23 08:40:52 +02001334 printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz);
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001335
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001336 printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
Ben Gardinerd91d3692013-05-30 17:12:51 -04001337 ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
Ben Gardinera6cd98d2013-05-30 17:12:46 -04001338 reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001339 printf("Partitioning Setting"
1340 " [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
Ben Gardinera6cd98d2013-05-30 17:12:46 -04001341 reg);
1342 if (reg)
1343 printf(" Device partition setting complete\n");
1344 else
1345 printf(" Device partition setting NOT complete\n");
1346
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001347 printf("General Purpose Partition Size\n"
1348 " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
1349 (ext_csd[153] << 8) | ext_csd[152]);
1350 printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
1351 (ext_csd[150] << 8) | ext_csd[149]);
1352 printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
1353 (ext_csd[147] << 8) | ext_csd[146]);
1354 printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
1355 (ext_csd[144] << 8) | ext_csd[143]);
1356
Oliver Metz11f2cea2013-09-23 08:40:52 +02001357 regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001358 (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
1359 ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001360 printf("Enhanced User Data Area Size"
Oliver Metz11f2cea2013-09-23 08:40:52 +02001361 " [ENH_SIZE_MULT]: 0x%06x\n", regl);
1362 printf(" i.e. %lu KiB\n", 512l * regl *
Ben Gardinerf82e27a2013-05-30 17:12:50 -04001363 get_hc_erase_grp_size(ext_csd) *
1364 get_hc_wp_grp_size(ext_csd));
Ben Gardiner68f490b2013-05-30 17:12:48 -04001365
Oliver Metz11f2cea2013-09-23 08:40:52 +02001366 regl = (ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
Ben Gardiner68f490b2013-05-30 17:12:48 -04001367 (ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) |
1368 (ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) |
1369 ext_csd[EXT_CSD_ENH_START_ADDR_0];
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001370 printf("Enhanced User Data Start Address"
Oliver Metz11f2cea2013-09-23 08:40:52 +02001371 " [ENH_START_ADDR]: 0x%06x\n", regl);
Ben Gardiner4e850232013-05-30 17:12:49 -04001372 printf(" i.e. %lu bytes offset\n", (is_blockaddresed(ext_csd) ?
Oliver Metz11f2cea2013-09-23 08:40:52 +02001373 1l : 512l) * regl);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001374
1375 /* A441]: reserved [135] */
1376 printf("Bad Block Management mode"
1377 " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
1378 /* A441: reserved [133:0] */
1379 }
1380 /* B45 */
1381 if (ext_csd_rev >= 6) {
1382 int j;
1383 /* tcase_support ext_csd[132] not readable */
1384 printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
1385 ext_csd[131]);
1386 printf("Program CID/CSD in DDR mode support"
1387 " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
1388 ext_csd[130]);
1389
1390 for (j = 127; j >= 64; j--)
1391 printf("Vendor Specific Fields"
1392 " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
1393 j, ext_csd[j]);
1394
1395 printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
1396 ext_csd[63]);
1397 printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
1398 ext_csd[62]);
1399 printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
1400 printf("1st initialization after disabling sector"
1401 " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
1402 ext_csd[60]);
1403 printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
1404 ext_csd[59]);
1405 printf("Number of addressed group to be Released"
1406 "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
1407 printf("Exception events control"
1408 " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
1409 (ext_csd[57] << 8) | ext_csd[56]);
1410 printf("Exception events status"
1411 "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
1412 (ext_csd[55] << 8) | ext_csd[54]);
1413 printf("Extended Partitions Attribute"
1414 " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
1415 (ext_csd[53] << 8) | ext_csd[52]);
1416
1417 for (j = 51; j >= 37; j--)
1418 printf("Context configuration"
1419 " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
1420
1421 printf("Packed command status"
1422 " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
1423 printf("Packed command failure index"
1424 " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
1425 printf("Power Off Notification"
1426 " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
Oleg Matcovschi64f63a32013-05-23 17:11:07 -07001427 printf("Control to turn the Cache ON/OFF"
1428 " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
Giuseppe CAVALLAROa5bf4a22012-02-20 09:45:29 +01001429 /* flush_cache ext_csd[32] not readable */
1430 /*Reserved [31:0] */
1431 }
1432
1433out_free:
Johan RUDHOLMa8bfde72012-02-12 11:46:44 -05001434 return ret;
1435}
Yaniv Gardi21bb4732013-05-26 13:25:33 -04001436
1437int do_sanitize(int nargs, char **argv)
1438{
1439 int fd, ret;
1440 char *device;
1441
1442 CHECK(nargs != 2, "Usage: mmc sanitize </path/to/mmcblkX>\n",
1443 exit(1));
1444
1445 device = argv[1];
1446
1447 fd = open(device, O_RDWR);
1448 if (fd < 0) {
1449 perror("open");
1450 exit(1);
1451 }
1452
1453 ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1);
1454 if (ret) {
1455 fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
1456 1, EXT_CSD_SANITIZE_START, device);
1457 exit(1);
1458 }
1459
1460 return ret;
1461
1462}
1463
Roman Peniaevc6cb0532014-08-12 23:25:45 +09001464#define DO_IO(func, fd, buf, nbyte) \
1465 ({ \
1466 ssize_t ret = 0, r; \
1467 do { \
1468 r = func(fd, buf + ret, nbyte - ret); \
1469 if (r < 0 && errno != EINTR) { \
1470 ret = -1; \
1471 break; \
1472 } \
1473 else if (r > 0) \
1474 ret += r; \
1475 } while (r != 0 && (size_t)ret != nbyte); \
1476 \
1477 ret; \
1478 })
1479
1480enum rpmb_op_type {
1481 MMC_RPMB_WRITE_KEY = 0x01,
1482 MMC_RPMB_READ_CNT = 0x02,
1483 MMC_RPMB_WRITE = 0x03,
1484 MMC_RPMB_READ = 0x04,
1485
1486 /* For internal usage only, do not use it directly */
1487 MMC_RPMB_READ_RESP = 0x05
1488};
1489
1490struct rpmb_frame {
1491 u_int8_t stuff[196];
1492 u_int8_t key_mac[32];
1493 u_int8_t data[256];
1494 u_int8_t nonce[16];
1495 u_int32_t write_counter;
1496 u_int16_t addr;
1497 u_int16_t block_count;
1498 u_int16_t result;
1499 u_int16_t req_resp;
1500};
1501
1502/* Performs RPMB operation.
1503 *
1504 * @fd: RPMB device on which we should perform ioctl command
1505 * @frame_in: input RPMB frame, should be properly inited
1506 * @frame_out: output (result) RPMB frame. Caller is responsible for checking
1507 * result and req_resp for output frame.
1508 * @out_cnt: count of outer frames. Used only for multiple blocks reading,
1509 * in the other cases -EINVAL will be returned.
1510 */
1511static int do_rpmb_op(int fd,
1512 const struct rpmb_frame *frame_in,
1513 struct rpmb_frame *frame_out,
1514 unsigned int out_cnt)
1515{
1516 int err;
1517 u_int16_t rpmb_type;
1518
1519 struct mmc_ioc_cmd ioc = {
1520 .arg = 0x0,
1521 .blksz = 512,
1522 .blocks = 1,
1523 .write_flag = 1,
1524 .opcode = MMC_WRITE_MULTIPLE_BLOCK,
1525 .flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
1526 .data_ptr = (uintptr_t)frame_in
1527 };
1528
1529 if (!frame_in || !frame_out || !out_cnt)
1530 return -EINVAL;
1531
1532 rpmb_type = be16toh(frame_in->req_resp);
1533
1534 switch(rpmb_type) {
1535 case MMC_RPMB_WRITE:
1536 case MMC_RPMB_WRITE_KEY:
1537 if (out_cnt != 1) {
1538 err = -EINVAL;
1539 goto out;
1540 }
1541
1542 /* Write request */
1543 ioc.write_flag |= (1<<31);
1544 err = ioctl(fd, MMC_IOC_CMD, &ioc);
1545 if (err < 0) {
1546 err = -errno;
1547 goto out;
1548 }
1549
1550 /* Result request */
1551 memset(frame_out, 0, sizeof(*frame_out));
1552 frame_out->req_resp = htobe16(MMC_RPMB_READ_RESP);
1553 ioc.write_flag = 1;
1554 ioc.data_ptr = (uintptr_t)frame_out;
1555 err = ioctl(fd, MMC_IOC_CMD, &ioc);
1556 if (err < 0) {
1557 err = -errno;
1558 goto out;
1559 }
1560
1561 /* Get response */
1562 ioc.write_flag = 0;
1563 ioc.opcode = MMC_READ_MULTIPLE_BLOCK;
1564 err = ioctl(fd, MMC_IOC_CMD, &ioc);
1565 if (err < 0) {
1566 err = -errno;
1567 goto out;
1568 }
1569
1570 break;
1571 case MMC_RPMB_READ_CNT:
1572 if (out_cnt != 1) {
1573 err = -EINVAL;
1574 goto out;
1575 }
1576 /* fall through */
1577
1578 case MMC_RPMB_READ:
1579 /* Request */
1580 err = ioctl(fd, MMC_IOC_CMD, &ioc);
1581 if (err < 0) {
1582 err = -errno;
1583 goto out;
1584 }
1585
1586 /* Get response */
1587 ioc.write_flag = 0;
1588 ioc.opcode = MMC_READ_MULTIPLE_BLOCK;
1589 ioc.blocks = out_cnt;
1590 ioc.data_ptr = (uintptr_t)frame_out;
1591 err = ioctl(fd, MMC_IOC_CMD, &ioc);
1592 if (err < 0) {
1593 err = -errno;
1594 goto out;
1595 }
1596
1597 break;
1598 default:
1599 err = -EINVAL;
1600 goto out;
1601 }
1602
1603out:
1604 return err;
1605}
1606
1607int do_rpmb_write_key(int nargs, char **argv)
1608{
1609 int ret, dev_fd, key_fd;
1610 struct rpmb_frame frame_in = {
1611 .req_resp = htobe16(MMC_RPMB_WRITE_KEY)
1612 }, frame_out;
1613
1614 CHECK(nargs != 3, "Usage: mmc rpmb write-key </path/to/mmcblkXrpmb> </path/to/key>\n",
1615 exit(1));
1616
1617 dev_fd = open(argv[1], O_RDWR);
1618 if (dev_fd < 0) {
1619 perror("device open");
1620 exit(1);
1621 }
1622
1623 if (0 == strcmp(argv[2], "-"))
1624 key_fd = STDIN_FILENO;
1625 else {
1626 key_fd = open(argv[2], O_RDONLY);
1627 if (key_fd < 0) {
1628 perror("can't open key file");
1629 exit(1);
1630 }
1631 }
1632
1633 /* Read the auth key */
1634 ret = DO_IO(read, key_fd, frame_in.key_mac, sizeof(frame_in.key_mac));
1635 if (ret < 0) {
1636 perror("read the key");
1637 exit(1);
1638 } else if (ret != sizeof(frame_in.key_mac)) {
1639 printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
1640 (unsigned long)sizeof(frame_in.key_mac),
1641 ret);
1642 exit(1);
1643 }
1644
1645 /* Execute RPMB op */
1646 ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
1647 if (ret != 0) {
1648 perror("RPMB ioctl failed");
1649 exit(1);
1650 }
1651
1652 /* Check RPMB response */
1653 if (frame_out.result != 0) {
1654 printf("RPMB operation failed, retcode 0x%04x\n",
1655 be16toh(frame_out.result));
1656 exit(1);
1657 }
1658
1659 close(dev_fd);
1660 if (key_fd != STDIN_FILENO)
1661 close(key_fd);
1662
1663 return ret;
1664}
1665
1666int rpmb_read_counter(int dev_fd, unsigned int *cnt)
1667{
1668 int ret;
1669 struct rpmb_frame frame_in = {
1670 .req_resp = htobe16(MMC_RPMB_READ_CNT)
1671 }, frame_out;
1672
1673 /* Execute RPMB op */
1674 ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
1675 if (ret != 0) {
1676 perror("RPMB ioctl failed");
1677 exit(1);
1678 }
1679
1680 /* Check RPMB response */
1681 if (frame_out.result != 0)
1682 return be16toh(frame_out.result);
1683
1684 *cnt = be32toh(frame_out.write_counter);
1685
1686 return 0;
1687}
1688
1689int do_rpmb_read_counter(int nargs, char **argv)
1690{
1691 int ret, dev_fd;
1692 unsigned int cnt;
1693
1694 CHECK(nargs != 2, "Usage: mmc rpmb read-counter </path/to/mmcblkXrpmb>\n",
1695 exit(1));
1696
1697 dev_fd = open(argv[1], O_RDWR);
1698 if (dev_fd < 0) {
1699 perror("device open");
1700 exit(1);
1701 }
1702
1703 ret = rpmb_read_counter(dev_fd, &cnt);
1704
1705 /* Check RPMB response */
1706 if (ret != 0) {
1707 printf("RPMB operation failed, retcode 0x%04x\n", ret);
1708 exit(1);
1709 }
1710
1711 close(dev_fd);
1712
1713 printf("Counter value: 0x%08x\n", cnt);
1714
1715 return ret;
1716}
1717
1718int do_rpmb_read_block(int nargs, char **argv)
1719{
1720 int i, ret, dev_fd, data_fd, key_fd = -1;
1721 uint16_t addr, blocks_cnt;
1722 unsigned char key[32];
1723 struct rpmb_frame frame_in = {
1724 .req_resp = htobe16(MMC_RPMB_READ),
1725 }, *frame_out_p;
1726
1727 CHECK(nargs != 5 && nargs != 6, "Usage: mmc rpmb read-block </path/to/mmcblkXrpmb> <address> <blocks count> </path/to/output_file> [/path/to/key]\n",
1728 exit(1));
1729
1730 dev_fd = open(argv[1], O_RDWR);
1731 if (dev_fd < 0) {
1732 perror("device open");
1733 exit(1);
1734 }
1735
1736 /* Get block address */
1737 errno = 0;
1738 addr = strtol(argv[2], NULL, 0);
1739 if (errno) {
1740 perror("incorrect address");
1741 exit(1);
1742 }
1743 frame_in.addr = htobe16(addr);
1744
1745 /* Get blocks count */
1746 errno = 0;
1747 blocks_cnt = strtol(argv[3], NULL, 0);
1748 if (errno) {
1749 perror("incorrect blocks count");
1750 exit(1);
1751 }
1752
1753 if (!blocks_cnt) {
1754 printf("please, specify valid blocks count number\n");
1755 exit(1);
1756 }
1757
1758 frame_out_p = calloc(sizeof(*frame_out_p), blocks_cnt);
1759 if (!frame_out_p) {
1760 printf("can't allocate memory for RPMB outer frames\n");
1761 exit(1);
1762 }
1763
1764 /* Write 256b data */
1765 if (0 == strcmp(argv[4], "-"))
1766 data_fd = STDOUT_FILENO;
1767 else {
1768 data_fd = open(argv[4], O_WRONLY | O_CREAT | O_APPEND,
1769 S_IRUSR | S_IWUSR);
1770 if (data_fd < 0) {
1771 perror("can't open output file");
1772 exit(1);
1773 }
1774 }
1775
1776 /* Key is specified */
1777 if (nargs == 6) {
1778 if (0 == strcmp(argv[5], "-"))
1779 key_fd = STDIN_FILENO;
1780 else {
1781 key_fd = open(argv[5], O_RDONLY);
1782 if (key_fd < 0) {
1783 perror("can't open input key file");
1784 exit(1);
1785 }
1786 }
1787
1788 ret = DO_IO(read, key_fd, key, sizeof(key));
1789 if (ret < 0) {
1790 perror("read the key data");
1791 exit(1);
1792 } else if (ret != sizeof(key)) {
1793 printf("Data must be %lu bytes length, but we read only %d, exit\n",
1794 (unsigned long)sizeof(key),
1795 ret);
1796 exit(1);
1797 }
1798 }
1799
1800 /* Execute RPMB op */
1801 ret = do_rpmb_op(dev_fd, &frame_in, frame_out_p, blocks_cnt);
1802 if (ret != 0) {
1803 perror("RPMB ioctl failed");
1804 exit(1);
1805 }
1806
1807 /* Check RPMB response */
1808 if (frame_out_p[blocks_cnt - 1].result != 0) {
1809 printf("RPMB operation failed, retcode 0x%04x\n",
1810 be16toh(frame_out_p[blocks_cnt - 1].result));
1811 exit(1);
1812 }
1813
1814 /* Do we have to verify data against key? */
1815 if (nargs == 6) {
1816 unsigned char mac[32];
1817 hmac_sha256_ctx ctx;
1818 struct rpmb_frame *frame_out = NULL;
1819
1820 hmac_sha256_init(&ctx, key, sizeof(key));
1821 for (i = 0; i < blocks_cnt; i++) {
1822 frame_out = &frame_out_p[i];
1823 hmac_sha256_update(&ctx, frame_out->data,
1824 sizeof(*frame_out) -
1825 offsetof(struct rpmb_frame, data));
1826 }
1827
1828 hmac_sha256_final(&ctx, mac, sizeof(mac));
1829
1830 /* Impossible */
1831 assert(frame_out);
1832
1833 /* Compare calculated MAC and MAC from last frame */
1834 if (memcmp(mac, frame_out->key_mac, sizeof(mac))) {
1835 printf("RPMB MAC missmatch\n");
1836 exit(1);
1837 }
1838 }
1839
1840 /* Write data */
1841 for (i = 0; i < blocks_cnt; i++) {
1842 struct rpmb_frame *frame_out = &frame_out_p[i];
1843 ret = DO_IO(write, data_fd, frame_out->data, sizeof(frame_out->data));
1844 if (ret < 0) {
1845 perror("write the data");
1846 exit(1);
1847 } else if (ret != sizeof(frame_out->data)) {
1848 printf("Data must be %lu bytes length, but we wrote only %d, exit\n",
1849 (unsigned long)sizeof(frame_out->data),
1850 ret);
1851 exit(1);
1852 }
1853 }
1854
1855 free(frame_out_p);
1856 close(dev_fd);
1857 if (data_fd != STDOUT_FILENO)
1858 close(data_fd);
1859 if (key_fd != -1 && key_fd != STDIN_FILENO)
1860 close(key_fd);
1861
1862 return ret;
1863}
1864
1865int do_rpmb_write_block(int nargs, char **argv)
1866{
1867 int ret, dev_fd, key_fd, data_fd;
1868 unsigned char key[32];
1869 uint16_t addr;
1870 unsigned int cnt;
1871 struct rpmb_frame frame_in = {
1872 .req_resp = htobe16(MMC_RPMB_WRITE),
1873 .block_count = htobe16(1)
1874 }, frame_out;
1875
1876 CHECK(nargs != 5, "Usage: mmc rpmb write-block </path/to/mmcblkXrpmb> <address> </path/to/input_file> </path/to/key>\n",
1877 exit(1));
1878
1879 dev_fd = open(argv[1], O_RDWR);
1880 if (dev_fd < 0) {
1881 perror("device open");
1882 exit(1);
1883 }
1884
1885 ret = rpmb_read_counter(dev_fd, &cnt);
1886 /* Check RPMB response */
1887 if (ret != 0) {
1888 printf("RPMB read counter operation failed, retcode 0x%04x\n", ret);
1889 exit(1);
1890 }
1891 frame_in.write_counter = htobe32(cnt);
1892
1893 /* Get block address */
1894 errno = 0;
1895 addr = strtol(argv[2], NULL, 0);
1896 if (errno) {
1897 perror("incorrect address");
1898 exit(1);
1899 }
1900 frame_in.addr = htobe16(addr);
1901
1902 /* Read 256b data */
1903 if (0 == strcmp(argv[3], "-"))
1904 data_fd = STDIN_FILENO;
1905 else {
1906 data_fd = open(argv[3], O_RDONLY);
1907 if (data_fd < 0) {
1908 perror("can't open input file");
1909 exit(1);
1910 }
1911 }
1912
1913 ret = DO_IO(read, data_fd, frame_in.data, sizeof(frame_in.data));
1914 if (ret < 0) {
1915 perror("read the data");
1916 exit(1);
1917 } else if (ret != sizeof(frame_in.data)) {
1918 printf("Data must be %lu bytes length, but we read only %d, exit\n",
1919 (unsigned long)sizeof(frame_in.data),
1920 ret);
1921 exit(1);
1922 }
1923
1924 /* Read the auth key */
1925 if (0 == strcmp(argv[4], "-"))
1926 key_fd = STDIN_FILENO;
1927 else {
1928 key_fd = open(argv[4], O_RDONLY);
1929 if (key_fd < 0) {
1930 perror("can't open key file");
1931 exit(1);
1932 }
1933 }
1934
1935 ret = DO_IO(read, key_fd, key, sizeof(key));
1936 if (ret < 0) {
1937 perror("read the key");
1938 exit(1);
1939 } else if (ret != sizeof(key)) {
1940 printf("Auth key must be %lu bytes length, but we read only %d, exit\n",
1941 (unsigned long)sizeof(key),
1942 ret);
1943 exit(1);
1944 }
1945
1946 /* Calculate HMAC SHA256 */
1947 hmac_sha256(
1948 key, sizeof(key),
1949 frame_in.data, sizeof(frame_in) - offsetof(struct rpmb_frame, data),
1950 frame_in.key_mac, sizeof(frame_in.key_mac));
1951
1952 /* Execute RPMB op */
1953 ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1);
1954 if (ret != 0) {
1955 perror("RPMB ioctl failed");
1956 exit(1);
1957 }
1958
1959 /* Check RPMB response */
1960 if (frame_out.result != 0) {
1961 printf("RPMB operation failed, retcode 0x%04x\n",
1962 be16toh(frame_out.result));
1963 exit(1);
1964 }
1965
1966 close(dev_fd);
1967 if (data_fd != STDIN_FILENO)
1968 close(data_fd);
1969 if (key_fd != STDIN_FILENO)
1970 close(key_fd);
1971
1972 return ret;
1973}
Al Cooperd0b46442015-04-29 18:12:35 -04001974
1975int do_cache_ctrl(int value, int nargs, char **argv)
1976{
1977 __u8 ext_csd[512];
1978 int fd, ret;
1979 char *device;
1980
1981 CHECK(nargs != 2, "Usage: mmc cache enable </path/to/mmcblkX>\n",
1982 exit(1));
1983
1984 device = argv[1];
1985
1986 fd = open(device, O_RDWR);
1987 if (fd < 0) {
1988 perror("open");
1989 exit(1);
1990 }
1991
1992 ret = read_extcsd(fd, ext_csd);
1993 if (ret) {
1994 fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
1995 exit(1);
1996 }
1997
1998 if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V4_5) {
1999 fprintf(stderr,
2000 "The CACHE option is only availabe on devices >= "
2001 "MMC 4.5 %s\n", device);
2002 exit(1);
2003 }
2004
2005 /* If the cache size is zero, this device does not have a cache */
2006 if (!(ext_csd[EXT_CSD_CACHE_SIZE_3] ||
2007 ext_csd[EXT_CSD_CACHE_SIZE_2] ||
2008 ext_csd[EXT_CSD_CACHE_SIZE_1] ||
2009 ext_csd[EXT_CSD_CACHE_SIZE_0])) {
2010 fprintf(stderr,
2011 "The CACHE option is not available on %s\n",
2012 device);
2013 exit(1);
2014 }
2015 ret = write_extcsd_value(fd, EXT_CSD_CACHE_CTRL, value);
2016 if (ret) {
2017 fprintf(stderr,
2018 "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
2019 value, EXT_CSD_CACHE_CTRL, device);
2020 exit(1);
2021 }
2022
2023 return ret;
2024}
2025
2026int do_cache_en(int nargs, char **argv)
2027{
2028 return do_cache_ctrl(1, nargs, argv);
2029}
2030
2031int do_cache_dis(int nargs, char **argv)
2032{
2033 return do_cache_ctrl(0, nargs, argv);
2034}