660 lines
17 KiB
C
660 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Rockchip UFS Host Controller driver
|
|
*
|
|
* Copyright (C) 2024 Rockchip Electronics Co.Ltd.
|
|
*/
|
|
|
|
#include <command.h>
|
|
#include <charset.h>
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <log.h>
|
|
#include <dm/lists.h>
|
|
#include <dm/device-internal.h>
|
|
#include <malloc.h>
|
|
#include <hexdump.h>
|
|
#include <scsi.h>
|
|
#include <asm/io.h>
|
|
#include <asm/dma-mapping.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include "ufs.h"
|
|
#include "ufs-rockchip-rpmb.h"
|
|
#include <u-boot/sha256.h>
|
|
|
|
extern int ufs_send_scsi_cmd(struct ufs_hba *hba, struct scsi_cmd *pccb);
|
|
|
|
#define UFS_OP_SECURITY_PROTOCOL_IN 0xA2
|
|
#define UFS_OP_SECURITY_PROTOCOL_OUT 0xB5
|
|
#define UFS_OP_TST_U_RDY 0x00
|
|
#define UFS_RPMB_KEY_SZ 32
|
|
#define SHA256_BLOCK_SIZE 64
|
|
|
|
static struct ufs_hba *rpmb_hba;
|
|
|
|
struct lu_info_tbl {
|
|
int lu_index;
|
|
uint32_t log2blksz;
|
|
uint64_t blkcnt;
|
|
};
|
|
|
|
struct lu_info_tbl rpmb_lu_info = {0};
|
|
static struct scsi_cmd tempccb; /* temporary scsi command buffer */
|
|
|
|
static void u16_to_bytes(uint16_t u16, uint8_t *bytes)
|
|
{
|
|
*bytes = (uint8_t) (u16 >> 8);
|
|
*(bytes + 1) = (uint8_t) u16;
|
|
}
|
|
|
|
static void bytes_to_u16(uint8_t *bytes, uint16_t *u16)
|
|
{
|
|
*u16 = (uint16_t) ((*bytes << 8) + *(bytes + 1));
|
|
}
|
|
|
|
static void bytes_to_u32(uint8_t *bytes, uint32_t *u32)
|
|
{
|
|
*u32 = (uint32_t) ((*(bytes) << 24) +
|
|
(*(bytes + 1) << 16) +
|
|
(*(bytes + 2) << 8) + (*(bytes + 3)));
|
|
}
|
|
|
|
static void u32_to_bytes(uint32_t u32, uint8_t *bytes)
|
|
{
|
|
*bytes = (uint8_t) (u32 >> 24);
|
|
*(bytes + 1) = (uint8_t) (u32 >> 16);
|
|
*(bytes + 2) = (uint8_t) (u32 >> 8);
|
|
*(bytes + 3) = (uint8_t) u32;
|
|
}
|
|
|
|
static int hba_test(struct ufs_hba *hba)
|
|
{
|
|
if (!hba) {
|
|
printf("No UFS device!\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void scsi_secproc_in(struct scsi_cmd *pccb, uint32_t lba, uint32_t size)
|
|
{
|
|
pccb->cmd[0] = UFS_OP_SECURITY_PROTOCOL_IN; /* 0: opcode */
|
|
pccb->cmd[1] = 0xEC; /* 1: security protocal */
|
|
pccb->cmd[2] = 0; /* 2: specific */
|
|
pccb->cmd[3] = 0x1; /* 3: specific */
|
|
pccb->cmd[4] = 0; /* 4: reserved */
|
|
pccb->cmd[5] = 0; /* 5: reserved */
|
|
pccb->cmd[6] = (uint8_t)((size >> 24) & 0xff); /* 6: MSB, shift 24 */
|
|
pccb->cmd[7] = (uint8_t)((size >> 16) & 0xff); /* 7: MSB, shift 16 */
|
|
pccb->cmd[8] = (uint8_t)((size >> 8) & 0xff); /* 8: LSB, shift 8 */
|
|
pccb->cmd[9] = (uint8_t)(size & 0xff); /* 9: LSB */
|
|
pccb->cmd[10] = 0; /* 10: reserved */
|
|
pccb->cmd[11] = 0; /* 11: control */
|
|
|
|
pccb->cmdlen = 12;
|
|
}
|
|
|
|
static void scsi_secproc_out(struct scsi_cmd *pccb, uint32_t lba, uint32_t size)
|
|
{
|
|
pccb->cmd[0] = UFS_OP_SECURITY_PROTOCOL_OUT; /* 0: opcode */
|
|
pccb->cmd[1] = 0xEC; /* 1: security protocal */
|
|
pccb->cmd[2] = 0; /* 2: specific */
|
|
pccb->cmd[3] = 0x1; /* 3: specific */
|
|
pccb->cmd[4] = 0; /* 4: reserved */
|
|
pccb->cmd[5] = 0; /* 5: reserved */
|
|
pccb->cmd[6] = (uint8_t)((size >> 24) & 0xff); /* 6: MSB, shift 24 */
|
|
pccb->cmd[7] = (uint8_t)((size >> 16) & 0xff); /* 7: MSB, shift 16 */
|
|
pccb->cmd[8] = (uint8_t)((size >> 8) & 0xff); /* 8: LSB, shift 8 */
|
|
pccb->cmd[9] = (uint8_t)(size & 0xff); /* 9: LSB */
|
|
pccb->cmd[10] = 0; /* 10: reserved */
|
|
pccb->cmd[11] = 0; /* 11: control */
|
|
|
|
pccb->cmdlen = 12;
|
|
}
|
|
|
|
static void scsi_test_unit_ready(struct scsi_cmd *pccb)
|
|
{
|
|
pccb->cmd[0] = UFS_OP_TST_U_RDY;
|
|
pccb->cmd[1] = pccb->lun << 5;
|
|
pccb->cmd[2] = 0;
|
|
pccb->cmd[3] = 0;
|
|
pccb->cmd[4] = 0;
|
|
pccb->cmd[5] = 0;
|
|
pccb->cmdlen = 6;
|
|
}
|
|
|
|
static int rpmb_send_scsi_cmd(struct ufs_hba *hba, uint32_t opcode, int dma_dir, int lun,
|
|
void *buf_addr, lbaint_t start, lbaint_t blkcnt)
|
|
{
|
|
struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
|
|
|
|
pccb->lun = lun;
|
|
pccb->pdata = buf_addr;
|
|
pccb->dma_dir = dma_dir;
|
|
pccb->datalen = blkcnt * sizeof(struct rpmb_data_frame);
|
|
|
|
if (opcode == UFS_OP_SECURITY_PROTOCOL_OUT) {
|
|
scsi_secproc_out(pccb, start, pccb->datalen);
|
|
pccb->cmdlen = 12;
|
|
} else if (opcode == UFS_OP_SECURITY_PROTOCOL_IN) {
|
|
scsi_secproc_in(pccb, start, pccb->datalen);
|
|
pccb->cmdlen = 12;
|
|
} else if (opcode == UFS_OP_TST_U_RDY) {
|
|
scsi_test_unit_ready(pccb);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ufs_send_scsi_cmd(hba, pccb);
|
|
}
|
|
|
|
static void ufs_rpmb_hmac(unsigned char *key, struct rpmb_data_frame *frames_in, ssize_t blocks_cnt,
|
|
unsigned char *output)
|
|
{
|
|
sha256_context ctx;
|
|
int i;
|
|
unsigned char k_ipad[SHA256_BLOCK_SIZE];
|
|
unsigned char k_opad[SHA256_BLOCK_SIZE];
|
|
|
|
sha256_starts(&ctx);
|
|
|
|
/* According to RFC 4634, the HMAC transform looks like:
|
|
SHA(K XOR opad, SHA(K XOR ipad, text))
|
|
|
|
where K is an n byte key.
|
|
ipad is the byte 0x36 repeated blocksize times
|
|
opad is the byte 0x5c repeated blocksize times
|
|
and text is the data being protected.
|
|
*/
|
|
|
|
for (i = 0; i < UFS_RPMB_KEY_SZ; i++) {
|
|
k_ipad[i] = key[i] ^ 0x36;
|
|
k_opad[i] = key[i] ^ 0x5c;
|
|
}
|
|
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
|
|
for ( ; i < SHA256_BLOCK_SIZE; i++) {
|
|
k_ipad[i] = 0x36;
|
|
k_opad[i] = 0x5c;
|
|
}
|
|
sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
|
|
|
|
for (i = 0; i < blocks_cnt; i++)
|
|
sha256_update(&ctx, frames_in[i].data, RPMB_DATA_HAM_SIZE);
|
|
|
|
sha256_finish(&ctx, output);
|
|
|
|
/* Init context for second pass */
|
|
sha256_starts(&ctx);
|
|
|
|
/* start with outer pad */
|
|
sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
|
|
|
|
/* then results of 1st hash */
|
|
sha256_update(&ctx, output, UFS_RPMB_KEY_SZ);
|
|
|
|
/* finish up 2nd pass */
|
|
sha256_finish(&ctx, output);
|
|
}
|
|
|
|
int prepare_rpmb_lu(void)
|
|
{
|
|
struct ufs_rpmb_unit_desc_tbl rpmb_unit_desc;
|
|
uint64_t block_count = 0;
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = ufshcd_read_desc_param(rpmb_hba, QUERY_DESC_IDN_UNIT, 0xc4, 0, (u8 *)&rpmb_unit_desc,
|
|
QUERY_DESC_UNIT_DEF_SIZE);
|
|
if (ret) {
|
|
dev_err(hba->dev, "%s: Failed reading RPMB Desc. err = %d\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
block_count = be64_to_cpu(rpmb_unit_desc.qLogicalBlockCount);
|
|
if (block_count) {
|
|
rpmb_lu_info.lu_index = 0xc4;
|
|
rpmb_lu_info.blkcnt = block_count;
|
|
rpmb_lu_info.log2blksz = rpmb_unit_desc.bLogicalBlockSize;
|
|
/*
|
|
* write key,read counter,write data,
|
|
* need this test_unit_ready operation.
|
|
*/
|
|
ret = rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_TST_U_RDY, DMA_NONE, rpmb_lu_info.lu_index,
|
|
NULL, 0, 0);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* @retrun 0 rpmb key unwritten */
|
|
int is_wr_ufs_rpmb_key(void)
|
|
{
|
|
int ret = 0;
|
|
struct rpmb_data_frame *data_frame;
|
|
uint16_t msg_type;
|
|
uint16_t op_result;
|
|
uint8_t nonce[RPMB_NONCE_SIZE] = {
|
|
0xa5, 0x5a, 0xff, 0x00, 0xbe, 0xef, 0xbe, 0xef,
|
|
0xbe, 0xef, 0xbe, 0xef, 0x00, 0xff, 0x5a, 0xa5
|
|
};
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (rpmb_lu_info.log2blksz == 0) {
|
|
ret = prepare_rpmb_lu();
|
|
if(0 != ret)
|
|
return ret;
|
|
}
|
|
|
|
msg_type = RPMB_READ;
|
|
data_frame = memalign(ARCH_DMA_MINALIGN, RPMB_DATA_FRAME_SIZE);
|
|
if (!data_frame) {
|
|
printf("%s malloc error\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
u16_to_bytes(msg_type, data_frame->msg_type);
|
|
memcpy(data_frame->nonce, nonce, RPMB_NONCE_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_IN, DMA_FROM_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
/* result check */
|
|
bytes_to_u16(data_frame->op_result, &op_result);
|
|
bytes_to_u16(data_frame->msg_type, &msg_type);
|
|
if (op_result == RPMB_RES_NO_AUTH_KEY) {
|
|
printf("%s rpmb key not write\n", __func__);
|
|
ret = 0;
|
|
} else {
|
|
printf("%s rpmb key has been written\n", __func__);
|
|
ret = -1;
|
|
}
|
|
free(data_frame);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t ufs_rpmb_read_writecount(void)
|
|
{
|
|
struct rpmb_data_frame *data_frame;
|
|
uint16_t msg_type;
|
|
uint16_t op_result;
|
|
uint32_t writecount;
|
|
uint8_t nonce[RPMB_NONCE_SIZE] = {
|
|
0xa5, 0x5a, 0xff, 0x00, 0xbe, 0xef, 0xbe, 0xef,
|
|
0xbe, 0xef, 0xbe, 0xef, 0x00, 0xff, 0x5a,0xa5
|
|
};
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (rpmb_lu_info.log2blksz == 0) {
|
|
ret = prepare_rpmb_lu();
|
|
if (ret != 0) {
|
|
printf("prepare rpmb unit failed!\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
msg_type = RPMB_READ_CNT;
|
|
data_frame = memalign(ARCH_DMA_MINALIGN, RPMB_DATA_FRAME_SIZE);
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
u16_to_bytes(msg_type, data_frame->msg_type);
|
|
memcpy(data_frame->nonce, nonce, RPMB_NONCE_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_IN, DMA_FROM_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
/* result check */
|
|
bytes_to_u16(data_frame->op_result, &op_result);
|
|
bytes_to_u16(data_frame->msg_type, &msg_type);
|
|
if ((op_result == RPMB_RESULT_OK) &&
|
|
(msg_type == RPMB_RESP_WRITE_COUNTER_VAL_READ)) {
|
|
bytes_to_u32(data_frame->write_counter, &writecount);
|
|
printf("read write count successed\n");
|
|
free(data_frame);
|
|
return writecount;
|
|
}
|
|
else
|
|
printf(" read write count:0x%x ,msg_type:0x%x\n",
|
|
op_result,msg_type);
|
|
free(data_frame);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* blk_data: for save read data;
|
|
* blk_index: the block index for read;
|
|
* block_count: the read count;
|
|
* success return 0;
|
|
*/
|
|
int ufs_rpmb_blk_read(char *blk_data, uint8_t *key, uint16_t blk_index, uint16_t block_count)
|
|
{
|
|
struct rpmb_data_frame *data_frame;
|
|
struct rpmb_data_frame *resp_buf;
|
|
uint16_t msg_type;
|
|
uint16_t op_result;
|
|
uint8_t nonce[RPMB_NONCE_SIZE] = {
|
|
0xa5, 0x5a, 0xff, 0x00, 0xbe, 0xef, 0xbe, 0xef,
|
|
0xbe, 0xef, 0xbe, 0xef, 0x00, 0xef, 0x5a,0xa5
|
|
};
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (rpmb_lu_info.log2blksz == 0) {
|
|
ret = prepare_rpmb_lu();
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
if (!blk_data) {
|
|
printf("rpmb_blk_read null \n");
|
|
return 0;
|
|
}
|
|
|
|
msg_type = RPMB_READ;
|
|
data_frame = memalign(ARCH_DMA_MINALIGN, RPMB_DATA_FRAME_SIZE);
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
u16_to_bytes(msg_type, data_frame->msg_type);
|
|
u16_to_bytes(blk_index, data_frame->address);
|
|
u16_to_bytes(block_count, data_frame->block_count);
|
|
memcpy(data_frame->nonce, nonce, RPMB_NONCE_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
resp_buf = memalign(ARCH_DMA_MINALIGN, RPMB_DATA_FRAME_SIZE * block_count);
|
|
memset(resp_buf, 0, RPMB_DATA_FRAME_SIZE * block_count);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_IN, DMA_FROM_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)resp_buf, 0, block_count);
|
|
|
|
/* result check */
|
|
bytes_to_u16((resp_buf + block_count - 1)->op_result, &op_result);
|
|
bytes_to_u16((resp_buf + block_count - 1)->msg_type, &msg_type);
|
|
if ((op_result == RPMB_RESULT_OK) &&
|
|
(msg_type == RPMB_RESP_AUTH_DATA_READ)) {
|
|
uint8_t i = 0;
|
|
for (i = 0; i < block_count; i++)
|
|
memcpy((blk_data + i * RPMB_DATA_SIZE),
|
|
((uint8_t *) (resp_buf + i) +
|
|
RPMB_STUFF_DATA_SIZE + RPMB_KEY_MAC_SIZE),
|
|
RPMB_DATA_SIZE);
|
|
printf("read successed\n");
|
|
free(resp_buf);
|
|
free(data_frame);
|
|
return block_count;
|
|
} else
|
|
printf("read write count:0x%x ,msg_type:0x%x\n", op_result, msg_type);
|
|
|
|
free(resp_buf);
|
|
free(data_frame);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* write_data: data for write
|
|
* blk_index: the block will be write to;
|
|
* success return 0
|
|
*/
|
|
|
|
/* for single data */
|
|
int ufs_rpmb_blk_write(char *write_data, uint8_t *key, uint16_t blk_index, uint16_t blk_count)
|
|
{
|
|
struct rpmb_data_frame *data_frame;
|
|
uint16_t msg_type;
|
|
uint16_t op_result;
|
|
uint32_t writecount;
|
|
int ret = 0, i;
|
|
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if(rpmb_lu_info.log2blksz == 0) {
|
|
ret = prepare_rpmb_lu();
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
if (!write_data)
|
|
return 1;
|
|
|
|
/* TODO: The following codes is multiple block write
|
|
* for(int i=0;i<(strlen(write_data)/RPMB_DATA_SIZE),i++){
|
|
*/
|
|
|
|
msg_type = RPMB_WRITE;
|
|
data_frame = memalign(ARCH_DMA_MINALIGN, RPMB_DATA_FRAME_SIZE * blk_count);
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE * blk_count);
|
|
writecount = ufs_rpmb_read_writecount();
|
|
|
|
for (i = 0; i < blk_count; i++) {
|
|
u16_to_bytes(msg_type, data_frame[i].msg_type);
|
|
u16_to_bytes(blk_index, data_frame[i].address);
|
|
u16_to_bytes(blk_count, data_frame[i].block_count);
|
|
u32_to_bytes(writecount, data_frame[i].write_counter);
|
|
memcpy(data_frame[i].data, write_data, RPMB_DATA_SIZE);
|
|
write_data += RPMB_DATA_FRAME_SIZE;
|
|
}
|
|
|
|
ufs_rpmb_hmac(key, data_frame, blk_count, data_frame[blk_count - 1].key_mac);
|
|
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, blk_count);
|
|
|
|
/* for read result req */
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
msg_type = RPMB_READ_RESP;
|
|
u16_to_bytes(msg_type, data_frame->msg_type);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_IN, DMA_FROM_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, 1);
|
|
|
|
/* result check */
|
|
bytes_to_u16(data_frame->op_result, &op_result);
|
|
bytes_to_u16(data_frame->msg_type, &msg_type);
|
|
if ((op_result == RPMB_RESULT_OK) && (msg_type == RPMB_RESP_AUTH_DATA_WRITE)) {
|
|
printf(" data write successed\n");
|
|
free(data_frame);
|
|
return blk_count;
|
|
} else {
|
|
printf(" data write fail op_result:0x%x ,msg_type:0x%x\n", op_result, msg_type);
|
|
}
|
|
|
|
free(data_frame);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* key: the key will write must 32 len;
|
|
* len :must be 32;
|
|
* reutrn 0 success
|
|
*/
|
|
int ufs_rpmb_write_key(uint8_t * key, uint8_t len)
|
|
{
|
|
struct rpmb_data_frame *data_frame = NULL;
|
|
uint16_t msg_type;
|
|
uint16_t op_result;
|
|
int ret = 0;
|
|
lbaint_t transfer_blkcnt = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (rpmb_lu_info.log2blksz == 0) {
|
|
ret = prepare_rpmb_lu();
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
/* rpmb_lu_info.log2blksz=0x08,256B */
|
|
transfer_blkcnt = RPMB_DATA_FRAME_SIZE >> (rpmb_lu_info.log2blksz);
|
|
|
|
if (!key || len != RPMB_KEY_MAC_SIZE)
|
|
return 1;
|
|
|
|
/* for write rpmb key req */
|
|
msg_type = RPMB_WRITE_KEY;
|
|
data_frame = memalign(ARCH_DMA_MINALIGN, RPMB_DATA_FRAME_SIZE);
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
u16_to_bytes(msg_type, data_frame->msg_type);
|
|
memcpy(data_frame->key_mac, key, RPMB_KEY_MAC_SIZE);
|
|
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, transfer_blkcnt);
|
|
|
|
/* for read result req */
|
|
memset(data_frame, 0, RPMB_DATA_FRAME_SIZE);
|
|
msg_type = RPMB_READ_RESP;
|
|
u16_to_bytes(msg_type, data_frame->msg_type);
|
|
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, transfer_blkcnt);
|
|
|
|
memset(data_frame, 0xcc, RPMB_DATA_FRAME_SIZE);
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_IN, DMA_FROM_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)data_frame, 0, transfer_blkcnt);
|
|
|
|
/* result check */
|
|
bytes_to_u16(data_frame->op_result, &op_result);
|
|
bytes_to_u16(data_frame->msg_type, &msg_type);
|
|
if ((op_result == RPMB_RESULT_OK) && (msg_type == RPMB_RESP_AUTH_KEY_PROGRAM)) {
|
|
printf(" key write successed\n");
|
|
free(data_frame);
|
|
return 0;
|
|
} else {
|
|
printf(" key write fail op_result:0x%x ,msg_type:0x%x\n", op_result, msg_type);
|
|
}
|
|
|
|
free(data_frame);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int ufs_read_desc(struct ufs_hba *hba, enum desc_idn desc_id,
|
|
int desc_index, u8 *buf, u32 size)
|
|
{
|
|
return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size);
|
|
}
|
|
|
|
int ufs_read_device_desc(u8 *buf, u32 size)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return ufs_read_desc(rpmb_hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
|
|
}
|
|
|
|
int ufs_read_string_desc(int desc_index, u8 *buf, u32 size)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return ufs_read_desc(rpmb_hba, QUERY_DESC_IDN_STRING, desc_index, buf, size);
|
|
}
|
|
|
|
int ufs_read_geo_desc(u8 *buf, u32 size)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return ufs_read_desc(rpmb_hba, QUERY_DESC_IDN_GEOMETRY, 0, buf, size);
|
|
}
|
|
|
|
int ufs_read_rpmb_unit_desc(u8 *buf, u32 size)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return ufs_read_desc(rpmb_hba, QUERY_DESC_IDN_UNIT, 0xc4, buf, size);
|
|
}
|
|
|
|
int do_rpmb_op(struct rpmb_data_frame *frame_in, uint32_t in_cnt,
|
|
struct rpmb_data_frame *frame_out, uint32_t out_cnt)
|
|
{
|
|
uint16_t msg_type = 0;
|
|
int ret = 0;
|
|
|
|
ret = hba_test(rpmb_hba);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (rpmb_lu_info.log2blksz == 0) {
|
|
ret = prepare_rpmb_lu();
|
|
if (ret != 0) {
|
|
printf("prepare rpmb unit failed!\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (!frame_in || !frame_out || !in_cnt || !out_cnt) {
|
|
printf("Wrong rpmb parameters\n");
|
|
return -1;
|
|
}
|
|
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)frame_in, 0, in_cnt);
|
|
|
|
bytes_to_u16(frame_in->msg_type, &msg_type);
|
|
if ((msg_type == RPMB_WRITE) || (msg_type == RPMB_WRITE_KEY) ||
|
|
(msg_type == RPMB_SEC_CONF_WRITE)) {
|
|
memset(&frame_in[0], 0, sizeof(frame_in[0]));
|
|
msg_type = RPMB_READ_RESP;
|
|
u16_to_bytes(msg_type, frame_in->msg_type);
|
|
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_OUT, DMA_TO_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)frame_in, 0, 1);
|
|
}
|
|
|
|
rpmb_send_scsi_cmd(rpmb_hba, UFS_OP_SECURITY_PROTOCOL_IN, DMA_FROM_DEVICE,
|
|
rpmb_lu_info.lu_index, (void*)frame_out, 0, out_cnt);
|
|
return 0;
|
|
}
|
|
|
|
int ufs_rpmb_init(struct ufs_hba *hba)
|
|
{
|
|
rpmb_hba = hba;
|
|
|
|
return 0;
|
|
}
|