Message ID | 20240518162647.452103-1-linux-mmc@danman.eu (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | implemented CMD42 locking unlocking | expand |
On 5/18/24 17:26, linux-mmc@danman.eu wrote: > ------ Tessian Warning ------ > > Be careful, the email's sending domain "@danman[.]eu" has never been seen on your company's network before today > > This warning message will be removed if you reply to or forward this email to a recipient outside of your organization. > > ---- Tessian Warning End ---- > > From: Daniel Kucera <daniel.kucera@gmail.com> Locking is pretty bad, at least for SD it's highly problematic with current mmcblk, as locked cards won't initialize AFAIR (SD status query is illegal, but initialization requires it if I remember correctly). Did you try that? > > --- > mmc.c | 11 +++++ > mmc.h | 11 +++++ > mmc_cmds.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > mmc_cmds.h | 2 + > 4 files changed, 147 insertions(+) > > diff --git a/mmc.c b/mmc.c > index bc8f74e..3ff7308 100644 > --- a/mmc.c > +++ b/mmc.c > @@ -250,6 +250,17 @@ static struct Command commands[] = { > "be 1.", > NULL > }, > + { do_lock_unlock, -3, > + "cmd42", "<password> " "<parameter> " "<device>\n" > + "Usage: mmc cmd42 <password> <s|c|l|u|e> <device>\n" > + "s\tset password\n" > + "c\tclear password\n" > + "l\tlock\n" > + "sl\tset password and lock\n" > + "u\tunlock\n" > + "e\tforce erase\n", > + NULL > + }, > { do_softreset, -1, > "softreset", "<device>\n" > "Issues a CMD0 softreset, e.g. for testing if hardware reset for UHS works", > diff --git a/mmc.h b/mmc.h > index 6f1bf3e..f8bac22 100644 > --- a/mmc.h > +++ b/mmc.h > @@ -30,6 +30,7 @@ > #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ > #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ > #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ > +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ > #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ > #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ > #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ > @@ -46,6 +47,7 @@ > [1] Discard Enable > [0] Identify Write Blocks for > Erase (or TRIM Enable) R1b */ > +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ > #define MMC_GEN_CMD 56 /* adtc [31:1] stuff bits. > [0]: RD/WR1 R1 */ > > @@ -70,6 +72,15 @@ > #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ > #define R1_APP_CMD (1 << 5) /* sr, c */ > > +#define MMC_CMD42_UNLOCK 0x0 /* UNLOCK */ > +#define MMC_CMD42_SET_PWD 0x1 /* SET_PWD */ > +#define MMC_CMD42_CLR_PWD 0x2 /* CLR_PWD */ > +#define MMC_CMD42_LOCK 0x4 /* LOCK */ > +#define MMC_CMD42_SET_LOCK 0x5 /* SET_PWD & LOCK */ > +#define MMC_CMD42_ERASE 0x8 /* ERASE */ > +#define MAX_PWD_LENGTH 32 /* max PWDS_LEN: old+new */ > +#define MMC_BLOCK_SIZE 512 /* data blk size for cmd42 */ > + > /* > * EXT_CSD fields > */ > diff --git a/mmc_cmds.c b/mmc_cmds.c > index 936e0c5..03fe04f 100644 > --- a/mmc_cmds.c > +++ b/mmc_cmds.c > @@ -129,6 +129,129 @@ int send_status(int fd, __u32 *response) > return ret; > } > > +//lock/unlock feature implementation > +int do_lock_unlock(int nargs, char **argv) > +{ > + int fd, ret = 0; > + char *device; > + __u8 data_block[MMC_BLOCK_SIZE]={0}; > + __u8 data_block_onebyte[1]={0}; > + int block_size = 0; > + struct mmc_ioc_cmd idata; > + int cmd42_para; //parameter of cmd42 > + char pwd[MAX_PWD_LENGTH+1]; //password > + int pwd_len; //password length > + __u32 r1_response; //R1 response token > + > + if (nargs != 4){ > + fprintf(stderr, "Usage: mmc cmd42 <password> <s|c|l|u|e> <device>\n"); > + exit(1); > + } > + > + strcpy(pwd, argv[1]); > + pwd_len = strlen(pwd); > + > + if (!strcmp("s", argv[2])) { > + cmd42_para = MMC_CMD42_SET_PWD; > + printf("Set password: password=%s ...\n", pwd); > + } > + else if (!strcmp("c", argv[2])) { > + cmd42_para = MMC_CMD42_CLR_PWD; > + printf("Clear password: password=%s ...\n", pwd); > + } > + else if (!strcmp("l", argv[2])) { > + cmd42_para = MMC_CMD42_LOCK; > + printf("Lock the card: password=%s ...\n", pwd); > + } > + else if (!strcmp("sl", argv[2])) { > + cmd42_para = MMC_CMD42_SET_LOCK; > + printf("Set password and lock the card: password - %s ...\n", pwd); > + } > + else if (!strcmp("u", argv[2])) { > + cmd42_para = MMC_CMD42_UNLOCK; > + printf("Unlock the card: password=%s ...\n", pwd); > + } > + else if (!strcmp("e", argv[2])) { > + cmd42_para = MMC_CMD42_ERASE; > + printf("Force erase ... (Warning: all card data will be erased together with PWD!)\n"); > + } > + else { > + printf("Invalid parameter:\n" "s\tset password\n" "c\tclear password\n" "l\tlock\n" > + "sl\tset password and lock\n" "u\tunlock\n" "e\tforce erase\n"); > + exit(1); > + } > + > + device = argv[nargs-1]; > + > + fd = open(device, O_RDWR); > + if (fd < 0) { > + perror("open"); > + exit(1); > + } > + > + if (cmd42_para==MMC_CMD42_ERASE) > + block_size = 2; //set blk size to 2-byte for Force Erase @DDR50 compability > + else > + block_size = MMC_BLOCK_SIZE; > + > + ret = set_block_len(fd, block_size); //set data block size prior to cmd42 > + printf("Set to data block length = %d byte(s).\n", block_size); > + > + if (cmd42_para==MMC_CMD42_ERASE) { > + data_block_onebyte[0] = cmd42_para; > + } else { > + data_block[0] = cmd42_para; > + data_block[1] = pwd_len; > + memcpy((char *)(data_block+2), pwd, pwd_len); > + } > + > + memset(&idata, 0, sizeof(idata)); > + idata.write_flag = 1; > + idata.opcode = MMC_LOCK_UNLOCK; > + idata.arg = 0; //set all 0 for cmd42 arg > + idata.flags = MMC_RSP_R1 | MMC_CMD_AC | MMC_CMD_ADTC; > + idata.blksz = block_size; > + idata.blocks = 1; > + > + if (cmd42_para==MMC_CMD42_ERASE) > + mmc_ioc_cmd_set_data(idata, data_block_onebyte); > + else > + mmc_ioc_cmd_set_data(idata, data_block); > + > + ret = ioctl(fd, MMC_IOC_CMD, &idata); //Issue CMD42 > + > + r1_response = idata.response[0]; > + printf("cmd42 response: 0x%08x\n", r1_response); > + if (r1_response & R1_ERROR) { //check CMD42 error > + printf("cmd42 error! Error code: 0x%08x\n", r1_response & R1_ERROR); > + ret=-1; > + } > + if (r1_response & R1_LOCK_UNLOCK_FAILED) { //check lock/unlock error > + printf("Card lock/unlock fail! Error code: 0x%08x\n", > + r1_response & R1_LOCK_UNLOCK_FAILED); > + ret=-1; > + } > + > + close(fd); > + return ret; > +} > + > +//change data block length > +int set_block_len(int fd, int blk_len) > +{ > + int ret = 0; > + struct mmc_ioc_cmd idata; > + > + memset(&idata, 0, sizeof(idata)); > + idata.opcode = MMC_SET_BLOCKLEN; > + idata.arg = blk_len; > + idata.flags = MMC_RSP_R1 | MMC_CMD_AC; > + > + ret = ioctl(fd, MMC_IOC_CMD, &idata); > + > + return ret; > +} > + > static __u32 get_size_in_blks(int fd) > { > int res; > diff --git a/mmc_cmds.h b/mmc_cmds.h > index 5f2bef1..9ee78a2 100644 > --- a/mmc_cmds.h > +++ b/mmc_cmds.h > @@ -50,3 +50,5 @@ int do_general_cmd_read(int nargs, char **argv); > int do_softreset(int nargs, char **argv); > int do_preidle(int nargs, char **argv); > int do_alt_boot_op(int nargs, char **argv); > +int do_lock_unlock(int nargs, char **argv); > +int set_block_len(int fd, int blk_len);
Hi, Thanks for submitting this. Please add a proper commit log and run checkpatch so we can start review your code. Also, please let the title start with "mmc-utils: ". Thanks, Avri > From: Daniel Kucera <daniel.kucera@gmail.com> > > --- > mmc.c | 11 +++++ > mmc.h | 11 +++++ > mmc_cmds.c | 123 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > mmc_cmds.h | 2 + > 4 files changed, 147 insertions(+) > > diff --git a/mmc.c b/mmc.c > index bc8f74e..3ff7308 100644 > --- a/mmc.c > +++ b/mmc.c > @@ -250,6 +250,17 @@ static struct Command commands[] = { > "be 1.", > NULL > }, > + { do_lock_unlock, -3, > + "cmd42", "<password> " "<parameter> " "<device>\n" > + "Usage: mmc cmd42 <password> <s|c|l|u|e> <device>\n" > + "s\tset password\n" > + "c\tclear password\n" > + "l\tlock\n" > + "sl\tset password and lock\n" > + "u\tunlock\n" > + "e\tforce erase\n", > + NULL > + }, > { do_softreset, -1, > "softreset", "<device>\n" > "Issues a CMD0 softreset, e.g. for testing if hardware reset for UHS works", > diff --git a/mmc.h b/mmc.h > index 6f1bf3e..f8bac22 100644 > --- a/mmc.h > +++ b/mmc.h > @@ -30,6 +30,7 @@ > #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ > #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ > #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ > +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ > #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ > #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ > #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ > @@ -46,6 +47,7 @@ > [1] Discard Enable > [0] Identify Write Blocks for > Erase (or TRIM Enable) R1b */ > +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ > #define MMC_GEN_CMD 56 /* adtc [31:1] stuff bits. > [0]: RD/WR1 R1 */ > > @@ -70,6 +72,15 @@ > #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ > #define R1_APP_CMD (1 << 5) /* sr, c */ > > +#define MMC_CMD42_UNLOCK 0x0 /* UNLOCK */ > +#define MMC_CMD42_SET_PWD 0x1 /* SET_PWD */ > +#define MMC_CMD42_CLR_PWD 0x2 /* CLR_PWD */ > +#define MMC_CMD42_LOCK 0x4 /* LOCK */ > +#define MMC_CMD42_SET_LOCK 0x5 /* SET_PWD & LOCK */ > +#define MMC_CMD42_ERASE 0x8 /* ERASE */ > +#define MAX_PWD_LENGTH 32 /* max PWDS_LEN: old+new */ > +#define MMC_BLOCK_SIZE 512 /* data blk size for cmd42 */ > + > /* > * EXT_CSD fields > */ > diff --git a/mmc_cmds.c b/mmc_cmds.c > index 936e0c5..03fe04f 100644 > --- a/mmc_cmds.c > +++ b/mmc_cmds.c > @@ -129,6 +129,129 @@ int send_status(int fd, __u32 *response) > return ret; > } > > +//lock/unlock feature implementation > +int do_lock_unlock(int nargs, char **argv) > +{ > + int fd, ret = 0; > + char *device; > + __u8 data_block[MMC_BLOCK_SIZE]={0}; > + __u8 data_block_onebyte[1]={0}; > + int block_size = 0; > + struct mmc_ioc_cmd idata; > + int cmd42_para; //parameter of cmd42 > + char pwd[MAX_PWD_LENGTH+1]; //password > + int pwd_len; //password length > + __u32 r1_response; //R1 response token > + > + if (nargs != 4){ > + fprintf(stderr, "Usage: mmc cmd42 <password> <s|c|l|u|e> > <device>\n"); > + exit(1); > + } > + > + strcpy(pwd, argv[1]); > + pwd_len = strlen(pwd); > + > + if (!strcmp("s", argv[2])) { > + cmd42_para = MMC_CMD42_SET_PWD; > + printf("Set password: password=%s ...\n", pwd); > + } > + else if (!strcmp("c", argv[2])) { > + cmd42_para = MMC_CMD42_CLR_PWD; > + printf("Clear password: password=%s ...\n", pwd); > + } > + else if (!strcmp("l", argv[2])) { > + cmd42_para = MMC_CMD42_LOCK; > + printf("Lock the card: password=%s ...\n", pwd); > + } > + else if (!strcmp("sl", argv[2])) { > + cmd42_para = MMC_CMD42_SET_LOCK; > + printf("Set password and lock the card: password - %s ...\n", pwd); > + } > + else if (!strcmp("u", argv[2])) { > + cmd42_para = MMC_CMD42_UNLOCK; > + printf("Unlock the card: password=%s ...\n", pwd); > + } > + else if (!strcmp("e", argv[2])) { > + cmd42_para = MMC_CMD42_ERASE; > + printf("Force erase ... (Warning: all card data will be erased together > with PWD!)\n"); > + } > + else { > + printf("Invalid parameter:\n" "s\tset password\n" "c\tclear > password\n" "l\tlock\n" > + "sl\tset password and lock\n" "u\tunlock\n" "e\tforce erase\n"); > + exit(1); > + } > + > + device = argv[nargs-1]; > + > + fd = open(device, O_RDWR); > + if (fd < 0) { > + perror("open"); > + exit(1); > + } > + > + if (cmd42_para==MMC_CMD42_ERASE) > + block_size = 2; //set blk size to 2-byte for Force Erase @DDR50 > compability > + else > + block_size = MMC_BLOCK_SIZE; > + > + ret = set_block_len(fd, block_size); //set data block size prior to cmd42 > + printf("Set to data block length = %d byte(s).\n", block_size); > + > + if (cmd42_para==MMC_CMD42_ERASE) { > + data_block_onebyte[0] = cmd42_para; > + } else { > + data_block[0] = cmd42_para; > + data_block[1] = pwd_len; > + memcpy((char *)(data_block+2), pwd, pwd_len); > + } > + > + memset(&idata, 0, sizeof(idata)); > + idata.write_flag = 1; > + idata.opcode = MMC_LOCK_UNLOCK; > + idata.arg = 0; //set all 0 for cmd42 arg > + idata.flags = MMC_RSP_R1 | MMC_CMD_AC | MMC_CMD_ADTC; > + idata.blksz = block_size; > + idata.blocks = 1; > + > + if (cmd42_para==MMC_CMD42_ERASE) > + mmc_ioc_cmd_set_data(idata, data_block_onebyte); > + else > + mmc_ioc_cmd_set_data(idata, data_block); > + > + ret = ioctl(fd, MMC_IOC_CMD, &idata); //Issue CMD42 > + > + r1_response = idata.response[0]; > + printf("cmd42 response: 0x%08x\n", r1_response); > + if (r1_response & R1_ERROR) { //check CMD42 error > + printf("cmd42 error! Error code: 0x%08x\n", r1_response & R1_ERROR); > + ret=-1; > + } > + if (r1_response & R1_LOCK_UNLOCK_FAILED) { //check lock/unlock error > + printf("Card lock/unlock fail! Error code: 0x%08x\n", > + r1_response & R1_LOCK_UNLOCK_FAILED); > + ret=-1; > + } > + > + close(fd); > + return ret; > +} > + > +//change data block length > +int set_block_len(int fd, int blk_len) > +{ > + int ret = 0; > + struct mmc_ioc_cmd idata; > + > + memset(&idata, 0, sizeof(idata)); > + idata.opcode = MMC_SET_BLOCKLEN; > + idata.arg = blk_len; > + idata.flags = MMC_RSP_R1 | MMC_CMD_AC; > + > + ret = ioctl(fd, MMC_IOC_CMD, &idata); > + > + return ret; > +} > + > static __u32 get_size_in_blks(int fd) > { > int res; > diff --git a/mmc_cmds.h b/mmc_cmds.h > index 5f2bef1..9ee78a2 100644 > --- a/mmc_cmds.h > +++ b/mmc_cmds.h > @@ -50,3 +50,5 @@ int do_general_cmd_read(int nargs, char **argv); > int do_softreset(int nargs, char **argv); > int do_preidle(int nargs, char **argv); > int do_alt_boot_op(int nargs, char **argv); > +int do_lock_unlock(int nargs, char **argv); > +int set_block_len(int fd, int blk_len); > -- > 2.34.1
Let me elaborate on that. First I wanted to have the (un)locking function implemented in mmc-utils so there is a way to use it. Locking works fine with the hardware I tested: rtsx_pci_sdmmc, rtsx_usb_sdmmc and meson-gx-mmc (in Allwinner s905w SoC). After locking and reinserting, the card is not detected but I have a kernel patch for that (does attachment work in mailing list?) which skips setup commands which are not allowed during locked state. This allows the device /dev/mmcblkX to be created and ioctl calls run against it. When the card is locked, all read/write calls are naturally timing out and it is indicated in dmesg. Unlocking using mmc-utils works fine with meson-gx-mmc. After unlocking, direct reads (dd if=/dev/mmcblkX) work fine but reloading partition table is necessary as the first attempts have failed. Unlocking doesn't work on both rtsx* drivers (PCIe and USB MMC card readers common in laptops) - I suspect this is a bug in the device driver. IMO it is not more dangerous than other functions already implemented in mmc-utils, e.g. erase. D. On 2024-05-18 22:42, Christian Loehle wrote: > On 5/18/24 17:26, linux-mmc@danman.eu wrote: >> ------ Tessian Warning ------ >> >> Be careful, the email's sending domain "@danman[.]eu" has never been >> seen on your company's network before today >> >> This warning message will be removed if you reply to or forward this >> email to a recipient outside of your organization. >> >> ---- Tessian Warning End ---- >> >> From: Daniel Kucera <daniel.kucera@gmail.com> > > Locking is pretty bad, at least for SD it's highly problematic with > current mmcblk, as locked cards won't > initialize AFAIR (SD status query is illegal, but initialization > requires it if I remember correctly). > Did you try that? > >> >> --- >> mmc.c | 11 +++++ >> mmc.h | 11 +++++ >> mmc_cmds.c | 123 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++ >> mmc_cmds.h | 2 + >> 4 files changed, 147 insertions(+) >> >> diff --git a/mmc.c b/mmc.c >> index bc8f74e..3ff7308 100644 >> --- a/mmc.c >> +++ b/mmc.c >> @@ -250,6 +250,17 @@ static struct Command commands[] = { >> "be 1.", >> NULL >> }, >> + { do_lock_unlock, -3, >> + "cmd42", "<password> " "<parameter> " "<device>\n" >> + "Usage: mmc cmd42 <password> <s|c|l|u|e> <device>\n" >> + "s\tset password\n" >> + "c\tclear password\n" >> + "l\tlock\n" >> + "sl\tset password and lock\n" >> + "u\tunlock\n" >> + "e\tforce erase\n", >> + NULL >> + }, >> { do_softreset, -1, >> "softreset", "<device>\n" >> "Issues a CMD0 softreset, e.g. for testing if hardware reset for >> UHS works", >> diff --git a/mmc.h b/mmc.h >> index 6f1bf3e..f8bac22 100644 >> --- a/mmc.h >> +++ b/mmc.h >> @@ -30,6 +30,7 @@ >> #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ >> #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ >> #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ >> +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ >> #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 >> */ >> #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 >> */ >> #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ >> @@ -46,6 +47,7 @@ >> [1] Discard Enable >> [0] Identify Write Blocks for >> Erase (or TRIM Enable) R1b */ >> +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ >> #define MMC_GEN_CMD 56 /* adtc [31:1] stuff bits. >> [0]: RD/WR1 R1 */ >> >> @@ -70,6 +72,15 @@ >> #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ >> #define R1_APP_CMD (1 << 5) /* sr, c */ >> >> +#define MMC_CMD42_UNLOCK 0x0 /* UNLOCK */ >> +#define MMC_CMD42_SET_PWD 0x1 /* SET_PWD */ >> +#define MMC_CMD42_CLR_PWD 0x2 /* CLR_PWD */ >> +#define MMC_CMD42_LOCK 0x4 /* LOCK */ >> +#define MMC_CMD42_SET_LOCK 0x5 /* SET_PWD & LOCK */ >> +#define MMC_CMD42_ERASE 0x8 /* ERASE */ >> +#define MAX_PWD_LENGTH 32 /* max PWDS_LEN: old+new */ >> +#define MMC_BLOCK_SIZE 512 /* data blk size for cmd42 */ >> + >> /* >> * EXT_CSD fields >> */ >> diff --git a/mmc_cmds.c b/mmc_cmds.c >> index 936e0c5..03fe04f 100644 >> --- a/mmc_cmds.c >> +++ b/mmc_cmds.c >> @@ -129,6 +129,129 @@ int send_status(int fd, __u32 *response) >> return ret; >> } >> >> +//lock/unlock feature implementation >> +int do_lock_unlock(int nargs, char **argv) >> +{ >> + int fd, ret = 0; >> + char *device; >> + __u8 data_block[MMC_BLOCK_SIZE]={0}; >> + __u8 data_block_onebyte[1]={0}; >> + int block_size = 0; >> + struct mmc_ioc_cmd idata; >> + int cmd42_para; //parameter of cmd42 >> + char pwd[MAX_PWD_LENGTH+1]; //password >> + int pwd_len; //password length >> + __u32 r1_response; //R1 response token >> + >> + if (nargs != 4){ >> + fprintf(stderr, "Usage: mmc cmd42 <password> <s|c|l|u|e> >> <device>\n"); >> + exit(1); >> + } >> + >> + strcpy(pwd, argv[1]); >> + pwd_len = strlen(pwd); >> + >> + if (!strcmp("s", argv[2])) { >> + cmd42_para = MMC_CMD42_SET_PWD; >> + printf("Set password: password=%s ...\n", pwd); >> + } >> + else if (!strcmp("c", argv[2])) { >> + cmd42_para = MMC_CMD42_CLR_PWD; >> + printf("Clear password: password=%s ...\n", pwd); >> + } >> + else if (!strcmp("l", argv[2])) { >> + cmd42_para = MMC_CMD42_LOCK; >> + printf("Lock the card: password=%s ...\n", pwd); >> + } >> + else if (!strcmp("sl", argv[2])) { >> + cmd42_para = MMC_CMD42_SET_LOCK; >> + printf("Set password and lock the card: password - %s ...\n", pwd); >> + } >> + else if (!strcmp("u", argv[2])) { >> + cmd42_para = MMC_CMD42_UNLOCK; >> + printf("Unlock the card: password=%s ...\n", pwd); >> + } >> + else if (!strcmp("e", argv[2])) { >> + cmd42_para = MMC_CMD42_ERASE; >> + printf("Force erase ... (Warning: all card data will be erased >> together with PWD!)\n"); >> + } >> + else { >> + printf("Invalid parameter:\n" "s\tset password\n" "c\tclear >> password\n" "l\tlock\n" >> + "sl\tset password and lock\n" "u\tunlock\n" "e\tforce erase\n"); >> + exit(1); >> + } >> + >> + device = argv[nargs-1]; >> + >> + fd = open(device, O_RDWR); >> + if (fd < 0) { >> + perror("open"); >> + exit(1); >> + } >> + >> + if (cmd42_para==MMC_CMD42_ERASE) >> + block_size = 2; //set blk size to 2-byte for Force Erase @DDR50 >> compability >> + else >> + block_size = MMC_BLOCK_SIZE; >> + >> + ret = set_block_len(fd, block_size); //set data block size prior to >> cmd42 >> + printf("Set to data block length = %d byte(s).\n", block_size); >> + >> + if (cmd42_para==MMC_CMD42_ERASE) { >> + data_block_onebyte[0] = cmd42_para; >> + } else { >> + data_block[0] = cmd42_para; >> + data_block[1] = pwd_len; >> + memcpy((char *)(data_block+2), pwd, pwd_len); >> + } >> + >> + memset(&idata, 0, sizeof(idata)); >> + idata.write_flag = 1; >> + idata.opcode = MMC_LOCK_UNLOCK; >> + idata.arg = 0; //set all 0 for cmd42 arg >> + idata.flags = MMC_RSP_R1 | MMC_CMD_AC | MMC_CMD_ADTC; >> + idata.blksz = block_size; >> + idata.blocks = 1; >> + >> + if (cmd42_para==MMC_CMD42_ERASE) >> + mmc_ioc_cmd_set_data(idata, data_block_onebyte); >> + else >> + mmc_ioc_cmd_set_data(idata, data_block); >> + >> + ret = ioctl(fd, MMC_IOC_CMD, &idata); //Issue CMD42 >> + >> + r1_response = idata.response[0]; >> + printf("cmd42 response: 0x%08x\n", r1_response); >> + if (r1_response & R1_ERROR) { //check CMD42 error >> + printf("cmd42 error! Error code: 0x%08x\n", r1_response & >> R1_ERROR); >> + ret=-1; >> + } >> + if (r1_response & R1_LOCK_UNLOCK_FAILED) { //check lock/unlock error >> + printf("Card lock/unlock fail! Error code: 0x%08x\n", >> + r1_response & R1_LOCK_UNLOCK_FAILED); >> + ret=-1; >> + } >> + >> + close(fd); >> + return ret; >> +} >> + >> +//change data block length >> +int set_block_len(int fd, int blk_len) >> +{ >> + int ret = 0; >> + struct mmc_ioc_cmd idata; >> + >> + memset(&idata, 0, sizeof(idata)); >> + idata.opcode = MMC_SET_BLOCKLEN; >> + idata.arg = blk_len; >> + idata.flags = MMC_RSP_R1 | MMC_CMD_AC; >> + >> + ret = ioctl(fd, MMC_IOC_CMD, &idata); >> + >> + return ret; >> +} >> + >> static __u32 get_size_in_blks(int fd) >> { >> int res; >> diff --git a/mmc_cmds.h b/mmc_cmds.h >> index 5f2bef1..9ee78a2 100644 >> --- a/mmc_cmds.h >> +++ b/mmc_cmds.h >> @@ -50,3 +50,5 @@ int do_general_cmd_read(int nargs, char **argv); >> int do_softreset(int nargs, char **argv); >> int do_preidle(int nargs, char **argv); >> int do_alt_boot_op(int nargs, char **argv); >> +int do_lock_unlock(int nargs, char **argv); >> +int set_block_len(int fd, int blk_len);
diff --git a/mmc.c b/mmc.c index bc8f74e..3ff7308 100644 --- a/mmc.c +++ b/mmc.c @@ -250,6 +250,17 @@ static struct Command commands[] = { "be 1.", NULL }, + { do_lock_unlock, -3, + "cmd42", "<password> " "<parameter> " "<device>\n" + "Usage: mmc cmd42 <password> <s|c|l|u|e> <device>\n" + "s\tset password\n" + "c\tclear password\n" + "l\tlock\n" + "sl\tset password and lock\n" + "u\tunlock\n" + "e\tforce erase\n", + NULL + }, { do_softreset, -1, "softreset", "<device>\n" "Issues a CMD0 softreset, e.g. for testing if hardware reset for UHS works", diff --git a/mmc.h b/mmc.h index 6f1bf3e..f8bac22 100644 --- a/mmc.h +++ b/mmc.h @@ -30,6 +30,7 @@ #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ @@ -46,6 +47,7 @@ [1] Discard Enable [0] Identify Write Blocks for Erase (or TRIM Enable) R1b */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ #define MMC_GEN_CMD 56 /* adtc [31:1] stuff bits. [0]: RD/WR1 R1 */ @@ -70,6 +72,15 @@ #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ #define R1_APP_CMD (1 << 5) /* sr, c */ +#define MMC_CMD42_UNLOCK 0x0 /* UNLOCK */ +#define MMC_CMD42_SET_PWD 0x1 /* SET_PWD */ +#define MMC_CMD42_CLR_PWD 0x2 /* CLR_PWD */ +#define MMC_CMD42_LOCK 0x4 /* LOCK */ +#define MMC_CMD42_SET_LOCK 0x5 /* SET_PWD & LOCK */ +#define MMC_CMD42_ERASE 0x8 /* ERASE */ +#define MAX_PWD_LENGTH 32 /* max PWDS_LEN: old+new */ +#define MMC_BLOCK_SIZE 512 /* data blk size for cmd42 */ + /* * EXT_CSD fields */ diff --git a/mmc_cmds.c b/mmc_cmds.c index 936e0c5..03fe04f 100644 --- a/mmc_cmds.c +++ b/mmc_cmds.c @@ -129,6 +129,129 @@ int send_status(int fd, __u32 *response) return ret; } +//lock/unlock feature implementation +int do_lock_unlock(int nargs, char **argv) +{ + int fd, ret = 0; + char *device; + __u8 data_block[MMC_BLOCK_SIZE]={0}; + __u8 data_block_onebyte[1]={0}; + int block_size = 0; + struct mmc_ioc_cmd idata; + int cmd42_para; //parameter of cmd42 + char pwd[MAX_PWD_LENGTH+1]; //password + int pwd_len; //password length + __u32 r1_response; //R1 response token + + if (nargs != 4){ + fprintf(stderr, "Usage: mmc cmd42 <password> <s|c|l|u|e> <device>\n"); + exit(1); + } + + strcpy(pwd, argv[1]); + pwd_len = strlen(pwd); + + if (!strcmp("s", argv[2])) { + cmd42_para = MMC_CMD42_SET_PWD; + printf("Set password: password=%s ...\n", pwd); + } + else if (!strcmp("c", argv[2])) { + cmd42_para = MMC_CMD42_CLR_PWD; + printf("Clear password: password=%s ...\n", pwd); + } + else if (!strcmp("l", argv[2])) { + cmd42_para = MMC_CMD42_LOCK; + printf("Lock the card: password=%s ...\n", pwd); + } + else if (!strcmp("sl", argv[2])) { + cmd42_para = MMC_CMD42_SET_LOCK; + printf("Set password and lock the card: password - %s ...\n", pwd); + } + else if (!strcmp("u", argv[2])) { + cmd42_para = MMC_CMD42_UNLOCK; + printf("Unlock the card: password=%s ...\n", pwd); + } + else if (!strcmp("e", argv[2])) { + cmd42_para = MMC_CMD42_ERASE; + printf("Force erase ... (Warning: all card data will be erased together with PWD!)\n"); + } + else { + printf("Invalid parameter:\n" "s\tset password\n" "c\tclear password\n" "l\tlock\n" + "sl\tset password and lock\n" "u\tunlock\n" "e\tforce erase\n"); + exit(1); + } + + device = argv[nargs-1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + perror("open"); + exit(1); + } + + if (cmd42_para==MMC_CMD42_ERASE) + block_size = 2; //set blk size to 2-byte for Force Erase @DDR50 compability + else + block_size = MMC_BLOCK_SIZE; + + ret = set_block_len(fd, block_size); //set data block size prior to cmd42 + printf("Set to data block length = %d byte(s).\n", block_size); + + if (cmd42_para==MMC_CMD42_ERASE) { + data_block_onebyte[0] = cmd42_para; + } else { + data_block[0] = cmd42_para; + data_block[1] = pwd_len; + memcpy((char *)(data_block+2), pwd, pwd_len); + } + + memset(&idata, 0, sizeof(idata)); + idata.write_flag = 1; + idata.opcode = MMC_LOCK_UNLOCK; + idata.arg = 0; //set all 0 for cmd42 arg + idata.flags = MMC_RSP_R1 | MMC_CMD_AC | MMC_CMD_ADTC; + idata.blksz = block_size; + idata.blocks = 1; + + if (cmd42_para==MMC_CMD42_ERASE) + mmc_ioc_cmd_set_data(idata, data_block_onebyte); + else + mmc_ioc_cmd_set_data(idata, data_block); + + ret = ioctl(fd, MMC_IOC_CMD, &idata); //Issue CMD42 + + r1_response = idata.response[0]; + printf("cmd42 response: 0x%08x\n", r1_response); + if (r1_response & R1_ERROR) { //check CMD42 error + printf("cmd42 error! Error code: 0x%08x\n", r1_response & R1_ERROR); + ret=-1; + } + if (r1_response & R1_LOCK_UNLOCK_FAILED) { //check lock/unlock error + printf("Card lock/unlock fail! Error code: 0x%08x\n", + r1_response & R1_LOCK_UNLOCK_FAILED); + ret=-1; + } + + close(fd); + return ret; +} + +//change data block length +int set_block_len(int fd, int blk_len) +{ + int ret = 0; + struct mmc_ioc_cmd idata; + + memset(&idata, 0, sizeof(idata)); + idata.opcode = MMC_SET_BLOCKLEN; + idata.arg = blk_len; + idata.flags = MMC_RSP_R1 | MMC_CMD_AC; + + ret = ioctl(fd, MMC_IOC_CMD, &idata); + + return ret; +} + static __u32 get_size_in_blks(int fd) { int res; diff --git a/mmc_cmds.h b/mmc_cmds.h index 5f2bef1..9ee78a2 100644 --- a/mmc_cmds.h +++ b/mmc_cmds.h @@ -50,3 +50,5 @@ int do_general_cmd_read(int nargs, char **argv); int do_softreset(int nargs, char **argv); int do_preidle(int nargs, char **argv); int do_alt_boot_op(int nargs, char **argv); +int do_lock_unlock(int nargs, char **argv); +int set_block_len(int fd, int blk_len);
From: Daniel Kucera <daniel.kucera@gmail.com> --- mmc.c | 11 +++++ mmc.h | 11 +++++ mmc_cmds.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mmc_cmds.h | 2 + 4 files changed, 147 insertions(+)