mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-18 06:58:54 +00:00
optee: support routing of rpmb data frames to mmc
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>
This commit is contained in:
parent
7ab5630a42
commit
232cfd6d91
5 changed files with 247 additions and 1 deletions
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
obj-y += core.o
|
obj-y += core.o
|
||||||
obj-y += supplicant.o
|
obj-y += supplicant.o
|
||||||
|
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
|
||||||
|
|
|
@ -315,6 +315,13 @@ static u32 do_call_with_arg(struct udevice *dev, struct optee_msg_arg *arg)
|
||||||
param.a3 = res.a3;
|
param.a3 = res.a3;
|
||||||
handle_rpc(dev, ¶m, &page_list);
|
handle_rpc(dev, ¶m, &page_list);
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* In case we've accessed RPMB to serve an RPC
|
||||||
|
* request we need to restore the previously
|
||||||
|
* selected partition as the caller may expect it
|
||||||
|
* to remain unchanged.
|
||||||
|
*/
|
||||||
|
optee_suppl_rpmb_release(dev);
|
||||||
return call_err_to_res(res.a0);
|
return call_err_to_res(res.a0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -651,4 +658,5 @@ U_BOOT_DRIVER(optee) = {
|
||||||
.probe = optee_probe,
|
.probe = optee_probe,
|
||||||
.ops = &optee_ops,
|
.ops = &optee_ops,
|
||||||
.platdata_auto_alloc_size = sizeof(struct optee_pdata),
|
.platdata_auto_alloc_size = sizeof(struct optee_pdata),
|
||||||
|
.priv_auto_alloc_size = sizeof(struct optee_private),
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,60 @@
|
||||||
#ifndef __OPTEE_PRIVATE_H
|
#ifndef __OPTEE_PRIVATE_H
|
||||||
#define __OPTEE_PRIVATE_H
|
#define __OPTEE_PRIVATE_H
|
||||||
|
|
||||||
|
#include <tee.h>
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct optee_private - OP-TEE driver private data
|
||||||
|
* @rpmb_mmc: mmc device for the RPMB partition
|
||||||
|
* @rpmb_dev_id: mmc device id matching @rpmb_mmc
|
||||||
|
* @rpmb_original_part: the previosly active partition on the mmc device,
|
||||||
|
* used to restore active the partition when the RPMB
|
||||||
|
* accesses are finished
|
||||||
|
*/
|
||||||
|
struct optee_private {
|
||||||
|
struct mmc *rpmb_mmc;
|
||||||
|
int rpmb_dev_id;
|
||||||
|
int rpmb_original_part;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct optee_msg_arg;
|
||||||
|
|
||||||
|
void optee_suppl_cmd(struct udevice *dev, struct tee_shm *shm_arg,
|
||||||
|
void **page_list);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUPPORT_EMMC_RPMB
|
||||||
|
/**
|
||||||
|
* optee_suppl_cmd_rpmb() - route RPMB frames to mmc
|
||||||
|
* @dev: device with the selected RPMB partition
|
||||||
|
* @arg: OP-TEE message holding the frames to transmit to the mmc
|
||||||
|
* and space for the response frames.
|
||||||
|
*
|
||||||
|
* Routes signed (MACed) RPMB frames from OP-TEE Secure OS to MMC and vice
|
||||||
|
* versa to manipulate the RPMB partition.
|
||||||
|
*/
|
||||||
|
void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* optee_suppl_rpmb_release() - release mmc device
|
||||||
|
* @dev: mmc device
|
||||||
|
*
|
||||||
|
* Releases the mmc device and restores the previously selected partition.
|
||||||
|
*/
|
||||||
|
void optee_suppl_rpmb_release(struct udevice *dev);
|
||||||
|
#else
|
||||||
|
static inline void optee_suppl_cmd_rpmb(struct udevice *dev,
|
||||||
|
struct optee_msg_arg *arg)
|
||||||
|
{
|
||||||
|
debug("OPTEE_MSG_RPC_CMD_RPMB not implemented\n");
|
||||||
|
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void optee_suppl_rpmb_release(struct udevice *dev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void *optee_alloc_and_init_page_list(void *buf, ulong len, u64 *phys_buf_ptr);
|
void *optee_alloc_and_init_page_list(void *buf, ulong len, u64 *phys_buf_ptr);
|
||||||
void optee_suppl_cmd(struct udevice *dev, void *shm, void **page_list);
|
|
||||||
|
|
||||||
#endif /* __OPTEE_PRIVATE_H */
|
#endif /* __OPTEE_PRIVATE_H */
|
||||||
|
|
181
drivers/tee/optee/rpmb.c
Normal file
181
drivers/tee/optee/rpmb.c
Normal file
|
@ -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));
|
||||||
|
}
|
|
@ -85,6 +85,9 @@ void optee_suppl_cmd(struct udevice *dev, struct tee_shm *shm_arg,
|
||||||
debug("OPTEE_MSG_RPC_CMD_FS not implemented\n");
|
debug("OPTEE_MSG_RPC_CMD_FS not implemented\n");
|
||||||
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
|
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
|
||||||
break;
|
break;
|
||||||
|
case OPTEE_MSG_RPC_CMD_RPMB:
|
||||||
|
optee_suppl_cmd_rpmb(dev, arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
|
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue