123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- // SPDX-License-Identifier: BSD-2-Clause
- /*
- * Copyright (c) 2018 Linaro Limited
- */
- #include <common.h>
- #include <dm.h>
- #include <log.h>
- #include <tee.h>
- #include <mmc.h>
- #include <dm/device_compat.h>
- #include "optee_msg.h"
- #include "optee_private.h"
- /*
- * Request and response definitions must be in sync with the secure side of
- * OP-TEE.
- */
- /* Request */
- struct rpmb_req {
- u16 cmd;
- #define RPMB_CMD_DATA_REQ 0x00
- #define RPMB_CMD_GET_DEV_INFO 0x01
- u16 dev_id;
- u16 block_count;
- /* Optional data frames (rpmb_data_frame) follow */
- };
- #define RPMB_REQ_DATA(req) ((void *)((struct rpmb_req *)(req) + 1))
- /* Response to device info request */
- struct rpmb_dev_info {
- u8 cid[16];
- u8 rpmb_size_mult; /* EXT CSD-slice 168: RPMB Size */
- u8 rel_wr_sec_c; /* EXT CSD-slice 222: Reliable Write Sector */
- /* Count */
- u8 ret_code;
- #define RPMB_CMD_GET_DEV_INFO_RET_OK 0x00
- #define RPMB_CMD_GET_DEV_INFO_RET_ERROR 0x01
- };
- static void release_mmc(struct optee_private *priv)
- {
- int rc;
- if (!priv->rpmb_mmc)
- return;
- rc = blk_select_hwpart_devnum(IF_TYPE_MMC, priv->rpmb_dev_id,
- priv->rpmb_original_part);
- if (rc)
- debug("%s: blk_select_hwpart_devnum() failed: %d\n",
- __func__, rc);
- priv->rpmb_mmc = NULL;
- }
- static struct mmc *get_mmc(struct optee_private *priv, int dev_id)
- {
- struct mmc *mmc;
- int rc;
- if (priv->rpmb_mmc && priv->rpmb_dev_id == dev_id)
- return priv->rpmb_mmc;
- release_mmc(priv);
- mmc = find_mmc_device(dev_id);
- if (!mmc) {
- debug("Cannot find RPMB device\n");
- return NULL;
- }
- if (!(mmc->version & MMC_VERSION_MMC)) {
- debug("Device id %d is not an eMMC device\n", dev_id);
- return NULL;
- }
- if (mmc->version < MMC_VERSION_4_41) {
- debug("Device id %d: RPMB not supported before version 4.41\n",
- dev_id);
- return NULL;
- }
- priv->rpmb_original_part = mmc_get_blk_desc(mmc)->hwpart;
- rc = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_id, MMC_PART_RPMB);
- if (rc) {
- debug("Device id %d: cannot select RPMB partition: %d\n",
- dev_id, rc);
- return NULL;
- }
- priv->rpmb_mmc = mmc;
- priv->rpmb_dev_id = dev_id;
- return mmc;
- }
- static u32 rpmb_get_dev_info(u16 dev_id, struct rpmb_dev_info *info)
- {
- struct mmc *mmc = find_mmc_device(dev_id);
- int i;
- if (!mmc)
- return TEE_ERROR_ITEM_NOT_FOUND;
- if (!mmc->ext_csd)
- return TEE_ERROR_GENERIC;
- for (i = 0; i < ARRAY_SIZE(mmc->cid); i++)
- ((u32 *) info->cid)[i] = cpu_to_be32(mmc->cid[i]);
- info->rel_wr_sec_c = mmc->ext_csd[222];
- info->rpmb_size_mult = mmc->ext_csd[168];
- info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK;
- return TEE_SUCCESS;
- }
- static u32 rpmb_process_request(struct optee_private *priv, void *req,
- ulong req_size, void *rsp, ulong rsp_size)
- {
- struct rpmb_req *sreq = req;
- struct mmc *mmc;
- if (req_size < sizeof(*sreq))
- return TEE_ERROR_BAD_PARAMETERS;
- switch (sreq->cmd) {
- case RPMB_CMD_DATA_REQ:
- mmc = get_mmc(priv, sreq->dev_id);
- if (!mmc)
- return TEE_ERROR_ITEM_NOT_FOUND;
- if (mmc_rpmb_route_frames(mmc, RPMB_REQ_DATA(req),
- req_size - sizeof(struct rpmb_req),
- rsp, rsp_size))
- return TEE_ERROR_BAD_PARAMETERS;
- return TEE_SUCCESS;
- case RPMB_CMD_GET_DEV_INFO:
- if (req_size != sizeof(struct rpmb_req) ||
- rsp_size != sizeof(struct rpmb_dev_info)) {
- debug("Invalid req/rsp size\n");
- return TEE_ERROR_BAD_PARAMETERS;
- }
- return rpmb_get_dev_info(sreq->dev_id, rsp);
- default:
- debug("Unsupported RPMB command: %d\n", sreq->cmd);
- return TEE_ERROR_BAD_PARAMETERS;
- }
- }
- void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg)
- {
- struct tee_shm *req_shm;
- struct tee_shm *rsp_shm;
- void *req_buf;
- void *rsp_buf;
- ulong req_size;
- ulong rsp_size;
- if (arg->num_params != 2 ||
- arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
- arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) {
- arg->ret = TEE_ERROR_BAD_PARAMETERS;
- return;
- }
- req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref;
- req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs;
- req_size = arg->params[0].u.rmem.size;
- rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref;
- rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs;
- rsp_size = arg->params[1].u.rmem.size;
- arg->ret = rpmb_process_request(dev_get_priv(dev), req_buf, req_size,
- rsp_buf, rsp_size);
- }
- void optee_suppl_rpmb_release(struct udevice *dev)
- {
- release_mmc(dev_get_priv(dev));
- }
|