IMX6UL eMMC加锁和解锁代码分析与实现

背景

最近在使用eMMC作为外部存储设备过程中,出现eMMC两个分区数据全部被清空,文件系统数据和用户数据全部为0 ,在网上看到一篇文件说对eMMC加锁后强制解锁会清除用户数据,这样达到的效果与我遇到的类似,下面实现加锁和解锁代码进行测试。

环境

在uboot中添加对emmc命令加解锁测试比较方便,uboot版本2017.03

命令

对emmc加解锁主要是用CMD42命令进行操作,发送的命令和数据都是参考上面链接文章。

mmc现有命令

=> mmc 
mmc - MMC sub system

Usage:
mmc info - display info of the current MMC device
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
mmc rescan
mmc part - lists available partition on current mmc device
mmc dev [dev] [part] - show or set current mmc device [partition]
mmc list - lists available devices
mmc hwpartition [args...] - does hardware partitioning

添加lock/unlock/clear命令,cmd/mmc.c,cmd_mmc结构体中:

	U_BOOT_CMD_MKENT(lock, 1, 0, do_lock, "", ""),
	U_BOOT_CMD_MKENT(unlock, 1, 0, undo_lock, "", ""),
	U_BOOT_CMD_MKENT(clear, 1, 0, do_clear, "", ""),
static void lock_emmc(struct mmc *mmc)
{
	mmc_lock_emmc(mmc);
}
static int do_lock(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc;

	if (curr_device < 0) {
		if (get_mmc_num() > 0)
			curr_device = 0;
		else {
			puts("No MMC device available\n");
			return 1;
		}
	}

	mmc = init_mmc_device(curr_device, false);
	if (!mmc)
		return CMD_RET_FAILURE;

	lock_emmc(mmc);
	return CMD_RET_SUCCESS;
}

CMD42数据结构体

第0字节:设备锁/解锁模式

第1字节:密码长度,单位字节,这里设置1

第2字节:密码数据,这里设置简单的1

#define MMC_LOCK_UNLOCK			42

struct mmc_pwd{
	u8 mode;
	u8 pwd_len;
	u8 pwd_data;
};

加锁

1. 若是没有选择设备,此时选择设备(CMD7),代码没实现,直接手动输入命令mmc dev 0。
           2. 设置block长度(CMD16),由8位设备锁/解锁模式,8位密码大小,总密码长度的大小决定。
           3. 发送CMD42命令,选择模式LOCK和SET_ PWD,另外加上PWD_LEN和PWD_DATA。

int mmc_lock_emmc(struct mmc *mmc)
{
	printf("mmc_lock_emmc\n");
	struct mmc_cmd cmd;
	struct mmc_data data;
	int timeout = 1000;

	printf("write_bl_len=%d\n",mmc->write_bl_len);//512

	if (mmc_set_blocklen(mmc, 3)){//设置block长度,总3个字节
		printf("mmc_set_blocklen failed!\n");
		return 0;
	}
	cmd.cmdidx = MMC_LOCK_UNLOCK;//CMD42
	cmd.cmdarg = 0;//
	cmd.resp_type = MMC_RSP_R1;

	struct mmc_pwd *src_pwd=(struct mmc_pwd *)malloc(3);
	if(NULL == src_pwd){
		printf("malloc failed!\n");
		return 0;
	}

	src_pwd->mode = 5;//lock and set pwd
	src_pwd->pwd_len = 1;
	src_pwd->pwd_data = 1;

	data.src = (char *)src_pwd;
	data.blocks = 1;
	data.blocksize = 3;
	data.flags = MMC_DATA_WRITE;

	if (mmc_send_cmd(mmc, &cmd, &data)) {
		printf("mmc write failed\n");
		return 0;
	}

	/* Waiting for the ready status */
	if (mmc_send_status(mmc, timeout)){
		printf("mmc_send_status failed\n");
		return 0;
	}
		
	return 0;
}

解锁

1. 若是没有选择设备,此时选择设备(CMD7),代码没实现,直接手动输入命令mmc dev 0。
           2. 设置block长度(CMD16),由8位设备锁/解锁模式,8位密码大小,总密码长度的大小决定。
           3. 发送CMD42命令,选择模式CLR_PWD,同样包括PWD_LEN和PWD,若是密码大小和内容正确,PWD内容会清除,且PWD_LEN设置为0。

int mmc_unlock_emmc(struct mmc *mmc)
{
	printf("mmc_unlock_emmc\n");
	struct mmc_cmd cmd;
	struct mmc_data data;
	int timeout = 1000;

	printf("write_bl_len=%d\n",mmc->write_bl_len);

	if (mmc_set_blocklen(mmc, 3)){
		printf("mmc_set_blocklen failed!\n");
		return 0;
	}
	cmd.cmdidx = MMC_LOCK_UNLOCK;
	cmd.cmdarg = 0;//
	cmd.resp_type = MMC_RSP_R1;

	struct mmc_pwd *src_pwd=(struct mmc_pwd *)malloc(3);
	if(NULL == src_pwd){
		printf("malloc failed!\n");
		return 0;
	}

	src_pwd->mode = 2;//unlock and clear pwd
	src_pwd->pwd_len = 1;
	src_pwd->pwd_data = 1;

	data.src = (char *)src_pwd;
	data.blocks = 1;
	data.blocksize = 3;
	data.flags = MMC_DATA_WRITE;

	if (mmc_send_cmd(mmc, &cmd, &data)) {
		printf("mmc write failed\n");
		return 0;
	}

	/* Waiting for the ready status */
	if (mmc_send_status(mmc, timeout)){
		printf("mmc_send_status failed\n");
		return 0;
	}
		
	return 0;
}

强制清除

用户忘了密码的情况,host可以清除所有PWD内容,这个过程叫做强行清除。
           1. 选择设备CMD7
           2. 设置block长度为1byte(CMD16)
           3. 发送CMD42,选择模式ERASE,data block表明模式ERASE。

struct mmc_pwd_clear{
	u8 mode;
};

int mmc_clear_emmc(struct mmc *mmc)
{
	printf("mmc_clear_emmc\n");
	struct mmc_cmd cmd;
	struct mmc_data data;
	int timeout = 1000;

	printf("write_bl_len=%d\n",mmc->write_bl_len);

	if (mmc_set_blocklen(mmc, 1)){
		printf("mmc_set_blocklen failed!\n");
		return 0;
	}
	cmd.cmdidx = MMC_LOCK_UNLOCK;
	cmd.cmdarg = 0;//
	cmd.resp_type = MMC_RSP_R1;

	struct mmc_pwd_clear *src_pwd_clear=(struct mmc_pwd *)malloc(1);
	if(NULL == src_pwd_clear){
		printf("malloc failed!\n");
		return 0;
	}

	src_pwd_clear->mode = 8;//q-clear

	data.src = (char *)src_pwd_clear;
	data.blocks = 1;
	data.blocksize = 1;
	data.flags = MMC_DATA_WRITE;

	if (mmc_send_cmd(mmc, &cmd, &data)) {
		printf("mmc write failed\n");
		return 0;
	}

	/* Waiting for the ready status */
	if (mmc_send_status(mmc, timeout)){
		printf("mmc_send_status failed\n");
		return 0;
	}
	
	return 0;
}

测试

选择设备

加锁前正常读

加锁

加锁后读失败

加锁后内核启动到文件系统读emmc失败打印

mmc1: new DDR MMC card at address 0001
mmcblk1: mmc1:0001 P1XXXX 7.20 GiB 
mmcblk1boot0: mmc1:0001 P1XXXX partition 1 16.0 MiB
mmcblk1boot1: mmc1:0001 P1XXXX partition 2 16.0 MiB
mmcblk1rpmb: mmc1:0001 P1XXXX partition 3 128 KiB
hub 1-1:1.0: USB hub found
hub 1-1:1.0: 4 ports detected
usb 1-1.1: new high-speed USB device number 3 using ci_hdrc
usb 1-1.3: new full-speed USB device number 4 using ci_hdrc
EXT4-fs (ram0): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext4 filesystem) readonly on device 1:0.
devtmpfs: mounted
Freeing unused kernel memory: 1024K (c0a00000 - c0b00000)
mmcblk1: error -110 sending stop command, original cmd response 0x2000900, card status 0x2400900
mmcblk1: error -110 transferring data, sector 0, nr 8, cmd response 0x2000900, card status 0x0
mmcblk1: error -110 sending stop command, original cmd response 0x2000900, card status 0x2400900
mmcblk1: error -110 transferring data, sector 0, nr 8, cmd response 0x2000900, card status 0x0
mmcblk1: retrying using single block read
mmcblk1: error -110 transferring data, sector 0, nr 8, cmd response 0x2000900, card status 0x0
blk_update_request: I/O error, dev mmcblk1, sector 0
mmcblk1: error -110 transferring data, sector 1, nr 7, cmd response 0x2000900, card status 0x0
blk_update_request: I/O error, dev mmcblk1, sector 1

解锁

解锁后读成功

加锁后强制清除

强制清除前分区存在

强制清除

强制清除后读成功,但数据全部为0

分区被删除

总结

加锁后强制清除会删除用户创建的分区和数据,EMMC出厂的数据会保留。与我遇到的情况有差异,我的是分区还在,但是分区里面的文件系统数据和用户数据全部被清空,原因待查中。。。

猜你喜欢

转载自blog.csdn.net/TSZ0000/article/details/86477716