Adds support in optee supplicant to route signed (MACed) RPMB frames from OP-TEE Secure OS to MMC and vice versa to manipulate the RPMB partition. Tested-by: Igor Opaniuk <igor.opaniuk@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org> Reviewed-by: Simon Glass <sjg@chromium.org>lime2-spi
parent
7ab5630a42
commit
232cfd6d91
@ -0,0 +1,181 @@ |
||||
// 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 "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); |
||||
|
||||
if (!mmc) |
||||
return TEE_ERROR_ITEM_NOT_FOUND; |
||||
|
||||
if (!mmc->ext_csd) |
||||
return TEE_ERROR_GENERIC; |
||||
|
||||
memcpy(info->cid, mmc->cid, sizeof(info->cid)); |
||||
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)); |
||||
} |
Loading…
Reference in new issue