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