背景 最近在使用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出厂的数据会保留。与我遇到的情况有差异,我的是分区还在,但是分区里面的文件系统数据和用户数据全部被清空,原因待查中。。。
原帖地址:IMX6UL eMMC加锁和解锁代码分析与实现_王二车的博客-CSDN博客_emmc加密
|