kernel_samsung_a34x-permissive/drivers/char/rpmb/rpmb-mtk.c

4133 lines
91 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/semaphore.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/memory.h>
#include <linux/io.h>
#include <linux/proc_fs.h>
#include <crypto/hash.h>
#include <linux/rpmb.h>
#include "rpmb-mtk.h"
#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include "queue.h"
#include "mmc_ops.h"
#include "core.h"
#include "card.h"
#ifdef CONFIG_TEEGRIS_TEE_SUPPORT
#include "tee_client_api.h"
#include "tzdev.h"
#endif
#if defined(CONFIG_MMC_MTK_PRO)
#include "mtk_sd.h"
#endif
#if defined(CONFIG_MMC_MTK)
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
static struct mmc_host *mtk_mmc_host[] = {NULL};
#endif
#ifndef CONFIG_TEEGRIS_TEE_SUPPORT
#ifdef CONFIG_SCSI_UFS_MEDIATEK
#include "ufs-mediatek.h"
#endif
#endif
#include <mt-plat/mtk_boot.h>
/* #define __RPMB_MTK_DEBUG_MSG */
/* #define __RPMB_MTK_DEBUG_HMAC_VERIFY */
#if defined(CONFIG_TEEGRIS_TEE_SUPPORT) || defined(CONFIG_TRUSTONIC_TEE_SUPPORT)
#include "drrpmb_Api.h"
#include "drrpmb_gp_Api.h"
static struct dciMessage_t *rpmb_gp_dci;
#endif
/* TEE usage */
#ifdef CONFIG_TRUSTONIC_TEE_SUPPORT
#include "mobicore_driver_api.h"
#ifndef CONFIG_TEE
static struct mc_uuid_t rpmb_uuid = RPMB_UUID;
static struct mc_session_handle rpmb_session = {0};
static u32 rpmb_devid = MC_DEVICE_ID_DEFAULT;
static struct dciMessage_t *rpmb_dci;
#endif
static struct mc_uuid_t rpmb_gp_uuid = RPMB_GP_UUID;
static struct mc_session_handle rpmb_gp_session = {0};
static u32 rpmb_gp_devid = MC_DEVICE_ID_DEFAULT;
#endif
#ifdef CONFIG_TEEGRIS_TEE_SUPPORT
#include <core/iwsock.h>
#define RPMB_SOCKET_NAME "rpmb_socket"
#define TEEGRIS_MAX_RPMB_TRANSFER_BLK (32)
#define TEEGRIS_MAX_RPMB_REQUEST_SIZE (512 * TEEGRIS_MAX_RPMB_TRANSFER_BLK)
#define RPMB_IPC_MAGIC 0x11111111
#define RPMB_REQUEST_MAGIC 0x44444444
#define RPMB_REPLY_MAGIC 0x66666666
struct rpmb_req {
uint16_t type;
uint16_t addr;
uint16_t blks;
uint8_t frame[0];
};
struct rpmb_ctx {
void *wsm_vaddr;
struct rpmb_req *req;
};
#ifdef CONFIG_SCSI_UFS_MEDIATEK
struct rpmb_dev *ufs_mtk_rpmb_get_raw_dev(void);
#endif
static struct task_struct *iwsock_th;
static DEFINE_MUTEX(rpmb_mutex);
static int dt_get_boot_type(void);
#endif
/*
* Dummy definition for MAX_RPMB_TRANSFER_BLK.
*
* For UFS RPMB driver, MAX_RPMB_TRANSFER_BLK will be always
* used however it will NOT be defined in projects w/o Security
* OS. Thus we add a dummy definition here to avoid build errors.
*
* For eMMC RPMB driver, MAX_RPMB_TRANSFER_BLK will be used
* only if RPMB_MULTI_BLOCK_ACCESS is defined. thus
* build error will not happen on projects w/o Security OS.
*
* NOTE: This dummy definition shall be located after
* #include "drrpmb_Api.h" and
* #include "rpmb-mtk.h"
* since MAX_RPMB_TRANSFER_BLK will be defined in those
* header files if security OS is enabled.
*/
#ifndef MAX_RPMB_TRANSFER_BLK
#define MAX_RPMB_TRANSFER_BLK (1)
#endif
#define RPMB_NAME "rpmb"
#define DEFAULT_HANDLES_NUM (64)
#define MAX_OPEN_SESSIONS (0xffffffff - 1)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
/* Debug message event */
#define DBG_EVT_NONE (0) /* No event */
#define DBG_EVT_CMD (1 << 0)/* SEC CMD related event */
#define DBG_EVT_FUNC (1 << 1)/* SEC function event */
#define DBG_EVT_INFO (1 << 2)/* SEC information event */
#define DBG_EVT_WRN (1 << 30) /* Warning event */
#define DBG_EVT_ERR (1 << 31) /* Error event */
#ifdef __RPMB_MTK_DEBUG_MSG
#define DBG_EVT_DBG_INFO (1 << 31) /* Error event */
#else
#define DBG_EVT_DBG_INFO (1 << 2) /* Information event */
#endif
#define DBG_EVT_ALL (0xffffffff)
#define DBG_EVT_MASK (DBG_EVT_ERR)
#define MSG(evt, fmt, args...) \
do {\
if ((DBG_EVT_##evt) & DBG_EVT_MASK) { \
pr_notice("[%s] "fmt, RPMB_NAME, ##args); \
} \
} while (0)
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
#define RPMB_DATA_BUFF_SIZE (1024 * 24)
#define RPMB_ONE_FRAME_SIZE (512)
static unsigned char *rpmb_buffer;
#endif
struct task_struct *open_th;
struct task_struct *rpmbDci_th;
struct task_struct *rpmb_gp_Dci_th;
static struct cdev rpmb_dev;
static struct class *mtk_rpmb_class;
/*
* This is an alternative way to get mmc_card strcuture from mmc_host which set
* from msdc driver with this callback function.
* The strength is we don't have to extern msdc_host_host global variable,
* extern global is very bad...
* The weakness is every platform driver needs to add this callback to give
* rpmb driver the mmc_host structure and then we could know card.
*
* Finally, I decide to ignore its strength, because the weakness is more
* important.
* If every projects have to add this callback, the operation is complicated.
*/
#ifdef EMMC_RPMB_SET_HOST
struct mmc_host *emmc_rpmb_host;
void emmc_rpmb_set_host(void *mmc_host)
{
emmc_rpmb_host = mmc_host;
}
#endif
int hmac_sha256(const char *key, u32 klen, const char *str, u32 len, u8 *hmac)
{
struct shash_desc *shash;
struct crypto_shash *hmacsha256 =
crypto_alloc_shash("hmac(sha256)", 0, 0);
u32 size = 0;
int err = 0;
if (IS_ERR(hmacsha256))
return -1;
size = sizeof(struct shash_desc) + crypto_shash_descsize(hmacsha256);
shash = kmalloc(size, GFP_KERNEL);
if (!shash) {
err = -1;
goto malloc_err;
}
shash->tfm = hmacsha256;
shash->flags = 0x0;
err = crypto_shash_setkey(hmacsha256, key, klen);
if (err) {
err = -1;
goto hash_err;
}
err = crypto_shash_init(shash);
if (err) {
err = -1;
goto hash_err;
}
crypto_shash_update(shash, str, len);
err = crypto_shash_final(shash, hmac);
hash_err:
kfree(shash);
malloc_err:
crypto_free_shash(hmacsha256);
return err;
}
#ifdef __RPMB_MTK_DEBUG_HMAC_VERIFY
unsigned char rpmb_key[32] = {
0x64, 0x76, 0xEE, 0xF0, 0xF1, 0x6B, 0x30, 0x47,
0xE9, 0x79, 0x31, 0x58, 0xF6, 0x42, 0xDA, 0x46,
0xF7, 0x3B, 0x53, 0xFD, 0xC5, 0xF8, 0x84, 0xCE,
0x03, 0x73, 0x15, 0xBC, 0x54, 0x47, 0xD4, 0x6A
};
int rpmb_cal_hmac(struct rpmb_frame *frame, int blk_cnt, u8 *key, u8 *key_mac)
{
int i;
u8 *buf, *buf_start;
buf = buf_start = kzalloc(284 * blk_cnt, 0);
for (i = 0; i < blk_cnt; i++) {
memcpy(buf, frame[i].data, 284);
buf += 284;
}
hmac_sha256(key, 32, buf_start, 284 * blk_cnt, key_mac);
kfree(buf_start);
return 0;
}
#endif
/*
* CHECK THIS!!! Copy from block.c mmc_blk_data structure.
*/
struct emmc_rpmb_blk_data {
spinlock_t lock;
struct device *parent;
struct gendisk *disk;
struct mmc_queue queue;
struct list_head part;
struct list_head rpmbs;
unsigned int flags;
unsigned int usage;
unsigned int read_only;
unsigned int part_type;
/* unsigned int name_idx; */
unsigned int reset_done;
/*
* Only set in main mmc_blk_data associated
* with mmc_card with mmc_set_drvdata, and keeps
* track of the current selected device partition.
*/
unsigned int part_curr;
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
int area_type;
};
struct emmc_rpmb_data {
struct device dev;
struct cdev chrdev;
int id;
unsigned int part_index;
struct emmc_rpmb_blk_data *md;
struct list_head node;
};
static void rpmb_dump_frame(u8 *data_frame)
{
MSG(DBG_INFO, "mac, frame[196] = 0x%x\n", data_frame[196]);
MSG(DBG_INFO, "mac, frame[197] = 0x%x\n", data_frame[197]);
MSG(DBG_INFO, "mac, frame[198] = 0x%x\n", data_frame[198]);
MSG(DBG_INFO, "data,frame[228] = 0x%x\n", data_frame[228]);
MSG(DBG_INFO, "data,frame[229] = 0x%x\n", data_frame[229]);
MSG(DBG_INFO, "nonce, frame[484] = 0x%x\n", data_frame[484]);
MSG(DBG_INFO, "nonce, frame[485] = 0x%x\n", data_frame[485]);
MSG(DBG_INFO, "nonce, frame[486] = 0x%x\n", data_frame[486]);
MSG(DBG_INFO, "nonce, frame[487] = 0x%x\n", data_frame[487]);
MSG(DBG_INFO, "wc, frame[500] = 0x%x\n", data_frame[500]);
MSG(DBG_INFO, "wc, frame[501] = 0x%x\n", data_frame[501]);
MSG(DBG_INFO, "wc, frame[502] = 0x%x\n", data_frame[502]);
MSG(DBG_INFO, "wc, frame[503] = 0x%x\n", data_frame[503]);
MSG(DBG_INFO, "addr, frame[504] = 0x%x\n", data_frame[504]);
MSG(DBG_INFO, "addr, frame[505] = 0x%x\n", data_frame[505]);
MSG(DBG_INFO, "blkcnt,frame[506] = 0x%x\n", data_frame[506]);
MSG(DBG_INFO, "blkcnt,frame[507] = 0x%x\n", data_frame[507]);
MSG(DBG_INFO, "result, frame[508] = 0x%x\n", data_frame[508]);
MSG(DBG_INFO, "result, frame[509] = 0x%x\n", data_frame[509]);
MSG(DBG_INFO, "type, frame[510] = 0x%x\n", data_frame[510]);
MSG(DBG_INFO, "type, frame[511] = 0x%x\n", data_frame[511]);
}
/*
* CHECK THIS!!! Copy from block.c mmc_blk_part_switch.
* Since it is static inline function, we cannot extern to use it.
* For syncing block data, this is the only way.
*/
int emmc_rpmb_switch(struct mmc_card *card, struct emmc_rpmb_blk_data *md)
{
int ret;
struct emmc_rpmb_blk_data *main_md = dev_get_drvdata(&card->dev);
if (main_md->part_curr == md->part_type)
return 0;
#if defined(CONFIG_MTK_EMMC_CQ_SUPPORT) || defined(CONFIG_MTK_EMMC_HW_CQ)
if (mmc_card_cmdq(card)) {
ret = mmc_cmdq_disable(card);
if (ret) {
MSG(ERR, "CQ disabled failed!!!(%x)\n", ret);
return ret;
}
mmc_card_clr_cmdq(card);
}
#elif defined(CONFIG_MMC_MTK)
if (md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
if (card->ext_csd.cmdq_en) {
ret = mmc_cmdq_disable(card);
if (ret) {
MSG(ERR, "CMDQ disabled failed!(%d)\n", ret);
return ret;
}
}
}
#endif
if (mmc_card_mmc(card)) {
u8 part_config = card->ext_csd.part_config;
part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
part_config |= md->part_type;
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, part_config,
card->ext_csd.part_time);
if (ret)
return ret;
card->ext_csd.part_config = part_config;
}
#if defined(CONFIG_MTK_EMMC_CQ_SUPPORT) || defined(CONFIG_MTK_EMMC_HW_CQ)
/* enable cmdq at user partition */
if (!mmc_card_cmdq(card)
&& (md->part_type <= 0)) {
ret = mmc_cmdq_enable(card);
if (ret)
pr_notice("%s enable CMDQ error %d, so just work without CMDQ\n",
mmc_hostname(card->host), ret);
else
mmc_card_set_cmdq(card);
}
#elif defined(CONFIG_MMC_MTK)
if (main_md->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB) {
if (card->reenable_cmdq && !card->ext_csd.cmdq_en) {
ret = mmc_cmdq_enable(card);
if (ret)
pr_notice("%s enable CMDQ error %d,so just work without CMDQ\n",
mmc_hostname(card->host), ret);
}
}
#endif
#if defined(CONFIG_MTK_EMMC_HW_CQ)
card->part_curr = md->part_type;
#endif
main_md->part_curr = md->part_type;
return 0;
}
static int emmc_rpmb_send_command(
struct mmc_card *card,
u8 *buf,
__u16 blks,
__u16 type,
u8 req_type
)
{
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_command sbc = {0};
struct mmc_data data = {0};
struct scatterlist sg;
u8 *transfer_buf = NULL;
if (blks == 0) {
MSG(ERR, "%s: Invalid blks: 0\n", __func__);
return -EINVAL;
}
mrq.sbc = &sbc;
mrq.cmd = &cmd;
mrq.data = &data;
mrq.stop = NULL;
transfer_buf = kzalloc(512 * blks, GFP_KERNEL);
if (!transfer_buf)
return -ENOMEM;
/*
* set CMD23
*/
sbc.opcode = MMC_SET_BLOCK_COUNT;
sbc.arg = blks;
if ((req_type == RPMB_REQ && type == RPMB_WRITE_DATA) ||
type == RPMB_PROGRAM_KEY)
sbc.arg |= 1 << 31;
sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
/*
* set CMD25/18
*/
sg_init_one(&sg, transfer_buf, 512 * blks);
if (req_type == RPMB_REQ) {
cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
sg_copy_from_buffer(&sg, 1, buf, 512 * blks);
data.flags |= MMC_DATA_WRITE;
} else {
cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
data.flags |= MMC_DATA_READ;
}
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 512;
data.blocks = blks;
data.sg = &sg;
data.sg_len = 1;
mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
if (req_type != RPMB_REQ)
sg_copy_to_buffer(&sg, 1, buf, 512 * blks);
kfree(transfer_buf);
if (cmd.error)
return cmd.error;
if (data.error)
return data.error;
return 0;
}
int emmc_rpmb_req_start(struct mmc_card *card, struct emmc_rpmb_req *req)
{
int err = 0;
u16 blks = req->blk_cnt;
u16 type = req->type;
u8 *data_frame = req->data_frame;
/* MSG(INFO, "%s, start\n", __func__); */
/*
* STEP 1: send request to RPMB partition.
*/
if (type == RPMB_WRITE_DATA)
err = emmc_rpmb_send_command(card, data_frame,
blks, type, RPMB_REQ);
else
err = emmc_rpmb_send_command(card, data_frame,
1, type, RPMB_REQ);
if (err) {
MSG(ERR, "%s step 1, request failed (%d)\n", __func__, err);
goto out;
}
/*
* STEP 2: check write result. Only for WRITE_DATA or Program key.
*/
memset(data_frame, 0, 512 * blks);
if (type == RPMB_WRITE_DATA || type == RPMB_PROGRAM_KEY) {
data_frame[RPMB_TYPE_BEG + 1] = RPMB_RESULT_READ;
err = emmc_rpmb_send_command(card, data_frame,
1, RPMB_RESULT_READ, RPMB_REQ);
if (err) {
MSG(ERR, "%s step 2, request result failed (%d)\n",
__func__, err);
goto out;
}
}
/*
* STEP 3: get response from RPMB partition
*/
data_frame[RPMB_TYPE_BEG] = 0;
data_frame[RPMB_TYPE_BEG + 1] = type;
if (type == RPMB_READ_DATA)
err = emmc_rpmb_send_command(card, data_frame, blks,
type, RPMB_RESP);
else
err = emmc_rpmb_send_command(card, data_frame, 1,
type, RPMB_RESP);
if (err)
MSG(ERR, "%s step 3, response failed (%d)\n", __func__, err);
/* MSG(INFO, "%s, end\n", __func__); */
out:
return err;
}
int emmc_rpmb_req_handle(struct mmc_card *card, struct emmc_rpmb_req *rpmb_req)
{
struct emmc_rpmb_blk_data *md = NULL, *part_md;
int ret;
struct emmc_rpmb_data *rpmb;
struct list_head *pos;
part_md = vzalloc(sizeof(struct emmc_rpmb_blk_data));
if (!part_md)
return -ENOMEM;
/* rpmb_dump_frame(rpmb_req->data_frame); */
md = dev_get_drvdata(&card->dev);
if (md == NULL)
return -ENODEV;
list_for_each(pos, &md->rpmbs) {
rpmb = list_entry(pos, struct emmc_rpmb_data, node);
if (rpmb) {
part_md->part_type = EXT_CSD_PART_CONFIG_ACC_RPMB;
break;
}
}
/* MSG(INFO, "%s start.\n", __func__); */
mmc_get_card(card, NULL);
/*
* STEP1: Switch to RPMB partition.
*/
ret = emmc_rpmb_switch(card, part_md);
if (ret) {
MSG(ERR, "%s emmc_rpmb_switch failed. (%x)\n", __func__, ret);
goto error;
}
/* MSG(INFO, "%s, emmc_rpmb_switch success.\n", __func__); */
/*
* STEP2: Start request. (CMD23, CMD25/18 procedure)
*/
ret = emmc_rpmb_req_start(card, rpmb_req);
if (ret) {
MSG(ERR, "%s emmc_rpmb_req_start failed!! (%x)\n",
__func__, ret);
goto error;
}
/* MSG(INFO, "%s end.\n", __func__); */
error:
ret = emmc_rpmb_switch(card, dev_get_drvdata(&card->dev));
if (ret)
MSG(ERR, "%s emmc_rpmb_switch main failed. (%x)\n",
__func__, ret);
mmc_put_card(card, NULL);
rpmb_dump_frame(rpmb_req->data_frame);
vfree(part_md);
return ret;
}
/* ****************************************************************************
*
* Following are internal APIs. Stand-alone driver without TEE.
*
*
******************************************************************************/
int emmc_rpmb_req_set_key(struct mmc_card *card, u8 *key)
{
struct emmc_rpmb_req rpmb_req;
struct s_rpmb *rpmb_frame;
int ret;
u8 user_key;
if (get_user(user_key, key))
return -EFAULT;
MSG(INFO, "%s start!!!\n", __func__);
rpmb_frame = kzalloc(sizeof(struct s_rpmb), 0);
if (rpmb_frame == NULL)
return RPMB_ALLOC_ERROR;
memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
rpmb_req.type = RPMB_PROGRAM_KEY;
rpmb_req.blk_cnt = 1;
rpmb_req.data_frame = (u8 *)rpmb_frame;
rpmb_frame->request = cpu_to_be16p(&rpmb_req.type);
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
goto free;
}
if (rpmb_frame->result) {
MSG(ERR, "%s, result error!!! (%x)\n",
__func__, cpu_to_be16p(&rpmb_frame->result));
ret = RPMB_RESULT_ERROR;
}
MSG(INFO, "%s end!!!\n", __func__);
free:
kfree(rpmb_frame);
return ret;
}
void rpmb_req_copy_data_for_hmac(u8 *buf, struct rpmb_frame *f)
{
u32 size;
/*
* Copy below members for HMAC calculation
* one by one with specifically assigning
* buf to each member to pass buffer-overrun checker.
*
* __u8 data[256];
* __u8 nonce[16];
* __be32 write_counter;
* __be16 addr;
* __be16 block_count;
* __be16 result;
* __be16 req_resp;
*/
memcpy(buf, f->data, RPMB_SZ_DATA);
buf += RPMB_SZ_DATA;
size = sizeof(f->nonce);
memcpy(buf, f->nonce, size);
buf += size;
size = sizeof(f->write_counter);
memcpy(buf, &f->write_counter, size);
buf += size;
size = sizeof(f->addr);
memcpy(buf, &f->addr, size);
buf += size;
size = sizeof(f->block_count);
memcpy(buf, &f->block_count, size);
buf += size;
size = sizeof(f->result);
memcpy(buf, &f->result, size);
buf += size;
size = sizeof(f->req_resp);
memcpy(buf, &f->req_resp, size);
buf += size;
}
#ifdef CONFIG_SCSI_UFS_MEDIATEK
static struct rpmb_frame *rpmb_alloc_frames(unsigned int cnt)
{
return kzalloc(sizeof(struct rpmb_frame) * cnt, 0);
}
int rpmb_req_get_wc_ufs(u8 *key, u32 *wc, u8 *frame)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb;
u8 nonce[RPMB_SZ_NONCE] = {0};
u8 hmac[RPMB_SZ_MAC];
int ret, i;
MSG(INFO, "%s start!!!\n", __func__);
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
do {
/*
* Initial frame buffers
*/
if (frame) {
/*
* Use external frame if possible.
* External frame shall have below field ready,
*
* nonce
* req_resp
*/
data.icmd.frames = (struct rpmb_frame *)frame;
data.ocmd.frames = (struct rpmb_frame *)frame;
} else {
data.icmd.frames = rpmb_alloc_frames(1);
if (data.icmd.frames == NULL)
return RPMB_ALLOC_ERROR;
data.ocmd.frames = rpmb_alloc_frames(1);
if (data.ocmd.frames == NULL) {
kfree(data.icmd.frames);
return RPMB_ALLOC_ERROR;
}
}
/*
* Prepare frame contents.
*
* Input frame (in view of device) only needs nonce
*/
data.req_type = RPMB_GET_WRITE_COUNTER;
data.icmd.nframes = 1;
/* Fill-in essential field in self-prepared frame */
if (!frame) {
get_random_bytes(nonce, RPMB_SZ_NONCE);
data.icmd.frames->req_resp =
cpu_to_be16(RPMB_GET_WRITE_COUNTER);
memcpy(data.icmd.frames->nonce, nonce, RPMB_SZ_NONCE);
}
/* Output frame (in view of device) */
data.ocmd.nframes = 1;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret) {
MSG(ERR, "%s, rpmb_cmd_req IO error!!!(0x%x)\n",
__func__, ret);
break;
}
/* Verify HMAC only if key is available */
if (key) {
/*
* Authenticate response write counter frame.
*/
hmac_sha256(key, 32, data.ocmd.frames->data, 284, hmac);
if (memcmp(hmac, data.ocmd.frames->key_mac, RPMB_SZ_MAC)
!= 0) {
MSG(ERR, "%s, hmac compare error!!!\n",
__func__);
ret = RPMB_HMAC_ERROR;
}
/*
* DEVICE ISSUE:
* We found some devices will return hmac vale with all
* zeros.
* For this kind of device, bypass hmac comparison.
*/
if (ret == RPMB_HMAC_ERROR) {
for (i = 0; i < 32; i++) {
if (data.ocmd.frames->key_mac[i]
!= 0x0) {
MSG(ERR,
"%s, device hmac is not NULL!!!\n",
__func__);
break;
}
}
MSG(ERR,
"%s, device hmac has all zero, bypassed!!!\n",
__func__);
ret = RPMB_SUCCESS;
}
}
/*
* Verify nonce and result only in self-prepared frame
* External frame shall be verified by frame provider,
* for example, TEE.
*/
if (!frame) {
if (memcmp(nonce, data.ocmd.frames->nonce,
RPMB_SZ_NONCE) != 0) {
MSG(ERR, "%s, nonce compare error!!!\n",
__func__);
rpmb_dump_frame((u8 *)data.ocmd.frames);
ret = RPMB_NONCE_ERROR;
break;
}
if (data.ocmd.frames->result) {
MSG(ERR, "%s, result error!!! (0x%x)\n",
__func__,
cpu_to_be16(data.ocmd.frames->result));
ret = RPMB_RESULT_ERROR;
break;
}
}
if (wc) {
*wc = cpu_to_be32(data.ocmd.frames->write_counter);
MSG(DBG_INFO, "%s: wc = %d (0x%x)\n",
__func__, *wc, *wc);
}
} while (0);
MSG(DBG_INFO, "%s: end\n", __func__);
if (!frame) {
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
}
return ret;
}
int rpmb_req_read_data_ufs(u8 *frame, u32 blk_cnt)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb;
int ret;
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
MSG(DBG_INFO, "%s: blk_cnt: %d\n", __func__, blk_cnt);
data.req_type = RPMB_READ_DATA;
data.icmd.nframes = 1;
data.icmd.frames = (struct rpmb_frame *)frame;
/*
* We need to fill-in block_count by ourselves for UFS case.
* TEE does not fill-in this field because eMMC spec specifiy it as 0.
*/
data.icmd.frames->block_count = cpu_to_be16(blk_cnt);
data.ocmd.nframes = blk_cnt;
data.ocmd.frames = (struct rpmb_frame *)frame;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret)
MSG(ERR, "%s: rpmb_cmd_req IO error, ret %d (0x%x)\n",
__func__, ret, ret);
MSG(DBG_INFO, "%s: result 0x%x\n", __func__,
cpu_to_be16(data.ocmd.frames->result));
MSG(DBG_INFO, "%s: ret 0x%x\n", __func__, ret);
return ret;
}
int rpmb_req_write_data_ufs(u8 *frame, u32 blk_cnt)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb;
int ret;
#ifdef __RPMB_MTK_DEBUG_HMAC_VERIFY
u8 *key_mac;
#endif
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
MSG(DBG_INFO, "%s: blk_cnt: %d\n", __func__, blk_cnt);
/*
* Alloc output frame to avoid overwriting input frame
* buffer provided by TEE
*/
data.ocmd.frames = rpmb_alloc_frames(1);
if (data.ocmd.frames == NULL)
return RPMB_ALLOC_ERROR;
data.ocmd.nframes = 1;
data.req_type = RPMB_WRITE_DATA;
data.icmd.nframes = blk_cnt;
data.icmd.frames = (struct rpmb_frame *)frame;
#ifdef __RPMB_MTK_DEBUG_HMAC_VERIFY
key_mac = kzalloc(32, 0);
rpmb_cal_hmac((struct rpmb_frame *)frame, blk_cnt, rpmb_key, key_mac);
if (memcmp(key_mac,
((struct rpmb_frame *)frame)[blk_cnt - 1].key_mac, 32)) {
MSG(ERR, "%s, Key Mac is NOT matched!\n", __func__);
kfree(key_mac);
ret = 1;
goto out;
} else
MSG(ERR, "%s, Key Mac check passed.\n", __func__);
kfree(key_mac);
#endif
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret)
MSG(ERR, "%s: rpmb_cmd_req IO error, ret %d (0x%x)\n",
__func__, ret, ret);
/*
* Microtrust TEE will check write counter in the first frame,
* thus we copy response frame to the first frame.
*/
memcpy(frame, data.ocmd.frames, 512);
MSG(DBG_INFO, "%s: result 0x%x\n", __func__,
cpu_to_be16(data.ocmd.frames->result));
kfree(data.ocmd.frames);
MSG(DBG_INFO, "%s: ret 0x%x\n", __func__, ret);
#ifdef __RPMB_MTK_DEBUG_HMAC_VERIFY
out:
#endif
return ret;
}
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
int rpmb_req_program_key_ufs(u8 *frame, u32 blk_cnt)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb;
int ret;
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
MSG(DBG_INFO, "%s: blk_cnt: %d\n", __func__, blk_cnt);
/*
* Alloc output frame to avoid overwriting input frame
* buffer provided by TEE
*/
data.ocmd.frames = rpmb_alloc_frames(1);
if (data.ocmd.frames == NULL)
return RPMB_ALLOC_ERROR;
data.ocmd.nframes = 1;
data.req_type = RPMB_PROGRAM_KEY;
data.icmd.nframes = 1;
data.icmd.frames = (struct rpmb_frame *)frame;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret)
MSG(ERR, "%s: rpmb_cmd_req IO error, ret %d (0x%x)\n",
__func__, ret, ret);
/*
* Microtrust TEE will check write counter in the first frame,
* thus we copy response frame to the first frame.
*/
memcpy(frame, data.ocmd.frames, 512);
if (data.ocmd.frames->result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16(data.ocmd.frames->result));
ret = RPMB_RESULT_ERROR;
}
kfree(data.ocmd.frames);
MSG(DBG_INFO, "%s: ret 0x%x\n", __func__, ret);
return ret;
}
#endif
int rpmb_req_ioctl_write_data_ufs(struct rpmb_ioc_param *param)
{
int err = 0;
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb;
u32 tran_size, left_size = param->data_len;
u32 wc = 0xFFFFFFFF;
u16 iCnt, tran_blkcnt, left_blkcnt;
u16 blkaddr;
u8 hmac[RPMB_SZ_MAC];
u8 *dataBuf, *dataBuf_start;
u8 key[32];
u32 size_for_hmac;
int i, ret = 0;
u8 user_param_data;
MSG(DBG_INFO, "%s start!!!\n", __func__);
if (get_user(user_param_data, param->data))
return -EFAULT;
if (get_user(user_param_data, param->key))
return -EFAULT;
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
i = 0;
tran_blkcnt = 0;
dataBuf = NULL;
dataBuf_start = NULL;
/* Get user key */
err = copy_from_user(key, param->key, 32);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n", __func__, err);
return -EFAULT;
}
left_blkcnt = ((param->data_len % RPMB_SZ_DATA) ?
(param->data_len / RPMB_SZ_DATA + 1) :
(param->data_len / RPMB_SZ_DATA));
/*
* For RPMB write data, the elements we need in the input data frame is
* 1. address.
* 2. write counter.
* 3. data.
* 4. block count.
* 5. MAC
*/
blkaddr = param->addr;
while (left_blkcnt) {
#if (MAX_RPMB_TRANSFER_BLK > 1)
if (left_blkcnt >= MAX_RPMB_TRANSFER_BLK)
tran_blkcnt = MAX_RPMB_TRANSFER_BLK;
else
tran_blkcnt = left_blkcnt;
#else
tran_blkcnt = 1;
#endif
MSG(DBG_INFO, "%s, total_blkcnt = 0x%x, tran_blkcnt = 0x%x\n",
__func__, left_blkcnt, tran_blkcnt);
ret = rpmb_req_get_wc_ufs(key, &wc, NULL);
if (ret) {
MSG(ERR, "%s, rpmb_req_get_wc_ufs error!!!(0x%x)\n",
__func__, ret);
return ret;
}
/*
* Initial frame buffers
*/
data.icmd.frames = rpmb_alloc_frames(tran_blkcnt);
if (data.icmd.frames == NULL)
return RPMB_ALLOC_ERROR;
data.ocmd.frames = rpmb_alloc_frames(1);
if (data.ocmd.frames == NULL) {
kfree(data.icmd.frames);
return RPMB_ALLOC_ERROR;
}
/*
* Initial data buffer for HMAC computation.
* Since HAMC computation tool which we use needs consecutive
* data buffer.Pre-alloced it.
*/
dataBuf_start = dataBuf = kzalloc(284 * tran_blkcnt, 0);
if (!dataBuf_start) {
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
return RPMB_ALLOC_ERROR;
}
/*
* Prepare frame contents
*/
data.req_type = RPMB_WRITE_DATA;
/* Output frames (in view of device) */
data.ocmd.nframes = 1;
/*
* All input frames (in view of device) need below stuff,
* 1. address.
* 2. write counter.
* 3. data.
* 4. block count.
* 5. MAC
*/
data.icmd.nframes = tran_blkcnt;
/* size for hmac calculation: 512 - 228 = 284 */
size_for_hmac =
sizeof(struct rpmb_frame) - offsetof(struct rpmb_frame, data);
for (iCnt = 0; iCnt < tran_blkcnt; iCnt++) {
/*
* Prepare write data frame. need addr, wc, blkcnt,
* data and mac.
*/
data.icmd.frames[iCnt].req_resp =
cpu_to_be16(RPMB_WRITE_DATA);
data.icmd.frames[iCnt].addr = cpu_to_be16(blkaddr);
data.icmd.frames[iCnt].block_count =
cpu_to_be16(tran_blkcnt);
data.icmd.frames[iCnt].write_counter = cpu_to_be32(wc);
if (left_size >= RPMB_SZ_DATA)
tran_size = RPMB_SZ_DATA;
else
tran_size = left_size;
err = copy_from_user(data.icmd.frames[iCnt].data,
(param->data +
i * MAX_RPMB_TRANSFER_BLK * RPMB_SZ_DATA +
(iCnt * RPMB_SZ_DATA)),
tran_size);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n",
__func__, err);
ret = -EFAULT;
goto out;
}
left_size -= tran_size;
rpmb_req_copy_data_for_hmac(
dataBuf, &data.icmd.frames[iCnt]);
dataBuf += size_for_hmac;
}
iCnt--;
hmac_sha256(key, 32, dataBuf_start, 284 * tran_blkcnt,
data.icmd.frames[iCnt].key_mac);
/*
* Send write data request.
*/
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret) {
MSG(ERR, "%s, rpmb_cmd_req IO error!!!(0x%x)\n",
__func__, ret);
break;
}
/*
* Authenticate write result response.
* 1. authenticate hmac.
* 2. check result.
* 3. compare write counter is increamented.
*/
hmac_sha256(key, 32, data.ocmd.frames->data, 284, hmac);
if (memcmp(hmac, data.ocmd.frames->key_mac, RPMB_SZ_MAC) != 0) {
MSG(ERR, "%s, hmac compare error!!!\n", __func__);
ret = RPMB_HMAC_ERROR;
break;
}
if (data.ocmd.frames->result) {
MSG(ERR, "%s, result error!!! (0x%x)\n", __func__,
cpu_to_be16(data.ocmd.frames->result));
ret = RPMB_RESULT_ERROR;
break;
}
if (cpu_to_be32(data.ocmd.frames->write_counter) != wc + 1) {
MSG(ERR, "%s, write counter error!!! (0x%x)\n",
__func__,
cpu_to_be32(data.ocmd.frames->write_counter));
ret = RPMB_WC_ERROR;
break;
}
blkaddr += tran_blkcnt;
left_blkcnt -= tran_blkcnt;
i++;
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
kfree(dataBuf_start);
};
out:
if (ret) {
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
kfree(dataBuf_start);
}
if (left_blkcnt || left_size) {
MSG(ERR, "left_blkcnt or left_size is not empty!!!!!!\n");
return RPMB_TRANSFER_NOT_COMPLETE;
}
MSG(DBG_INFO, "%s end!!!\n", __func__);
return ret;
}
int rpmb_req_ioctl_read_data_ufs(struct rpmb_ioc_param *param)
{
int err = 0;
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb;
u32 tran_size, left_size = param->data_len;
u16 iCnt, tran_blkcnt, left_blkcnt;
u16 blkaddr;
u8 nonce[RPMB_SZ_NONCE] = {0};
u8 hmac[RPMB_SZ_MAC];
u8 *dataBuf, *dataBuf_start;
u8 key[32];
u32 size_for_hmac;
int i, ret = 0;
u8 user_param_data;
MSG(DBG_INFO, "%s start!!!\n", __func__);
if (get_user(user_param_data, param->data))
return -EFAULT;
if (get_user(user_param_data, param->key))
return -EFAULT;
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
i = 0;
tran_blkcnt = 0;
dataBuf = NULL;
dataBuf_start = NULL;
/* Get user key */
err = copy_from_user(key, param->key, 32);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n", __func__, err);
return -EFAULT;
}
left_blkcnt = ((param->data_len % RPMB_SZ_DATA) ?
(param->data_len / RPMB_SZ_DATA + 1) :
(param->data_len / RPMB_SZ_DATA));
blkaddr = param->addr;
while (left_blkcnt) {
#if (MAX_RPMB_TRANSFER_BLK > 1)
if (left_blkcnt >= MAX_RPMB_TRANSFER_BLK)
tran_blkcnt = MAX_RPMB_TRANSFER_BLK;
else
tran_blkcnt = left_blkcnt;
#else
tran_blkcnt = 1;
#endif
MSG(DBG_INFO, "%s, left_blkcnt = 0x%x, tran_blkcnt = 0x%x\n",
__func__, left_blkcnt, tran_blkcnt);
/*
* initial frame buffers
*/
data.icmd.frames = rpmb_alloc_frames(1);
if (data.icmd.frames == NULL)
return RPMB_ALLOC_ERROR;
data.ocmd.frames = rpmb_alloc_frames(tran_blkcnt);
if (data.ocmd.frames == NULL) {
kfree(data.icmd.frames);
return RPMB_ALLOC_ERROR;
}
/*
* Initial data buffer for HMAC computation.
* Since HAMC computation tool which we use needs consecutive
* data buffer.Pre-alloced it.
*/
dataBuf_start = dataBuf = kzalloc(284 * tran_blkcnt, 0);
if (!dataBuf_start) {
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
return RPMB_ALLOC_ERROR;
}
get_random_bytes(nonce, RPMB_SZ_NONCE);
/*
* Prepare request read data frame.
*
* Input frame (in view of device) only needs addr and nonce.
*/
data.req_type = RPMB_READ_DATA;
data.icmd.nframes = 1;
data.icmd.frames->req_resp = cpu_to_be16(RPMB_READ_DATA);
data.icmd.frames->addr = cpu_to_be16(blkaddr);
data.icmd.frames->block_count = cpu_to_be16(tran_blkcnt);
memcpy(data.icmd.frames->nonce, nonce, RPMB_SZ_NONCE);
/* output frames (in view of device) */
data.ocmd.nframes = tran_blkcnt;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret) {
MSG(ERR, "%s, rpmb_cmd_req IO error!!!(0x%x)\n",
__func__, ret);
break;
}
/*
* Retrieve every data frame one by one.
*/
/* size for hmac calculation: 512 - 228 = 284 */
size_for_hmac =
sizeof(struct rpmb_frame) - offsetof(struct rpmb_frame, data);
for (iCnt = 0; iCnt < tran_blkcnt; iCnt++) {
if (left_size >= RPMB_SZ_DATA)
tran_size = RPMB_SZ_DATA;
else
tran_size = left_size;
/*
* dataBuf used for hmac calculation. we need to
* aggregate each block's data till to type field.
* each block has 284 bytes (size_for_hmac)
* need aggregation.
*/
rpmb_req_copy_data_for_hmac(
dataBuf, &data.ocmd.frames[iCnt]);
dataBuf += size_for_hmac;
err = copy_to_user(
(param->data +
i * MAX_RPMB_TRANSFER_BLK * RPMB_SZ_DATA +
(iCnt * RPMB_SZ_DATA)),
data.ocmd.frames[iCnt].data,
tran_size);
if (err) {
MSG(ERR, "%s, copy to user failed: %x\n",
__func__, err);
ret = -EFAULT;
goto out;
}
left_size -= tran_size;
}
iCnt--;
/*
* Authenticate response read data frame.
*/
hmac_sha256(key,
32, dataBuf_start, size_for_hmac * tran_blkcnt, hmac);
if (memcmp(hmac, data.ocmd.frames[iCnt].key_mac, RPMB_SZ_MAC)
!= 0) {
MSG(ERR, "%s, hmac compare error!!!\n", __func__);
ret = RPMB_HMAC_ERROR;
break;
}
if (memcmp(nonce, data.ocmd.frames[iCnt].nonce, RPMB_SZ_NONCE)
!= 0) {
MSG(ERR, "%s, nonce compare error!!!\n", __func__);
ret = RPMB_NONCE_ERROR;
break;
}
if (data.ocmd.frames[iCnt].result) {
MSG(ERR, "%s, result error!!! (0x%x)\n",
__func__,
cpu_to_be16p(&data.ocmd.frames[iCnt].result));
ret = RPMB_RESULT_ERROR;
break;
}
blkaddr += tran_blkcnt;
left_blkcnt -= tran_blkcnt;
i++;
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
kfree(dataBuf_start);
};
out:
if (ret) {
kfree(data.icmd.frames);
kfree(data.ocmd.frames);
kfree(dataBuf_start);
}
if (left_blkcnt || left_size) {
MSG(ERR, "left_blkcnt or left_size is not empty!!!!!!\n");
return RPMB_TRANSFER_NOT_COMPLETE;
}
MSG(DBG_INFO, "%s end!!!\n", __func__);
return ret;
}
#endif
int rpmb_req_get_wc_emmc(struct mmc_card *card, u8 *key, u32 *wc)
{
struct emmc_rpmb_req rpmb_req;
struct s_rpmb *rpmb_frame;
u8 nonce[RPMB_SZ_NONCE] = {0};
u8 hmac[RPMB_SZ_MAC];
int ret;
MSG(INFO, "%s start!!!\n", __func__);
do {
rpmb_frame = kzalloc(sizeof(struct s_rpmb), 0);
if (rpmb_frame == NULL)
return RPMB_ALLOC_ERROR;
get_random_bytes(nonce, RPMB_SZ_NONCE);
/*
* Prepare request. Get write counter.
*/
rpmb_req.type = RPMB_GET_WRITE_COUNTER;
rpmb_req.blk_cnt = 1;
rpmb_req.data_frame = (u8 *)rpmb_frame;
/*
* Prepare get write counter frame. only need nonce.
*/
rpmb_frame->request = cpu_to_be16p(&rpmb_req.type);
memcpy(rpmb_frame->nonce, nonce, RPMB_SZ_NONCE);
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
break;
}
/*
* Authenticate response write counter frame.
*/
if (key) {
hmac_sha256(key, 32, rpmb_frame->data, 284, hmac);
if (memcmp(hmac, rpmb_frame->mac, RPMB_SZ_MAC) != 0) {
MSG(ERR, "%s, hmac compare error!!!\n",
__func__);
ret = RPMB_HMAC_ERROR;
break;
}
}
if (memcmp(nonce, rpmb_frame->nonce, RPMB_SZ_NONCE) != 0) {
MSG(ERR, "%s, nonce compare error!!!\n", __func__);
ret = RPMB_NONCE_ERROR;
break;
}
if (rpmb_frame->result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16p(&rpmb_frame->result));
ret = RPMB_RESULT_ERROR;
break;
}
*wc = cpu_to_be32p(&rpmb_frame->write_counter);
} while (0);
MSG(INFO, "%s end!!!\n", __func__);
kfree(rpmb_frame);
return ret;
}
int rpmb_req_ioctl_write_data_emmc(struct mmc_card *card,
struct rpmb_ioc_param *param)
{
struct emmc_rpmb_req rpmb_req;
struct s_rpmb *rpmb_frame;
u32 tran_size, left_size = param->data_len;
u32 wc = 0xFFFFFFFF;
u16 iCnt, total_blkcnt, tran_blkcnt, left_blkcnt;
u16 blkaddr;
u8 hmac[RPMB_SZ_MAC];
u8 *dataBuf, *dataBuf_start;
int i, ret = 0;
#ifdef RPMB_MULTI_BLOCK_ACCESS
u8 write_blks_one_time = 0;
u32 size_for_hmac;
#endif
MSG(INFO, "%s start!!!\n", __func__);
i = 0;
tran_blkcnt = 0;
dataBuf = NULL;
dataBuf_start = NULL;
left_blkcnt = total_blkcnt = ((param->data_len % RPMB_SZ_DATA) ?
(param->data_len / RPMB_SZ_DATA + 1) :
(param->data_len / RPMB_SZ_DATA));
#ifdef RPMB_MULTI_BLOCK_ACCESS
/*
* For RPMB write data, the elements we need in the data frame is
* 1. address.
* 2. write counter.
* 3. data.
* 4. block count.
* 5. MAC
*
*/
blkaddr = param->addr;
write_blks_one_time = MIN(MAX_RPMB_TRANSFER_BLK,
card->ext_csd.rel_sectors * 2);
while (left_blkcnt) {
if (left_blkcnt > write_blks_one_time)
tran_blkcnt = write_blks_one_time;
else
tran_blkcnt = left_blkcnt;
MSG(INFO, "%s, total_blkcnt=%x, tran_blkcnt=%x\n",
__func__, left_blkcnt, tran_blkcnt);
ret = rpmb_req_get_wc_emmc(card, param->key, &wc);
if (ret) {
MSG(ERR, "%s, rpmb_req_get_wc_emmc error!!!(%x)\n",
__func__, ret);
return ret;
}
rpmb_frame = kzalloc(tran_blkcnt * sizeof(struct s_rpmb)
+ tran_blkcnt * 512, 0);
if (rpmb_frame == NULL)
return RPMB_ALLOC_ERROR;
dataBuf_start = dataBuf = (u8 *)(rpmb_frame + tran_blkcnt);
/*
* Prepare request. write data.
*/
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = tran_blkcnt;
rpmb_req.data_frame = (u8 *)rpmb_frame;
/*
* STEP 3(data), prepare every data frame one by one and
* hook HMAC to the last.
*/
/* size for hmac calculation: 512 - 228 = 284 */
size_for_hmac =
sizeof(struct rpmb_frame) - offsetof(struct rpmb_frame, data);
for (iCnt = 0; iCnt < tran_blkcnt; iCnt++) {
/*
* Prepare write data frame. need addr, wc,
* blkcnt, data and mac.
*/
rpmb_frame[iCnt].request = cpu_to_be16p(&rpmb_req.type);
rpmb_frame[iCnt].address = cpu_to_be16p(&blkaddr);
rpmb_frame[iCnt].write_counter = cpu_to_be32p(&wc);
rpmb_frame[iCnt].block_count =
cpu_to_be16p(&rpmb_req.blk_cnt);
if (left_size >= RPMB_SZ_DATA)
tran_size = RPMB_SZ_DATA;
else
tran_size = left_size;
memcpy(rpmb_frame[iCnt].data,
param->data + (iCnt * RPMB_SZ_DATA)
+ i * write_blks_one_time * RPMB_SZ_DATA,
tran_size);
left_size -= tran_size;
rpmb_req_copy_data_for_hmac(dataBuf,
(struct rpmb_frame *) &rpmb_frame[iCnt]);
dataBuf += size_for_hmac;
}
iCnt--;
hmac_sha256(param->key, 32, dataBuf_start, 284 * tran_blkcnt,
rpmb_frame[iCnt].mac);
/*
* STEP 4, send write data request.
*/
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
break;
}
/*
* STEP 5. authenticate write result response.
* 1. authenticate hmac.
* 2. check result.
* 3. compare write counter is increamented.
*/
hmac_sha256(param->key, 32, rpmb_frame->data, 284, hmac);
if (memcmp(hmac, rpmb_frame->mac, RPMB_SZ_MAC) != 0) {
MSG(ERR, "%s, hmac compare error!!!\n", __func__);
ret = RPMB_HMAC_ERROR;
break;
}
if (rpmb_frame->result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16p(&rpmb_frame->result));
ret = RPMB_RESULT_ERROR;
break;
}
if (cpu_to_be32p(&rpmb_frame->write_counter) != wc + 1) {
MSG(ERR, "%s, write counter error!!! (%x)\n", __func__,
cpu_to_be32p(&rpmb_frame->write_counter));
ret = RPMB_WC_ERROR;
break;
}
blkaddr += tran_blkcnt;
left_blkcnt -= tran_blkcnt;
i++;
kfree(rpmb_frame);
};
if (ret)
kfree(rpmb_frame);
if (left_blkcnt || left_size) {
MSG(ERR, "left_blkcnt or left_size is not empty!!!!!!\n");
return RPMB_TRANSFER_NOT_COMPLETE;
}
#else
rpmb_frame = kzalloc(sizeof(struct s_rpmb), 0);
if (rpmb_frame == NULL)
return RPMB_ALLOC_ERROR;
blkaddr = param->addr;
for (iCnt = 0; iCnt < total_blkcnt; iCnt++) {
ret = rpmb_req_get_wc_emmc(card, param->key, &wc);
if (ret)
break;
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
/*
* Prepare request. write data.
*/
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = 1;
rpmb_req.data_frame = (u8 *)rpmb_frame;
/*
* Prepare write data frame. need addr, wc,
* blkcnt, data and mac.
*/
rpmb_frame->request = cpu_to_be16p(&rpmb_req.type);
rpmb_frame->address = cpu_to_be16p(&blkaddr);
rpmb_frame->write_counter = cpu_to_be32p(&wc);
rpmb_frame->block_count = cpu_to_be16p(&rpmb_req.blk_cnt);
if (left_size >= RPMB_SZ_DATA)
tran_size = RPMB_SZ_DATA;
else
tran_size = left_size;
memcpy(rpmb_frame->data,
param->data + iCnt * RPMB_SZ_DATA, tran_size);
hmac_sha256(param->key, 32, rpmb_frame->data, 284,
rpmb_frame->mac);
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
break;
}
/*
* Authenticate response write data frame.
*/
hmac_sha256(param->key, 32, rpmb_frame->data, 284, hmac);
if (memcmp(hmac, rpmb_frame->mac, RPMB_SZ_MAC) != 0) {
MSG(ERR, "%s, hmac compare error!!!\n", __func__);
ret = RPMB_HMAC_ERROR;
break;
}
if (rpmb_frame->result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16p(&rpmb_frame->result));
ret = RPMB_RESULT_ERROR;
break;
}
if (cpu_to_be32p(&rpmb_frame->write_counter) != wc + 1) {
MSG(ERR, "%s, write counter error!!! (%x)\n", __func__,
cpu_to_be32p(&rpmb_frame->write_counter));
ret = RPMB_WC_ERROR;
break;
}
left_size -= tran_size;
blkaddr++;
}
kfree(rpmb_frame);
#endif
MSG(INFO, "%s end!!!\n", __func__);
return ret;
}
int rpmb_req_ioctl_read_data_emmc(struct mmc_card *card,
struct rpmb_ioc_param *param)
{
struct emmc_rpmb_req rpmb_req;
/* if we put a large static buffer here, it will build fail.
* rpmb_frame[MAX_RPMB_TRANSFER_BLK];
* so I use dynamic alloc.
*/
struct s_rpmb *rpmb_frame;
u32 tran_size, left_size = param->data_len;
u16 iCnt, total_blkcnt, tran_blkcnt, left_blkcnt;
u16 blkaddr;
u8 nonce[RPMB_SZ_NONCE] = {0};
u8 hmac[RPMB_SZ_MAC];
u8 *dataBuf, *dataBuf_start;
int i, ret = 0;
#ifdef RPMB_MULTI_BLOCK_ACCESS
u32 size_for_hmac;
#endif
MSG(INFO, "%s start!!!\n", __func__);
i = 0;
tran_blkcnt = 0;
dataBuf = NULL;
dataBuf_start = NULL;
left_blkcnt = total_blkcnt = ((param->data_len % RPMB_SZ_DATA) ?
(param->data_len / RPMB_SZ_DATA + 1) :
(param->data_len / RPMB_SZ_DATA));
#ifdef RPMB_MULTI_BLOCK_ACCESS
blkaddr = param->addr;
while (left_blkcnt) {
if (left_blkcnt >= MAX_RPMB_TRANSFER_BLK)
tran_blkcnt = MAX_RPMB_TRANSFER_BLK;
else
tran_blkcnt = left_blkcnt;
MSG(INFO, "%s, left_blkcnt=%x, tran_blkcnt=%x\n", __func__,
left_blkcnt, tran_blkcnt);
/*
* initial buffer. (since HMAC computation of multi block needs
* multi buffer, pre-alloced it)
*/
rpmb_frame =
kzalloc(tran_blkcnt * sizeof(struct s_rpmb) + tran_blkcnt * 512, 0);
if (rpmb_frame == NULL)
return RPMB_ALLOC_ERROR;
dataBuf_start = dataBuf = (u8 *)(rpmb_frame + tran_blkcnt);
get_random_bytes(nonce, RPMB_SZ_NONCE);
/*
* Prepare request.
*/
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = tran_blkcnt;
rpmb_req.data_frame = (u8 *)rpmb_frame;
/*
* Prepare request read data frame. only need addr and nonce.
*/
rpmb_frame->request = cpu_to_be16p(&rpmb_req.type);
rpmb_frame->address = cpu_to_be16p(&blkaddr);
memcpy(rpmb_frame->nonce, nonce, RPMB_SZ_NONCE);
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
break;
}
/*
* STEP 3, retrieve every data frame one by one.
*/
/* size for hmac calculation: 512 - 228 = 284 */
size_for_hmac =
sizeof(struct rpmb_frame) - offsetof(struct rpmb_frame, data);
for (iCnt = 0; iCnt < tran_blkcnt; iCnt++) {
if (left_size >= RPMB_SZ_DATA)
tran_size = RPMB_SZ_DATA;
else
tran_size = left_size;
/*
* dataBuf used for hmac calculation. we need to
* aggregate each block's data till to type field.
* each block has 284 bytes need to aggregate.
*/
rpmb_req_copy_data_for_hmac(dataBuf,
(struct rpmb_frame *) &rpmb_frame[iCnt]);
dataBuf += size_for_hmac;
/*
* sorry, I shouldn't copy read data to user's buffer
* now, it should be later
* after checking no problem,
* but for convenience...you know...
*/
memcpy(
param->data + i * MAX_RPMB_TRANSFER_BLK * RPMB_SZ_DATA + (iCnt * RPMB_SZ_DATA),
rpmb_frame[iCnt].data,
tran_size);
left_size -= tran_size;
}
iCnt--;
/*
* Authenticate response read data frame.
*/
hmac_sha256(param->key,
32, dataBuf_start, 284 * tran_blkcnt, hmac);
if (memcmp(hmac, rpmb_frame[iCnt].mac, RPMB_SZ_MAC) != 0) {
MSG(ERR, "%s, hmac compare error!!!\n", __func__);
ret = RPMB_HMAC_ERROR;
break;
}
if (memcmp(nonce, rpmb_frame[iCnt].nonce, RPMB_SZ_NONCE) != 0) {
MSG(ERR, "%s, nonce compare error!!!\n", __func__);
ret = RPMB_NONCE_ERROR;
break;
}
if (rpmb_frame[iCnt].result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16p(&rpmb_frame[iCnt].result));
ret = RPMB_RESULT_ERROR;
break;
}
blkaddr += tran_blkcnt;
left_blkcnt -= tran_blkcnt;
i++;
kfree(rpmb_frame);
};
if (ret)
kfree(rpmb_frame);
if (left_blkcnt || left_size) {
MSG(ERR, "left_blkcnt or left_size is not empty!!!!!!\n");
return RPMB_TRANSFER_NOT_COMPLETE;
}
#else
rpmb_frame = kzalloc(sizeof(struct s_rpmb), 0);
if (rpmb_frame == NULL)
return RPMB_ALLOC_ERROR;
blkaddr = param->addr;
for (iCnt = 0; iCnt < total_blkcnt; iCnt++) {
memset(rpmb_frame, 0, sizeof(struct s_rpmb));
get_random_bytes(nonce, RPMB_SZ_NONCE);
/*
* Prepare request.
*/
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = 1;
rpmb_req.data_frame = (u8 *)rpmb_frame;
/*
* Prepare request read data frame. only need addr and nonce.
*/
rpmb_frame->request = cpu_to_be16p(&rpmb_req.type);
rpmb_frame->address = cpu_to_be16p(&blkaddr);
memcpy(rpmb_frame->nonce, nonce, RPMB_SZ_NONCE);
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
break;
}
/*
* Authenticate response read data frame.
*/
hmac_sha256(param->key, 32, rpmb_frame->data, 284, hmac);
if (memcmp(hmac, rpmb_frame->mac, RPMB_SZ_MAC) != 0) {
MSG(ERR, "%s, hmac compare error!!!\n", __func__);
ret = RPMB_HMAC_ERROR;
break;
}
if (memcmp(nonce, rpmb_frame->nonce, RPMB_SZ_NONCE) != 0) {
MSG(ERR, "%s, nonce compare error!!!\n", __func__);
ret = RPMB_NONCE_ERROR;
break;
}
if (rpmb_frame->result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16p(&rpmb_frame->result));
ret = RPMB_RESULT_ERROR;
break;
}
if (left_size >= RPMB_SZ_DATA)
tran_size = RPMB_SZ_DATA;
else
tran_size = left_size;
memcpy(param->data + RPMB_SZ_DATA * iCnt,
rpmb_frame->data, tran_size);
left_size -= tran_size;
blkaddr++;
}
kfree(rpmb_frame);
#endif
MSG(INFO, "%s end!!!\n", __func__);
return ret;
}
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
int ut_rpmb_req_get_max_wr_size(struct mmc_card *card,
unsigned int *max_wr_size)
{
*max_wr_size = card->ext_csd.rel_sectors;
return 0;
}
int ut_rpmb_req_get_wc(struct mmc_card *card, unsigned int *wc)
{
struct emmc_rpmb_req rpmb_req;
struct s_rpmb rpmb_frame;
u8 nonce[RPMB_SZ_NONCE] = {0};
int ret;
memset(&rpmb_frame, 0, sizeof(rpmb_frame));
get_random_bytes(nonce, RPMB_SZ_NONCE);
/*
* Prepare request. Get write counter.
*/
rpmb_req.type = RPMB_GET_WRITE_COUNTER;
rpmb_req.blk_cnt = 1;
rpmb_req.data_frame = (u8 *)&rpmb_frame;
/*
* Prepare get write counter frame. only need nonce.
*/
rpmb_frame.request = cpu_to_be16p(&rpmb_req.type);
memcpy(rpmb_frame.nonce, nonce, RPMB_SZ_NONCE);
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret) {
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
return ret;
}
if (memcmp(nonce, rpmb_frame.nonce, RPMB_SZ_NONCE) != 0) {
MSG(ERR, "%s, nonce compare error!!!\n", __func__);
ret = RPMB_NONCE_ERROR;
return ret;
}
if (rpmb_frame.result) {
MSG(ERR, "%s, result error!!! (%x)\n", __func__,
cpu_to_be16p(&rpmb_frame.result));
ret = RPMB_RESULT_ERROR;
return cpu_to_be16p(&rpmb_frame.result);
}
*wc = cpu_to_be32p(&rpmb_frame.write_counter);
return ret;
}
EXPORT_SYMBOL(ut_rpmb_req_get_wc);
int ut_rpmb_req_read_data(struct mmc_card *card,
struct s_rpmb *param, u32 blk_cnt)/*struct mmc_card *card, */
{
struct emmc_rpmb_req rpmb_req;
int ret;
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = blk_cnt;
rpmb_req.data_frame = (u8 *)param;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
return ret;
}
EXPORT_SYMBOL(ut_rpmb_req_read_data);
int ut_rpmb_req_write_data(struct mmc_card *card,
struct s_rpmb *param, u32 blk_cnt)/*struct mmc_card *card, */
{
struct emmc_rpmb_req rpmb_req;
int ret;
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = blk_cnt;
rpmb_req.data_frame = (u8 *)param;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle IO error!!!(%x)\n",
__func__, ret);
return ret;
}
EXPORT_SYMBOL(ut_rpmb_req_write_data);
#endif /* CONFIG_MICROTRUST_TEE_SUPPORT */
/*
* End of above.
*/
#ifdef CONFIG_TRUSTONIC_TEE_SUPPORT
#ifdef CONFIG_SCSI_UFS_MEDIATEK
#ifndef CONFIG_TEE
static int rpmb_execute_ufs(u32 cmdId)
{
int ret;
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_READ_DATA\n", __func__);
ret = rpmb_req_read_data_ufs(rpmb_dci->request.frame,
rpmb_dci->request.blks);
break;
case DCI_RPMB_CMD_GET_WCNT:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_GET_WCNT\n", __func__);
ret = rpmb_req_get_wc_ufs(NULL, NULL, rpmb_dci->request.frame);
break;
case DCI_RPMB_CMD_WRITE_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_WRITE_DATA\n", __func__);
ret = rpmb_req_write_data_ufs(rpmb_dci->request.frame,
rpmb_dci->request.blks);
break;
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
case DCI_RPMB_CMD_PROGRAM_KEY:
MSG(INFO, "%s: DCI_RPMB_CMD_PROGRAM_KEY.\n", __func__);
rpmb_dump_frame(rpmb_dci->request.frame);
ret = rpmb_req_program_key_ufs(rpmb_dci->request.frame, 1);
break;
#endif
default:
MSG(ERR, "%s: receive an unknown command id (%d).\n",
__func__, cmdId);
break;
}
return 0;
}
#endif
static int rpmb_gp_execute_ufs(u32 cmdId)
{
int ret;
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_READ_DATA\n", __func__);
ret = rpmb_req_read_data_ufs(rpmb_gp_dci->request.frame,
rpmb_gp_dci->request.blks);
break;
case DCI_RPMB_CMD_GET_WCNT:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_GET_WCNT\n", __func__);
ret = rpmb_req_get_wc_ufs(NULL, NULL,
rpmb_gp_dci->request.frame);
break;
case DCI_RPMB_CMD_WRITE_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_WRITE_DATA\n", __func__);
ret = rpmb_req_write_data_ufs(rpmb_gp_dci->request.frame,
rpmb_gp_dci->request.blks);
break;
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
case DCI_RPMB_CMD_PROGRAM_KEY:
MSG(INFO, "%s: DCI_RPMB_CMD_PROGRAM_KEY.\n", __func__);
rpmb_dump_frame(rpmb_gp_dci->request.frame);
ret = rpmb_req_program_key_ufs(rpmb_gp_dci->request.frame, 1);
break;
#endif
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, cmdId);
break;
}
return 0;
}
#endif
#ifndef CONFIG_TEE
#if defined(CONFIG_MMC_MTK_PRO) || defined(CONFIG_MMC_MTK)
static int rpmb_execute_emmc(u32 cmdId)
{
int ret;
#if defined(CONFIG_MMC_MTK_PRO)
struct mmc_card *card = mtk_msdc_host[0]->mmc->card;
#else
struct mmc_host *mmc = mtk_mmc_host[0];
struct mmc_card *card = mmc->card;
#endif
struct emmc_rpmb_req rpmb_req;
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_READ_DATA.\n", __func__);
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = rpmb_dci->request.blks;
rpmb_req.addr = rpmb_dci->request.addr;
rpmb_req.data_frame = rpmb_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case DCI_RPMB_CMD_GET_WCNT:
MSG(INFO, "%s: DCI_RPMB_CMD_GET_WCNT.\n", __func__);
rpmb_req.type = RPMB_GET_WRITE_COUNTER;
rpmb_req.blk_cnt = rpmb_dci->request.blks;
rpmb_req.addr = rpmb_dci->request.addr;
rpmb_req.data_frame = rpmb_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case DCI_RPMB_CMD_WRITE_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_WRITE_DATA.\n", __func__);
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = rpmb_dci->request.blks;
rpmb_req.addr = rpmb_dci->request.addr;
rpmb_req.data_frame = rpmb_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
case DCI_RPMB_CMD_PROGRAM_KEY:
MSG(INFO, "%s: DCI_RPMB_CMD_PROGRAM_KEY.\n", __func__);
rpmb_dump_frame(rpmb_dci->request.frame);
rpmb_req.type = RPMB_PROGRAM_KEY;
/* rpmb_req.blk_cnt = rpmb_dci->request.blks; */
rpmb_req.blk_cnt = 1;
rpmb_req.addr = rpmb_dci->request.addr;
rpmb_req.data_frame = rpmb_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
#endif
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, cmdId);
break;
}
return 0;
}
#endif
#endif
#if defined(CONFIG_MMC_MTK_PRO) || defined(CONFIG_MMC_MTK)
static int rpmb_gp_execute_emmc(u32 cmdId)
{
int ret;
#if defined(CONFIG_MMC_MTK_PRO)
struct mmc_card *card = mtk_msdc_host[0]->mmc->card;
#else
struct mmc_host *mmc = mtk_mmc_host[0];
struct mmc_card *card = mmc->card;
#endif
struct emmc_rpmb_req rpmb_req;
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_READ_DATA.\n", __func__);
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case DCI_RPMB_CMD_GET_WCNT:
MSG(INFO, "%s: DCI_RPMB_CMD_GET_WCNT.\n", __func__);
rpmb_req.type = RPMB_GET_WRITE_COUNTER;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case DCI_RPMB_CMD_WRITE_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_WRITE_DATA.\n", __func__);
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
case DCI_RPMB_CMD_PROGRAM_KEY:
MSG(INFO, "%s: DCI_RPMB_CMD_PROGRAM_KEY.\n", __func__);
rpmb_dump_frame(rpmb_gp_dci->request.frame);
rpmb_req.type = RPMB_PROGRAM_KEY;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
#endif
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, cmdId);
break;
}
return 0;
}
#endif
#ifndef CONFIG_TEE
int rpmb_listenDci(void *data)
{
enum mc_result mc_ret;
u32 cmdId;
MSG(INFO, "%s: DCI listener.\n", __func__);
for (;;) {
MSG(INFO, "%s: Waiting for notification\n", __func__);
/* Wait for notification from SWd */
mc_ret = mc_wait_notification(&rpmb_session,
MC_INFINITE_TIMEOUT);
if (mc_ret != MC_DRV_OK) {
MSG(ERR, "%s: mcWaitNotification failed, mc_ret=%d\n",
__func__, mc_ret);
break;
}
cmdId = rpmb_dci->command.header.commandId;
MSG(INFO, "%s: wait notification done!! cmdId = %x\n",
__func__, cmdId);
#if defined(CONFIG_MMC_MTK_PRO)
/* Received exception. */
if (mtk_msdc_host[0] && mtk_msdc_host[0]->mmc
&& mtk_msdc_host[0]->mmc->card)
mc_ret = rpmb_execute_emmc(cmdId);
else
#elif defined(CONFIG_MMC_MTK)
/* Received exception. */
if (mtk_mmc_host[0] && mtk_mmc_host[0]->card)
mc_ret = rpmb_execute_emmc(cmdId);
else
#endif
#ifdef CONFIG_SCSI_UFS_MEDIATEK
mc_ret = rpmb_execute_ufs(cmdId);
#else
return -EFAULT;
#endif
/* Notify the STH */
mc_ret = mc_notify(&rpmb_session);
if (mc_ret != MC_DRV_OK) {
MSG(ERR, "%s: mcNotify returned: %d\n",
__func__, mc_ret);
break;
}
}
return 0;
}
#endif
#ifndef CONFIG_TEE
static int rpmb_open_session(void)
{
int cnt = 0;
enum mc_result mc_ret = MC_DRV_ERR_UNKNOWN;
MSG(INFO, "%s start\n", __func__);
do {
msleep(2000);
/* open device */
mc_ret = mc_open_device(rpmb_devid);
if (mc_ret != MC_DRV_OK) {
MSG(ERR, "%s, mc_open_device failed: %d\n",
__func__, mc_ret);
cnt++;
continue;
}
MSG(INFO, "%s, mc_open_device success.\n", __func__);
/* allocating WSM for DCI */
mc_ret = mc_malloc_wsm(rpmb_devid, 0,
sizeof(struct dciMessage_t),
(uint8_t **)&rpmb_dci, 0);
if (mc_ret != MC_DRV_OK) {
mc_close_device(rpmb_devid);
MSG(ERR, "%s, mc_malloc_wsm failed: %d\n",
__func__, mc_ret);
cnt++;
continue;
}
MSG(INFO, "%s, mc_malloc_wsm success.\n", __func__);
MSG(INFO, "uuid[0]=%d, uuid[1]=%d, uuid[2]=%d, uuid[3]=%d\n",
rpmb_uuid.value[0], rpmb_uuid.value[1],
rpmb_uuid.value[2], rpmb_uuid.value[3]);
rpmb_session.device_id = rpmb_devid;
/* open session */
mc_ret = mc_open_session(&rpmb_session,
&rpmb_uuid,
(uint8_t *) rpmb_dci,
sizeof(struct dciMessage_t));
if (mc_ret != MC_DRV_OK) {
MSG(ERR,
"%s, mc_open_session failed, result(%d), times(%d)\n",
__func__, mc_ret, cnt);
mc_ret = mc_free_wsm(rpmb_devid, (uint8_t *)rpmb_dci);
MSG(ERR, "%s, free wsm result (%d)\n",
__func__, mc_ret);
mc_ret = mc_close_device(rpmb_devid);
MSG(ERR, "%s, try free wsm and close device\n",
__func__);
cnt++;
continue;
}
MSG(INFO, "%s, mc_open_session success.\n", __func__);
/* create a thread for listening DCI signals */
rpmbDci_th = kthread_run(rpmb_listenDci, NULL, "rpmb_Dci");
if (IS_ERR(rpmbDci_th))
MSG(ERR, "%s, init kthread_run failed!\n", __func__);
else
break;
} while (cnt < 30);
if (cnt >= 30)
MSG(ERR, "%s, open session failed!!!\n", __func__);
MSG(ERR, "%s end, mc_ret = %x\n", __func__, mc_ret);
return mc_ret;
}
#endif
int rpmb_gp_listenDci(void *data)
{
enum mc_result mc_ret;
u32 cmdId;
MSG(ERR, "%s: DCI listener.\n", __func__);
for (;;) {
MSG(INFO, "%s: Waiting for notification\n", __func__);
/* Wait for notification from SWd */
mc_ret = mc_wait_notification(&rpmb_gp_session,
MC_INFINITE_TIMEOUT);
if (mc_ret != MC_DRV_OK) {
MSG(ERR, "%s: mcWaitNotification failed, mc_ret=%d\n",
__func__, mc_ret);
break;
}
cmdId = rpmb_gp_dci->command.header.commandId;
MSG(INFO, "%s: wait notification done!! cmdId = %x\n",
__func__, cmdId);
#if defined(CONFIG_MMC_MTK_PRO)
/* Received exception. */
if (mtk_msdc_host[0] && mtk_msdc_host[0]->mmc
&& mtk_msdc_host[0]->mmc->card)
mc_ret = rpmb_gp_execute_emmc(cmdId);
else
#elif defined(CONFIG_MMC_MTK)
/* Received exception. */
if (mtk_mmc_host[0] && mtk_mmc_host[0]->card)
mc_ret = rpmb_gp_execute_emmc(cmdId);
else
#endif
#ifdef CONFIG_SCSI_UFS_MEDIATEK
mc_ret = rpmb_gp_execute_ufs(cmdId);
#else
return -EFAULT;
#endif
/* Notify the STH*/
mc_ret = mc_notify(&rpmb_gp_session);
if (mc_ret != MC_DRV_OK) {
MSG(ERR, "%s: mcNotify returned: %d\n",
__func__, mc_ret);
break;
}
}
return 0;
}
static int rpmb_gp_open_session(void)
{
int cnt = 0;
enum mc_result mc_ret = MC_DRV_ERR_UNKNOWN;
MSG(INFO, "%s start\n", __func__);
do {
msleep(500);
/* open device */
mc_ret = mc_open_device(rpmb_gp_devid);
if (mc_ret != MC_DRV_OK) {
MSG(ERR, "%s, mc_open_device failed: %d\n",
__func__, mc_ret);
cnt++;
continue;
}
MSG(INFO, "%s, mc_open_device success.\n", __func__);
/* allocating WSM for DCI */
mc_ret = mc_malloc_wsm(rpmb_gp_devid, 0,
sizeof(struct dciMessage_t),
(uint8_t **)&rpmb_gp_dci, 0);
if (mc_ret != MC_DRV_OK) {
mc_close_device(rpmb_gp_devid);
MSG(ERR, "%s, mc_malloc_wsm failed: %d\n",
__func__, mc_ret);
cnt++;
continue;
}
MSG(INFO, "%s, mc_malloc_wsm success.\n", __func__);
MSG(INFO, "uuid[0]=%d, uuid[1]=%d, uuid[2]=%d, uuid[3]=%d\n",
rpmb_gp_uuid.value[0],
rpmb_gp_uuid.value[1],
rpmb_gp_uuid.value[2],
rpmb_gp_uuid.value[3]
);
rpmb_gp_session.device_id = rpmb_gp_devid;
/* open session */
mc_ret = mc_open_session(&rpmb_gp_session,
&rpmb_gp_uuid,
(uint8_t *) rpmb_gp_dci,
sizeof(struct dciMessage_t));
if (mc_ret != MC_DRV_OK) {
MSG(ERR,
"%s, mc_open_session failed, result(%d), times(%d)\n",
__func__, mc_ret, cnt);
mc_ret = mc_free_wsm(rpmb_gp_devid,
(uint8_t *)rpmb_gp_dci);
MSG(ERR, "%s, free wsm result (%d)\n",
__func__, mc_ret);
mc_ret = mc_close_device(rpmb_gp_devid);
MSG(ERR, "%s, try free wsm and close device\n",
__func__);
cnt++;
continue;
}
MSG(INFO, "%s, mc_open_session success.\n", __func__);
/* create a thread for listening DCI signals */
rpmb_gp_Dci_th = kthread_run(rpmb_gp_listenDci,
NULL, "rpmb_gp_Dci");
if (IS_ERR(rpmb_gp_Dci_th))
MSG(ERR, "%s, init kthread_run failed!\n", __func__);
else
break;
} while (cnt < 240);
if (cnt >= 240)
MSG(ERR, "%s, open session failed!!!\n", __func__);
MSG(ERR, "%s end, mc_ret = %x\n", __func__, mc_ret);
return mc_ret;
}
static int rpmb_thread(void *context)
{
int ret;
MSG(INFO, "%s start\n", __func__);
#ifndef CONFIG_TEE
ret = rpmb_open_session();
MSG(INFO, "%s rpmb_open_session, ret = %x\n", __func__, ret);
#endif
ret = rpmb_gp_open_session();
MSG(INFO, "%s rpmb_gp_open_session, ret = %x\n", __func__, ret);
return 0;
}
#endif
#ifdef CONFIG_TEEGRIS_TEE_SUPPORT
static struct rpmb_ctx *create_rpmb_ctx(void)
{
struct rpmb_ctx *ctx;
ctx = kzalloc(sizeof(struct rpmb_ctx), GFP_KERNEL);
if (!ctx) {
MSG(ERR, "%s rpmb context alloc failed\n", __func__);
return ERR_PTR(-ENOMEM);
}
return ctx;
}
static int init_rpmb_wsm(struct rpmb_ctx *ctx)
{
ctx->wsm_vaddr = kzalloc(sizeof(struct rpmb_req) + TEEGRIS_MAX_RPMB_REQUEST_SIZE, GFP_KERNEL);
if (!ctx->wsm_vaddr) {
MSG(ERR, "%s failed to alloc rpmb wsm\n", __func__);
return -ENOMEM;
}
MSG(INFO, "%s rpmb dma ddr : virt(%pK)\n",
__func__, (uint64_t)ctx->wsm_vaddr);
ctx->req = (struct rpmb_req *)ctx->wsm_vaddr;
return 0;
}
static struct sock_desc *accept_swd_connection(void)
{
int ret;
struct sock_desc *rpmb_conn;
struct sock_desc *srpmb_listen;
srpmb_listen = tz_iwsock_socket(1, 0);
if (IS_ERR(srpmb_listen)) {
MSG(ERR, "failed to create iwd socket, err = %ld\n", PTR_ERR(srpmb_listen));
return srpmb_listen;
}
MSG(INFO, "Created socket\n");
ret = tz_iwsock_listen(srpmb_listen, RPMB_SOCKET_NAME);
if (ret) {
MSG(ERR, "failed make iwd socket listening, err = %d\n", ret);
rpmb_conn = ERR_PTR(ret);
goto out;
}
MSG(INFO, "Make socket listening\n");
/* Accept connection */
rpmb_conn = tz_iwsock_accept(srpmb_listen);
if (IS_ERR(rpmb_conn)) {
MSG(ERR, "failed to accept connection, err = %ld\n", PTR_ERR(rpmb_conn));
goto out;
}
MSG(INFO, "Accepted connection\n");
out:
tz_iwsock_release(srpmb_listen);
return rpmb_conn;
}
static int register_rpmb_wsm(struct rpmb_ctx *ctx, struct sock_desc *rpmb_conn)
{
int ret;
ssize_t len;
uint64_t sock_data;
len = tz_iwsock_read(rpmb_conn, &sock_data, sizeof(sock_data), 0);
if (len > 0 && len != sizeof(sock_data)) {
MSG(ERR, "failed to receive request, invalid len = %zd\n", len);
return -EMSGSIZE;
} else if (!len) {
MSG(ERR, "connection was reset by peer\n");
return -ECONNRESET;
} else if (len < 0) {
ret = len;
MSG(ERR, "error while receiving request from SWd, err = %u\n", ret);
return ret;
}
if (sock_data != RPMB_IPC_MAGIC) {
MSG(ERR, "received invalied request data = %llx\n", sock_data);
return -EINVAL;
}
sock_data = virt_to_phys(ctx->wsm_vaddr);
len = tz_iwsock_write(rpmb_conn, &sock_data, sizeof(sock_data), 0);
if (len != sizeof(sock_data)) {
ret = len >= 0 ? -EMSGSIZE : len;
MSG(ERR, "failed to send reply, err = %d\n", ret);
return ret;
}
MSG(INFO, "%s registered WSM success\n", __func__);
return 0;
}
static int rpmb_wait_request(struct sock_desc *rpmb_conn)
{
int ret;
ssize_t len;
unsigned int sock_data;
MSG(INFO, "%s Read wait\n", __func__);
len = tz_iwsock_read(rpmb_conn, &sock_data, sizeof(sock_data), 0);
if (len > 0 && len != sizeof(sock_data)) {
MSG(ERR, "%s failed to receive request, invalid len = %zd\n", __func__, len);
return -EMSGSIZE;
} else if (!len) {
MSG(ERR, "%s connection was reset by peer\n", __func__);
return -ECONNRESET;
} else if (len < 0) {
ret = len;
MSG(ERR, "%s error while receiving request from SWd, err = %u\n", __func__, ret);
return ret;
}
MSG(INFO, "%s Read request\n", __func__);
if (sock_data != RPMB_REQUEST_MAGIC) {
MSG(ERR, "%s received invalied request data = %u\n", __func__, sock_data);
return -EINVAL;
}
return 0;
}
static int rpmb_send_reply(struct sock_desc *rpmb_conn)
{
int ret;
ssize_t len;
unsigned int sock_data;
sock_data = RPMB_REPLY_MAGIC;
len = tz_iwsock_write(rpmb_conn, &sock_data, sizeof(sock_data), 0);
if (len != sizeof(sock_data)) {
ret = len >= 0 ? -EMSGSIZE : len;
MSG(ERR, "%s failed to send reply, err = %d\n", __func__, ret);
return ret;
}
MSG(INFO, "%s Sent reply\n", __func__);
return 0;
}
static inline void release_rpmb_sock(struct sock_desc *rpmb_conn)
{
tz_iwsock_release(rpmb_conn);
}
static inline void release_rpmb_wsm(struct rpmb_ctx *ctx)
{
kfree(ctx->wsm_vaddr);
}
static inline void destroy_rpmb_ctx(struct rpmb_ctx *ctx)
{
kfree(ctx);
}
#ifdef CONFIG_SCSI_UFS_MEDIATEK
static void rpmb_iwsock_execute_ufs(struct rpmb_ctx *ctx)
{
int ret = 0;
switch (ctx->req->type) {
case RPMB_READ_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_READ_DATA\n", __func__);
ret = rpmb_req_read_data_ufs(ctx->req->frame,
ctx->req->blks);
break;
case RPMB_GET_WRITE_COUNTER:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_GET_WCNT\n", __func__);
ret = rpmb_req_get_wc_ufs(NULL, NULL,
ctx->req->frame);
break;
case RPMB_WRITE_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_WRITE_DATA\n", __func__);
ret = rpmb_req_write_data_ufs(ctx->req->frame,
ctx->req->blks);
break;
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, ctx->req->type);
break;
}
if (ret)
MSG(ERR, "%s: Error ret(%d).\n", __func__, ret);
}
#endif
static void rpmb_iwsock_execute_emmc(struct rpmb_ctx *ctx)
{
int ret = 0, cnt = 0;
struct mmc_card *card;
struct emmc_rpmb_req rpmb_req;
#if defined(CONFIG_MMC_MTK_PRO)
while (!mtk_msdc_host[0]
|| !mtk_msdc_host[0]->mmc
|| !mtk_msdc_host[0]->mmc->card
|| !dev_get_drvdata(&(mtk_msdc_host[0]->mmc->card)->dev)) {
msleep(100);
if (cnt++ > 200)
return;
};
card = mtk_msdc_host[0]->mmc->card;
#elif defined(CONFIG_MMC_MTK)
while (!mtk_mmc_host[0]
|| !mtk_mmc_host[0]->card
|| !dev_get_drvdata(&(mtk_mmc_host[0]->card)->dev)) {
msleep(100);
if (cnt++ > 200)
return;
};
card = mtk_mmc_host[0]->card;
#endif
switch (ctx->req->type) {
case RPMB_READ_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_READ_DATA.\n", __func__);
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = ctx->req->blks;
rpmb_req.addr = ctx->req->addr;
rpmb_req.data_frame = ctx->req->frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case RPMB_GET_WRITE_COUNTER:
MSG(INFO, "%s: DCI_RPMB_CMD_GET_WCNT.\n", __func__);
rpmb_req.type = RPMB_GET_WRITE_COUNTER;
rpmb_req.blk_cnt = ctx->req->blks;
rpmb_req.addr = ctx->req->addr;
rpmb_req.data_frame = ctx->req->frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case RPMB_WRITE_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_WRITE_DATA.\n", __func__);
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = ctx->req->blks;
rpmb_req.addr = ctx->req->addr;
rpmb_req.data_frame = ctx->req->frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, ctx->req->type);
break;
}
if (ret)
MSG(ERR, "%s: Error ret(%d).\n", __func__, ret);
}
static int rpmb_iwsock_thread(void *context)
{
int ret;
int boot_type;
struct rpmb_ctx *ctx;
struct sock_desc *rpmb_conn;
MSG(INFO, "%s teegris iwsock thread start\n", __func__);
ctx = create_rpmb_ctx();
if (IS_ERR(ctx)) {
MSG(ERR, "%s failed to alloc context error:%ld\n", __func__, PTR_ERR(ctx));
return PTR_ERR(ctx);
}
ret = init_rpmb_wsm(ctx);
if (ret) {
MSG(ERR, "failed to initialize wsm\n");
goto destroy_ctx;
}
rpmb_conn = accept_swd_connection();
if (IS_ERR(rpmb_conn)) {
MSG(ERR, "%s failed to connect swd error:%ld\n", __func__, PTR_ERR(rpmb_conn));
ret = PTR_ERR(rpmb_conn);
goto release_wsm;
}
ret = register_rpmb_wsm(ctx, rpmb_conn);
if (ret) {
MSG(ERR, "%s failed to register wsm\n", __func__);
goto release_sock;
}
/* rpmb kthread main function */
while (!kthread_should_stop()) {
ret = rpmb_wait_request(rpmb_conn);
if (ret)
goto release_sock;
boot_type = dt_get_boot_type();
mutex_lock(&rpmb_mutex);
if (boot_type == BOOTDEV_SDMMC)
rpmb_iwsock_execute_emmc(ctx);
#ifdef CONFIG_SCSI_UFS_MEDIATEK
else if (boot_type == BOOTDEV_UFS)
rpmb_iwsock_execute_ufs(ctx);
#endif
mutex_unlock(&rpmb_mutex);
ret = rpmb_send_reply(rpmb_conn);
if (ret) {
MSG(ERR, "rpmb send reply error : %d\n", ret);
goto release_sock;
}
}
release_sock:
release_rpmb_sock(rpmb_conn);
release_wsm:
release_rpmb_wsm(ctx);
destroy_ctx:
destroy_rpmb_ctx(ctx);
return ret;
}
#endif
static int rpmb_open(struct inode *inode, struct file *file)
{
#if defined(CONFIG_MICROTRUST_TEE_SUPPORT)
if (rpmb_buffer == NULL) {
MSG(ERR, "%s, rpmb buffer is null!!!\n", __func__);
return -1;
}
MSG(INFO, "%s, rpmb kzalloc memory done!!!\n", __func__);
#endif
return 0;
}
#ifdef CONFIG_SCSI_UFS_MEDIATEK
long rpmb_ioctl_ufs(struct file *file, unsigned int cmd, unsigned long arg)
{
int err = 0;
struct rpmb_ioc_param param;
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
u32 rpmb_size = 0;
u32 arg_k;
struct rpmb_infor rpmbinfor;
struct rpmb_dev *rawdev_ufs_rpmb;
memset(&rpmbinfor, 0, sizeof(struct rpmb_infor));
#endif
err = copy_from_user(&param, (void *)arg, sizeof(param));
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n", __func__, err);
return -EFAULT;
}
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
if ((cmd == RPMB_IOCTL_SOTER_WRITE_DATA) ||
(cmd == RPMB_IOCTL_SOTER_READ_DATA)) {
if (rpmb_buffer == NULL) {
MSG(ERR, "%s, rpmb_buffer is NULL!\n", __func__);
return -1;
}
err = copy_from_user(&rpmb_size, (void *)arg, 4);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n",
__func__, err);
return -EFAULT;
}
rpmbinfor.size = *(unsigned char *)&rpmb_size |
(*((unsigned char *)&rpmb_size+1) << 8);
rpmbinfor.size |= (*((unsigned char *)&rpmb_size+2) << 16) |
(*((unsigned char *)&rpmb_size+3) << 24);
if (rpmbinfor.size <= (RPMB_DATA_BUFF_SIZE-4)) {
MSG(DBG_INFO, "%s, rpmbinfor.size is %d!\n",
__func__, rpmbinfor.size);
err = copy_from_user(rpmb_buffer,
(void *)arg, 4 + rpmbinfor.size);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n",
__func__, err);
return -EFAULT;
}
rpmbinfor.data_frame = (rpmb_buffer + 4);
} else {
MSG(ERR, "%s, rpmbinfor.size(%d+4) is overflow (%d)!\n",
__func__,
rpmbinfor.size, RPMB_DATA_BUFF_SIZE);
return -1;
}
}
#endif
switch (cmd) {
case RPMB_IOCTL_PROGRAM_KEY:
MSG(DBG_INFO,
"%s, cmd = RPMB_IOCTL_PROGRAM_KEY not supported !!!!!!!!!!!!!!\n",
__func__);
break;
case RPMB_IOCTL_READ_DATA:
MSG(DBG_INFO, "%s, cmd = RPMB_IOCTL_READ_DATA!!!!!!!!!!!!!!\n",
__func__);
err = rpmb_req_ioctl_read_data_ufs(&param);
if (err) {
MSG(ERR,
"%s, rpmb_req_ioctl_read_data IO error!!!(%x)\n",
__func__, err);
return err;
}
err = copy_to_user((void *)arg, &param, sizeof(param));
if (err) {
MSG(ERR, "%s, copy to user user failed: %x\n",
__func__, err);
return -EFAULT;
}
break;
case RPMB_IOCTL_WRITE_DATA:
MSG(DBG_INFO, "%s, cmd = RPMB_IOCTL_WRITE_DATA!!!!!!!!!!!!!!\n",
__func__);
err = rpmb_req_ioctl_write_data_ufs(&param);
if (err)
MSG(ERR,
"%s, rpmb_req_ioctl_write_data IO error!!!(%x)\n",
__func__, err);
break;
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
case RPMB_IOCTL_SOTER_WRITE_DATA:
MSG(DBG_INFO, "%s, cmd = RPMB_IOCTL_SOTER_WRITE_DATA\n",
__func__);
err = rpmb_req_write_data_ufs(rpmbinfor.data_frame,
rpmbinfor.size / RPMB_ONE_FRAME_SIZE);
if (err) {
MSG(ERR,
"%s, Microtrust rpmb write request IO error!!!(%x)\n",
__func__, err);
return err;
}
err = copy_to_user((void *)arg,
rpmb_buffer, 4 + rpmbinfor.size);
if (err) {
MSG(ERR, "%s, copy to user user failed: %x\n",
__func__, err);
return -EFAULT;
}
break;
case RPMB_IOCTL_SOTER_READ_DATA:
MSG(DBG_INFO, "%s, cmd = RPMB_IOCTL_SOTER_READ_DATA\n",
__func__);
err = rpmb_req_read_data_ufs(rpmbinfor.data_frame,
rpmbinfor.size / RPMB_ONE_FRAME_SIZE);
if (err) {
MSG(ERR,
"%s, Microtrust rpmb read request IO error!!!(%x)\n",
__func__, err);
return err;
}
err = copy_to_user((void *)arg,
rpmb_buffer, 4 + rpmbinfor.size);
if (err) {
MSG(ERR, "%s, copy to user user failed: %x\n",
__func__, err);
return -EFAULT;
}
break;
case RPMB_IOCTL_SOTER_GET_CNT:
MSG(DBG_INFO, "%s, cmd = RPMB_IOCTL_SOTER_GET_CNT\n", __func__);
err = rpmb_req_get_wc_ufs(NULL, &arg_k, NULL);
if (err) {
MSG(ERR,
"%s, Microtrust get rpmb write counter failed, error code (%x)\n",
__func__, err);
return err;
}
err = copy_to_user((void *)arg, &arg_k, sizeof(u32));
if (err) {
MSG(ERR, "%s, copy_to_user failed: %x\n",
__func__, err);
return -EFAULT;
}
break;
case RPMB_IOCTL_SOTER_GET_WR_SIZE:
MSG(DBG_INFO, "%s, cmd = RPMB_IOCTL_SOTER_GET_WR_SIZE\n",
__func__);
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
if (rawdev_ufs_rpmb) {
arg_k = rpmb_get_rw_size(rawdev_ufs_rpmb);
err = copy_to_user((void *)arg, &arg_k, sizeof(u32));
if (err) {
MSG(ERR, "%s, copy_to_user failed: %x\n",
__func__, err);
return -EFAULT;
}
} else
err = RPMB_ALLOC_ERROR;
break;
#endif
default:
MSG(ERR, "%s, wrong ioctl code (%d)!!!\n", __func__, cmd);
return -ENOTTY;
}
return err;
}
#endif
long rpmb_ioctl_emmc(struct file *file, unsigned int cmd, unsigned long arg)
{
#if defined(RPMB_IOCTL_UT) || defined(CONFIG_MICROTRUST_TEE_SUPPORT)
int err = 0;
#endif
struct mmc_card *card;
int ret = 0;
#if defined(RPMB_IOCTL_UT)
struct rpmb_ioc_param param;
unsigned char *ukey, *udata;
#endif
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
u32 arg_k;
u32 rpmb_size = 0;
struct rpmb_infor rpmbinfor;
unsigned int *arg_p = (unsigned int *)arg;
unsigned int user_arg;
memset(&rpmbinfor, 0, sizeof(struct rpmb_infor));
#endif
#if defined(CONFIG_MMC_MTK_PRO)
if (!mtk_msdc_host[0] || !mtk_msdc_host[0]->mmc
|| !mtk_msdc_host[0]->mmc->card)
return -EFAULT;
card = mtk_msdc_host[0]->mmc->card;
#elif defined(CONFIG_MMC_MTK)
if (!mtk_mmc_host[0] || !mtk_mmc_host[0]->card)
return -EFAULT;
card = mtk_mmc_host[0]->card;
#else
card = NULL;
ret = -EFAULT;
#endif
#if defined(RPMB_IOCTL_UT)
err = copy_from_user(&param, (void *)arg, sizeof(param));
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n", __func__, err);
return -EFAULT;
}
/* limit R/W arguments : less than RPMB area size
* follow block.c: limit transfer size 128K(don't use
* vmalloc for system performance)
*/
if ((param.data_len + param.addr * 256)
> card->ext_csd.raw_rpmb_size_mult * 128 * 1024 ||
param.data_len > RPMB_IOC_MAX_BYTES)
return -EINVAL;
if (!param.key || !param.data)
return -EFAULT;
ukey = param.key;
udata = param.data;
param.key = kmalloc(32, GFP_KERNEL);
/* follow block.c : at least one block(RPMB
* block size is:256) is allocated
*/
if (param.data_len < RPMB_SZ_DATA)
param.data = kmalloc(RPMB_SZ_DATA, GFP_KERNEL);
else
param.data = kmalloc(param.data_len, GFP_KERNEL);
if (param.key) {
err = copy_from_user(param.key, ukey, 32);
if (err != 0) {
MSG(ERR, "%s, err=%x\n", __func__, err);
ret = -1;
goto end;
}
} else {
ret = -1;
goto end;
}
if (param.data) {
err = copy_from_user(param.data, udata, param.data_len);
if (err != 0) {
MSG(ERR, "%s, err=%x\n", __func__, err);
ret = -1;
goto end;
}
} else {
ret = -1;
goto end;
}
#endif
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
if ((cmd == RPMB_IOCTL_SOTER_WRITE_DATA) ||
(cmd == RPMB_IOCTL_SOTER_READ_DATA)) {
if (rpmb_buffer == NULL) {
MSG(ERR, "%s, rpmb_buffer is NULL!\n", __func__);
ret = -1;
goto end;
}
err = copy_from_user(&rpmb_size, (void *)arg, 4);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n",
__func__, err);
ret = -1;
goto end;
}
rpmbinfor.size = *(unsigned char *)&rpmb_size |
(*((unsigned char *)&rpmb_size+1) << 8);
rpmbinfor.size |= (*((unsigned char *)&rpmb_size+2) << 16) |
(*((unsigned char *)&rpmb_size+3) << 24);
if (rpmbinfor.size <= (RPMB_DATA_BUFF_SIZE-4)) {
MSG(INFO, "%s, rpmbinfor.size is %d!\n",
__func__, rpmbinfor.size);
err = copy_from_user(rpmb_buffer,
(void *)arg, 4 + rpmbinfor.size);
if (err) {
MSG(ERR, "%s, copy from user failed: %x\n",
__func__, err);
ret = -1;
goto end;
}
rpmbinfor.data_frame = (rpmb_buffer + 4);
} else {
MSG(ERR, "%s, rpmbinfor.size(%d+4) is overflow (%d)!\n",
__func__, rpmbinfor.size,
RPMB_DATA_BUFF_SIZE);
ret = -1;
goto end;
}
}
#endif
switch (cmd) {
#if defined(RPMB_IOCTL_UT)
case RPMB_IOCTL_PROGRAM_KEY:
MSG(INFO, "%s, cmd = RPMB_IOCTL_PROGRAM_KEY!!!!!!!!!!!!!!\n",
__func__);
ret = emmc_rpmb_req_set_key(card, param.key);
break;
case RPMB_IOCTL_READ_DATA:
MSG(INFO, "%s, cmd = RPMB_IOCTL_READ_DATA!!!!!!!!!!!!!!\n",
__func__);
ret = rpmb_req_ioctl_read_data_emmc(card, &param);
err = copy_to_user(udata, param.data, param.data_len);
if (err) {
MSG(ERR, "%s, err=%x\n", __func__, err);
ret = -1;
goto end;
}
break;
case RPMB_IOCTL_WRITE_DATA:
MSG(INFO, "%s, cmd = RPMB_IOCTL_WRITE_DATA!!!!!!!!!!!!!!\n",
__func__);
ret = rpmb_req_ioctl_write_data_emmc(card, &param);
break;
#endif
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
case RPMB_IOCTL_SOTER_WRITE_DATA:
ret = ut_rpmb_req_write_data(card,
(struct s_rpmb *)(rpmbinfor.data_frame),
rpmbinfor.size/RPMB_ONE_FRAME_SIZE);
if (ret) {
MSG(ERR,
"%s, ISEE rpmb write request IO error!!!(%x)\n",
__func__, ret);
goto end;
}
ret = copy_to_user((void *)arg,
rpmb_buffer, 4 + rpmbinfor.size);
if (ret)
goto end;
break;
case RPMB_IOCTL_SOTER_READ_DATA:
ret = ut_rpmb_req_read_data(card,
(struct s_rpmb *)(rpmbinfor.data_frame),
rpmbinfor.size/RPMB_ONE_FRAME_SIZE);
if (ret) {
MSG(ERR, "%s, ISEE rpmb read request IO error!!!(%x)\n",
__func__, ret);
goto end;
}
ret = copy_to_user((void *)arg,
rpmb_buffer, 4 + rpmbinfor.size);
if (ret)
goto end;
break;
case RPMB_IOCTL_SOTER_GET_CNT:
if (get_user(user_arg, arg_p)) {
ret = -1;
goto end;
}
ret = ut_rpmb_req_get_wc(card, (unsigned int *)&arg_k);
if (ret) {
MSG(ERR, "%s, ISEE rpmb get write counter error (%x)\n",
__func__, ret);
goto end;
}
ret = copy_to_user((void *)arg, &arg_k, sizeof(u32));
if (ret) {
MSG(ERR, "%s, copy_to_user failed: %x\n",
__func__, ret);
goto end;
}
break;
case RPMB_IOCTL_SOTER_GET_WR_SIZE:
if (get_user(user_arg, arg_p)) {
ret = -1;
goto end;
}
ret = ut_rpmb_req_get_max_wr_size(card, (unsigned int *)&arg_k);
if (ret) {
MSG(ERR,
"%s, ISEE rpmb get max write block size error (%x)\n",
__func__, ret);
goto end;
}
ret = copy_to_user((void *)arg, &arg_k, sizeof(u32));
if (ret) {
MSG(ERR, "%s, copy_to_user failed: %x\n",
__func__, ret);
goto end;
}
break;
#endif
default:
MSG(ERR, "%s, wrong ioctl code (%d)!!!\n", __func__, cmd);
ret = -ENOTTY;
goto end;
}
end:
#if defined(RPMB_IOCTL_UT)
kfree(param.data);
kfree(param.key);
#endif
return ret;
}
static int rpmb_close(struct inode *inode, struct file *file)
{
int ret = 0;
MSG(INFO, "%s, !!!!!!!!!!!!\n", __func__);
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
if (rpmb_buffer)
memset(rpmb_buffer, 0x0, RPMB_DATA_BUFF_SIZE);
#endif
return ret;
}
#ifdef CONFIG_SCSI_UFS_MEDIATEK
static const struct file_operations rpmb_fops_ufs = {
.owner = THIS_MODULE,
.open = rpmb_open,
.release = rpmb_close,
.unlocked_ioctl = rpmb_ioctl_ufs,
.write = NULL,
.read = NULL,
};
#endif
static const struct file_operations rpmb_fops_emmc = {
.owner = THIS_MODULE,
.open = rpmb_open,
.release = rpmb_close,
.unlocked_ioctl = rpmb_ioctl_emmc,
.write = NULL,
.read = NULL,
};
#if defined(CONFIG_MMC_MTK_PRO) || defined(CONFIG_MMC_MTK)
struct tag_bootmode {
u32 size;
u32 tag;
u32 bootmode;
u32 boottype;
};
static int dt_get_boot_type(void)
{
struct tag_bootmode *tags = NULL;
struct device_node *node = NULL;
unsigned long size = 0;
int ret = BOOTDEV_UFS;
node = of_find_node_by_path("/chosen");
if (!node)
node = of_find_node_by_path("/chosen@0");
if (node) {
tags = (struct tag_bootmode *)of_get_property(node,
"atag,boot", (int *)&size);
} else
pr_notice("[%s] of_chosen not found\n", __func__);
if (tags) {
ret = tags->boottype;
if ((ret > 2) || (ret < 0))
ret = BOOTDEV_SDMMC;
} else {
pr_notice("[%s] 'atag,boot' is not found\n", __func__);
}
return ret;
}
#endif
#if defined(CONFIG_MMC_MTK)
int mmc_rpmb_register(struct mmc_host *mmc)
{
int ret = 0;
if (!(mmc->caps2 & MMC_CAP2_NO_MMC))
mtk_mmc_host[0] = mmc;
else if (!(mmc->caps2 & MMC_CAP2_NO_SD))
return ret;
else
return -EINVAL;
return ret;
}
EXPORT_SYMBOL_GPL(mmc_rpmb_register);
#endif
#ifdef CONFIG_TEEGRIS_TEE_SUPPORT
#ifdef CONFIG_SCSI_UFS_MEDIATEK
static void rpmb_gp_execute_ufs(u32 cmdId)
{
int ret;
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_READ_DATA\n", __func__);
ret = rpmb_req_read_data_ufs(rpmb_gp_dci->request.frame,
rpmb_gp_dci->request.blks);
break;
case DCI_RPMB_CMD_GET_WCNT:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_GET_WCNT\n", __func__);
ret = rpmb_req_get_wc_ufs(NULL, NULL,
rpmb_gp_dci->request.frame);
break;
case DCI_RPMB_CMD_WRITE_DATA:
MSG(DBG_INFO, "%s: DCI_RPMB_CMD_WRITE_DATA\n", __func__);
ret = rpmb_req_write_data_ufs(rpmb_gp_dci->request.frame,
rpmb_gp_dci->request.blks);
break;
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
case DCI_RPMB_CMD_PROGRAM_KEY:
MSG(INFO, "%s: DCI_RPMB_CMD_PROGRAM_KEY.\n", __func__);
rpmb_dump_frame(rpmb_gp_dci->request.frame);
ret = rpmb_req_program_key_ufs(rpmb_gp_dci->request.frame, 1);
break;
#endif
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, cmdId);
break;
}
if (ret)
MSG(ERR, "%s: Error ret(%d).\n", __func__, ret);
}
#endif
#if defined(CONFIG_MMC_MTK_PRO) || defined(CONFIG_MMC_MTK)
static void rpmb_gp_execute_emmc(u32 cmdId)
{
int ret;
struct mmc_card *card;
struct emmc_rpmb_req rpmb_req;
#if defined(CONFIG_MMC_MTK_PRO)
if (!mtk_msdc_host[0] || !mtk_msdc_host[0]->mmc
|| !mtk_msdc_host[0]->mmc->card) {
MSG(ERR, "%s: ret= %x\n", __func__, -EFAULT);
return;
}
card = mtk_msdc_host[0]->mmc->card;
#elif defined(CONFIG_MMC_MTK)
if (!mtk_mmc_host[0] || !mtk_mmc_host[0]->card) {
MSG(ERR, "%s: ret= %x\n", __func__, -EFAULT);
return;
}
card = mtk_mmc_host[0]->card;
#else
card = NULL;
MSG(ERR, "%s: ret= %x\n", __func__, -EFAULT);
return;
#endif
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_READ_DATA.\n", __func__);
rpmb_req.type = RPMB_READ_DATA;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case DCI_RPMB_CMD_GET_WCNT:
MSG(INFO, "%s: DCI_RPMB_CMD_GET_WCNT.\n", __func__);
rpmb_req.type = RPMB_GET_WRITE_COUNTER;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
case DCI_RPMB_CMD_WRITE_DATA:
MSG(INFO, "%s: DCI_RPMB_CMD_WRITE_DATA.\n", __func__);
rpmb_req.type = RPMB_WRITE_DATA;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
#ifdef CFG_RPMB_KEY_PROGRAMED_IN_KERNEL
case DCI_RPMB_CMD_PROGRAM_KEY:
MSG(INFO, "%s: DCI_RPMB_CMD_PROGRAM_KEY.\n", __func__);
rpmb_dump_frame(rpmb_gp_dci->request.frame);
rpmb_req.type = RPMB_PROGRAM_KEY;
rpmb_req.blk_cnt = rpmb_gp_dci->request.blks;
rpmb_req.addr = rpmb_gp_dci->request.addr;
rpmb_req.data_frame = rpmb_gp_dci->request.frame;
ret = emmc_rpmb_req_handle(card, &rpmb_req);
if (ret)
MSG(ERR, "%s, emmc_rpmb_req_handle failed!!(%x)\n",
__func__, ret);
break;
#endif
default:
MSG(ERR, "%s: receive an unknown command id(%d).\n",
__func__, cmdId);
break;
}
if (ret)
MSG(ERR, "%s: Error ret(%d).\n", __func__, ret);
}
#endif
TEEC_UUID uuid_client = {
.timeLow = 0x00000000,
.timeMid = 0x4D54,
.timeHiAndVersion = 0x4B5F,
.clockSeqAndNode = {0x42, 0x46, 0x72, 0x70, 0x6D, 0x62, 0x74, 0x61},
};
enum cmd_invoke {
CMD_WAITING_NOTIFY,
CMD_DONE_NOTIFY,
CMD_ERROR_NOTIFY,
};
struct TEE_GP_SESSION_DATA {
TEEC_Context context;
TEEC_Session session;
void *wsm_buffer;
};
static struct TEE_GP_SESSION_DATA *rpmb_gp_session;
#define TEEGRIS_OPEN_SESSION_TMO 100
TEEC_Result teegris_rpmb_open_session(TEEC_Context *context,
TEEC_Operation *operation, TEEC_Session *session)
{
TEEC_Result res;
uint32_t returnOrigin;
int cnt = 0;
do {
res = TEEC_OpenSession(context, session, &uuid_client,
0, NULL, operation, &returnOrigin);
if (!res) {
MSG(INFO, "%s:open session success\n", __func__);
break;
}
cnt++;
if (cnt == TEEGRIS_OPEN_SESSION_TMO) {
MSG(ERR, "%s:open session fail,err:0x%x\n",
__func__, res);
break;
}
msleep(1000);
} while (1);
return res;
}
static int check_tee_return(TEEC_Result res)
{
if (res == TEEC_ERROR_TARGET_DEAD) {
#ifdef CONFIG_MTK_ENG_BUILD
BUG();
#endif
return 1;
} else if (res != TEEC_SUCCESS){
return 1;
}
return 0;
}
TEEC_Result teegris_rpmb_run(TEEC_Context *context)
{
TEEC_Result res;
TEEC_Operation operation;
uint32_t returnOrigin;
u32 cmdId;
int boot_type;
memset(&operation, 0, sizeof(TEEC_Operation));
operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT,
TEEC_NONE, TEEC_NONE, TEEC_NONE);
operation.params[0].value.a =
virt_to_phys(rpmb_gp_session->wsm_buffer) & 0xFFFFFFFF;
operation.params[0].value.b =
(virt_to_phys(rpmb_gp_session->wsm_buffer)) >> 32;
res = teegris_rpmb_open_session(context, &operation,
&rpmb_gp_session->session);
if (res)
goto exit;
while (1) {
MSG(ERR, "%s: wait swd notify\n", __func__);
/* wait swd notify */
res = TEEC_InvokeCommand(&rpmb_gp_session->session,
CMD_WAITING_NOTIFY, &operation, &returnOrigin);
if (res != TEEC_SUCCESS)
goto exit;
rpmb_gp_dci =
(struct dciMessage_t *)(rpmb_gp_session->wsm_buffer);
cmdId = rpmb_gp_dci->command.header.commandId;
MSG(ERR, "%s: cmd wait notify done!! cmdId = %x\n",
__func__, cmdId);
boot_type = dt_get_boot_type();
mutex_lock(&rpmb_mutex);
if (boot_type == BOOTDEV_SDMMC)
rpmb_gp_execute_emmc(cmdId);
#ifdef CONFIG_SCSI_UFS_MEDIATEK
else if (boot_type == BOOTDEV_UFS)
rpmb_gp_execute_ufs(cmdId);
#endif
mutex_unlock(&rpmb_mutex);
switch (cmdId) {
case DCI_RPMB_CMD_READ_DATA:
case DCI_RPMB_CMD_GET_WCNT:
case DCI_RPMB_CMD_WRITE_DATA:
case DCI_RPMB_CMD_PROGRAM_KEY:
res = TEEC_InvokeCommand(&rpmb_gp_session->session,
CMD_DONE_NOTIFY,
&operation,
&returnOrigin);
break;
default:
res = TEEC_InvokeCommand(&rpmb_gp_session->session,
CMD_ERROR_NOTIFY,
&operation,
&returnOrigin);
break;
}
if (res != TEEC_SUCCESS)
goto exit;
}
exit:
TEEC_CloseSession(&rpmb_gp_session->session);
return res;
}
#define TEEGRIS_INIT_CONTEXT_TMO 100
#define ALLOCATED_DCI_MSG_SIZE (PAGE_SIZE * 3)
int teegris_rpmb_thread(void *data)
{
int cnt = 0;
int recovery_cnt = 0;
TEEC_Result res = -1;
recovery:
rpmb_gp_session =
kzalloc(sizeof(struct TEE_GP_SESSION_DATA), GFP_KERNEL);
if (!rpmb_gp_session) {
MSG(ERR, "failed to alloc rpmb_gp_session\n");
return -ENOMEM;
}
do {
res = TEEC_InitializeContext(NULL, &rpmb_gp_session->context);
if (!res)
break;
cnt++;
if (cnt == TEEGRIS_INIT_CONTEXT_TMO) {
MSG(ERR, "failed to init context,err:0x%x\n", res);
return res;
}
msleep(500);
} while (1);
rpmb_gp_session->wsm_buffer =
kzalloc(ALLOCATED_DCI_MSG_SIZE, GFP_KERNEL);
if (!rpmb_gp_session->wsm_buffer) {
MSG(ERR, "failed to allocate wsm buffer\n");
return -ENOMEM;
}
res = teegris_rpmb_run(&rpmb_gp_session->context);
if (check_tee_return(res)) {
kfree(rpmb_gp_session->wsm_buffer);
recovery_cnt++;
MSG(ERR, "RPMB recovery cnt %d\n", recovery_cnt);
}
MSG(ERR, "TEEC_FinalizeContex\n", res);
TEEC_FinalizeContext(&rpmb_gp_session->context);
kfree(rpmb_gp_session);
goto recovery;
return (res != TEEC_SUCCESS);
}
#endif
static int __init rpmb_init(void)
{
int alloc_ret = -1;
int cdev_ret = -1;
int major;
dev_t dev;
struct device *device = NULL;
MSG(INFO, "%s start\n", __func__);
alloc_ret = alloc_chrdev_region(&dev, 0, 1, RPMB_NAME);
if (alloc_ret) {
MSG(ERR, "%s, init alloc_chrdev_region failed!\n", __func__);
goto error;
}
major = MAJOR(dev);
#if defined(CONFIG_MMC_MTK_PRO) || defined(CONFIG_MMC_MTK)
if (dt_get_boot_type() == BOOTDEV_SDMMC)
cdev_init(&rpmb_dev, &rpmb_fops_emmc);
else
#endif
#ifdef CONFIG_SCSI_UFS_MEDIATEK
cdev_init(&rpmb_dev, &rpmb_fops_ufs);
#else
return -EFAULT;
#endif
rpmb_dev.owner = THIS_MODULE;
cdev_ret = cdev_add(&rpmb_dev, MKDEV(major, 0), 1);
if (cdev_ret) {
MSG(ERR, "%s, init cdev_add failed!\n", __func__);
goto error;
}
mtk_rpmb_class = class_create(THIS_MODULE, RPMB_NAME);
if (IS_ERR(mtk_rpmb_class)) {
MSG(ERR, "%s, init class_create failed!\n", __func__);
goto error;
}
device = device_create(mtk_rpmb_class, NULL, MKDEV(major, 0), NULL,
RPMB_NAME "%d", 0);
if (IS_ERR(device)) {
MSG(ERR, "%s, init device_create failed!\n", __func__);
goto error;
}
#ifdef CONFIG_TRUSTONIC_TEE_SUPPORT
open_th = kthread_run(rpmb_thread, NULL, "rpmb_open");
if (IS_ERR(open_th))
MSG(ERR, "%s, init kthread_run failed!\n", __func__);
#endif
#ifdef CONFIG_TEEGRIS_TEE_SUPPORT
open_th = kthread_run(teegris_rpmb_thread, NULL, "teegris rpmb");
if (IS_ERR(open_th))
MSG(ERR, "%s, init kthread_run failed!\n", __func__);
iwsock_th = kthread_run(rpmb_iwsock_thread, NULL, "rpmb_iwsock");
if (IS_ERR(iwsock_th))
MSG(ERR, "%s, rpmb iwsock kthread_run failed!\n", __func__);
#endif
#if (defined(CONFIG_MICROTRUST_TEE_SUPPORT))
rpmb_buffer = kzalloc(RPMB_DATA_BUFF_SIZE, 0);
if (rpmb_buffer == NULL) {
MSG(ERR, "%s, rpmb kzalloc memory fail!!!\n", __func__);
return -1;
}
MSG(INFO, "%s, rpmb kzalloc memory done!!!\n", __func__);
#endif
MSG(INFO, "%s end!!!!\n", __func__);
return 0;
error:
if (mtk_rpmb_class)
class_destroy(mtk_rpmb_class);
if (cdev_ret == 0)
cdev_del(&rpmb_dev);
if (alloc_ret == 0)
unregister_chrdev_region(dev, 1);
return -1;
}
late_initcall(rpmb_init);