1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9 * General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/ioctl.h>
21#include <sys/types.h>
22#include <sys/endian.h>
23#include <dirent.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <libgen.h>
28#include <limits.h>
29#include <ctype.h>
30#include <errno.h>
31#include <stdint.h>
32#include <assert.h>
33
34#include "mmc.h"
35#include "mmc_cmds.h"
36#include "3rdparty/hmac_sha/hmac_sha2.h"
37
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
80int 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
99void print_writeprotect_status(__u8 *ext_csd)
100{
101	__u8 reg;
102	__u8 ext_csd_rev = ext_csd[EXT_CSD_REV];
103
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
139	CHECK(nargs != 2, "Usage: mmc writeprotect get </path/to/mmcblkX>\n",
140			  exit(1));
141
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
167	CHECK(nargs != 2, "Usage: mmc writeprotect set </path/to/mmcblkX>\n",
168			  exit(1));
169
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
197int 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
241int 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
307int 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
376int 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
435int 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
473int 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
501unsigned 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
516unsigned 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
526int 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
571int 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;
577	unsigned long total_sz, total_gp_user_sz;
578	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	}
651	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);
785
786	return 0;
787}
788
789int 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	}
910	value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR;
911	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
912	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
919	ret = check_enhanced_area_total_limit(device, fd);
920	if (ret)
921		exit(1);
922
923	printf("Done setting ENH_USR area on %s\n", device);
924
925	if (!set_partitioning_setting_completed(dry_run, device, fd))
926		exit(1);
927
928	return 0;
929}
930
931int 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
993int do_read_extcsd(int nargs, char **argv)
994{
995	__u8 ext_csd[512], ext_csd_rev, reg;
996	__u32 regl;
997	int fd, ret;
998	char *device;
999	const char *str;
1000
1001	CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
1002			  exit(1));
1003
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
1018	ext_csd_rev = ext_csd[EXT_CSD_REV];
1019
1020	switch (ext_csd_rev) {
1021	case 7:
1022		str = "5.0";
1023		break;
1024	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)
1059		printf(" - Standard MMC command sets\n");
1060
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)
1065			printf("implementation based on CMD12\n");
1066		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) {
1103		printf("Background operations status"
1104			" [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
1105
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] */
1112		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		}
1125		printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
1126		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]);
1151
1152	reg = get_hc_erase_grp_size(ext_csd);
1153	printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
1154		reg);
1155	printf(" i.e. %u KiB\n", 512 * reg);
1156
1157	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]);
1161
1162	reg = get_hc_wp_grp_size(ext_csd);
1163	printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
1164		reg);
1165	printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
1166
1167	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] */
1172
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
1180	/* 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
1211	/* 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");
1220
1221	printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
1222	/* ext_csd_rev = ext_csd[EXT_CSD_REV] (already done!!!) */
1223	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);
1233	switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
1234	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;
1257	case 0x3:
1258		printf(" R/W Replay Protected Memory Block (RPMB)\n");
1259		break;
1260	default:
1261		printf(" Access to General Purpose partition %d\n",
1262			(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"
1271		" [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
1272
1273	print_writeprotect_status(ext_csd);
1274
1275	if (ext_csd_rev >= 5) {
1276		/* 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]);
1282
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";
1289		printf("Write reliability setting register"
1290			" [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];
1300		printf("Write reliability parameter register"
1301			" [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
1308		/* 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]);
1315		reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1316		printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
1317			reg);
1318		if (reg & EXT_CSD_PARTITIONING_EN)
1319			printf(" Device support partitioning feature\n");
1320		else
1321			printf(" Device NOT support partitioning feature\n");
1322		if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
1323			printf(" Device can have enhanced tech.\n");
1324		else
1325			printf(" Device cannot have enhanced tech.\n");
1326
1327		regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
1328			(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
1329			ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
1330
1331		printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
1332			   regl);
1333		unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
1334		unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
1335		printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz);
1336
1337		printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
1338			ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
1339		reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
1340		printf("Partitioning Setting"
1341			" [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
1342			reg);
1343		if (reg)
1344			printf(" Device partition setting complete\n");
1345		else
1346			printf(" Device partition setting NOT complete\n");
1347
1348		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
1358		regl =	(ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
1359			(ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
1360			ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
1361		printf("Enhanced User Data Area Size"
1362			" [ENH_SIZE_MULT]: 0x%06x\n", regl);
1363		printf(" i.e. %lu KiB\n", 512l * regl *
1364		       get_hc_erase_grp_size(ext_csd) *
1365		       get_hc_wp_grp_size(ext_csd));
1366
1367		regl =	(ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
1368			(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];
1371		printf("Enhanced User Data Start Address"
1372			" [ENH_START_ADDR]: 0x%06x\n", regl);
1373		printf(" i.e. %lu bytes offset\n", (is_blockaddresed(ext_csd) ?
1374				1l : 512l) * regl);
1375
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]);
1428		printf("Control to turn the Cache ON/OFF"
1429			" [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
1430		/* flush_cache ext_csd[32] not readable */
1431		/*Reserved [31:0] */
1432	}
1433
1434out_free:
1435	return ret;
1436}
1437
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
1465#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}
1975
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}
2036