xref: /openbmc/u-boot/drivers/tee/optee/rpmb.c (revision 232cfd6d9152fd2a4e7113faec51db2a9ab8c6bd)
1  // SPDX-License-Identifier: BSD-2-Clause
2  /*
3   * Copyright (c) 2018 Linaro Limited
4   */
5  
6  #include <common.h>
7  #include <dm.h>
8  #include <log.h>
9  #include <tee.h>
10  #include <mmc.h>
11  
12  #include "optee_msg.h"
13  #include "optee_private.h"
14  
15  /*
16   * Request and response definitions must be in sync with the secure side of
17   * OP-TEE.
18   */
19  
20  /* Request */
21  struct rpmb_req {
22  	u16 cmd;
23  #define RPMB_CMD_DATA_REQ      0x00
24  #define RPMB_CMD_GET_DEV_INFO  0x01
25  	u16 dev_id;
26  	u16 block_count;
27  	/* Optional data frames (rpmb_data_frame) follow */
28  };
29  
30  #define RPMB_REQ_DATA(req) ((void *)((struct rpmb_req *)(req) + 1))
31  
32  /* Response to device info request */
33  struct rpmb_dev_info {
34  	u8 cid[16];
35  	u8 rpmb_size_mult;	/* EXT CSD-slice 168: RPMB Size */
36  	u8 rel_wr_sec_c;	/* EXT CSD-slice 222: Reliable Write Sector */
37  				/*                    Count */
38  	u8 ret_code;
39  #define RPMB_CMD_GET_DEV_INFO_RET_OK     0x00
40  #define RPMB_CMD_GET_DEV_INFO_RET_ERROR  0x01
41  };
42  
release_mmc(struct optee_private * priv)43  static void release_mmc(struct optee_private *priv)
44  {
45  	int rc;
46  
47  	if (!priv->rpmb_mmc)
48  		return;
49  
50  	rc = blk_select_hwpart_devnum(IF_TYPE_MMC, priv->rpmb_dev_id,
51  				      priv->rpmb_original_part);
52  	if (rc)
53  		debug("%s: blk_select_hwpart_devnum() failed: %d\n",
54  		      __func__, rc);
55  
56  	priv->rpmb_mmc = NULL;
57  }
58  
get_mmc(struct optee_private * priv,int dev_id)59  static struct mmc *get_mmc(struct optee_private *priv, int dev_id)
60  {
61  	struct mmc *mmc;
62  	int rc;
63  
64  	if (priv->rpmb_mmc && priv->rpmb_dev_id == dev_id)
65  		return priv->rpmb_mmc;
66  
67  	release_mmc(priv);
68  
69  	mmc = find_mmc_device(dev_id);
70  	if (!mmc) {
71  		debug("Cannot find RPMB device\n");
72  		return NULL;
73  	}
74  	if (!(mmc->version & MMC_VERSION_MMC)) {
75  		debug("Device id %d is not an eMMC device\n", dev_id);
76  		return NULL;
77  	}
78  	if (mmc->version < MMC_VERSION_4_41) {
79  		debug("Device id %d: RPMB not supported before version 4.41\n",
80  		      dev_id);
81  		return NULL;
82  	}
83  
84  	priv->rpmb_original_part = mmc_get_blk_desc(mmc)->hwpart;
85  
86  	rc = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_id, MMC_PART_RPMB);
87  	if (rc) {
88  		debug("Device id %d: cannot select RPMB partition: %d\n",
89  		      dev_id, rc);
90  		return NULL;
91  	}
92  
93  	priv->rpmb_mmc = mmc;
94  	priv->rpmb_dev_id = dev_id;
95  	return mmc;
96  }
97  
rpmb_get_dev_info(u16 dev_id,struct rpmb_dev_info * info)98  static u32 rpmb_get_dev_info(u16 dev_id, struct rpmb_dev_info *info)
99  {
100  	struct mmc *mmc = find_mmc_device(dev_id);
101  
102  	if (!mmc)
103  		return TEE_ERROR_ITEM_NOT_FOUND;
104  
105  	if (!mmc->ext_csd)
106  		return TEE_ERROR_GENERIC;
107  
108  	memcpy(info->cid, mmc->cid, sizeof(info->cid));
109  	info->rel_wr_sec_c = mmc->ext_csd[222];
110  	info->rpmb_size_mult = mmc->ext_csd[168];
111  	info->ret_code = RPMB_CMD_GET_DEV_INFO_RET_OK;
112  
113  	return TEE_SUCCESS;
114  }
115  
rpmb_process_request(struct optee_private * priv,void * req,ulong req_size,void * rsp,ulong rsp_size)116  static u32 rpmb_process_request(struct optee_private *priv, void *req,
117  				ulong req_size, void *rsp, ulong rsp_size)
118  {
119  	struct rpmb_req *sreq = req;
120  	struct mmc *mmc;
121  
122  	if (req_size < sizeof(*sreq))
123  		return TEE_ERROR_BAD_PARAMETERS;
124  
125  	switch (sreq->cmd) {
126  	case RPMB_CMD_DATA_REQ:
127  		mmc = get_mmc(priv, sreq->dev_id);
128  		if (!mmc)
129  			return TEE_ERROR_ITEM_NOT_FOUND;
130  		if (mmc_rpmb_route_frames(mmc, RPMB_REQ_DATA(req),
131  					  req_size - sizeof(struct rpmb_req),
132  					  rsp, rsp_size))
133  			return TEE_ERROR_BAD_PARAMETERS;
134  		return TEE_SUCCESS;
135  
136  	case RPMB_CMD_GET_DEV_INFO:
137  		if (req_size != sizeof(struct rpmb_req) ||
138  		    rsp_size != sizeof(struct rpmb_dev_info)) {
139  			debug("Invalid req/rsp size\n");
140  			return TEE_ERROR_BAD_PARAMETERS;
141  		}
142  		return rpmb_get_dev_info(sreq->dev_id, rsp);
143  
144  	default:
145  		debug("Unsupported RPMB command: %d\n", sreq->cmd);
146  		return TEE_ERROR_BAD_PARAMETERS;
147  	}
148  }
149  
optee_suppl_cmd_rpmb(struct udevice * dev,struct optee_msg_arg * arg)150  void optee_suppl_cmd_rpmb(struct udevice *dev, struct optee_msg_arg *arg)
151  {
152  	struct tee_shm *req_shm;
153  	struct tee_shm *rsp_shm;
154  	void *req_buf;
155  	void *rsp_buf;
156  	ulong req_size;
157  	ulong rsp_size;
158  
159  	if (arg->num_params != 2 ||
160  	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_RMEM_INPUT ||
161  	    arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT) {
162  		arg->ret = TEE_ERROR_BAD_PARAMETERS;
163  		return;
164  	}
165  
166  	req_shm = (struct tee_shm *)(ulong)arg->params[0].u.rmem.shm_ref;
167  	req_buf = (u8 *)req_shm->addr + arg->params[0].u.rmem.offs;
168  	req_size = arg->params[0].u.rmem.size;
169  
170  	rsp_shm = (struct tee_shm *)(ulong)arg->params[1].u.rmem.shm_ref;
171  	rsp_buf = (u8 *)rsp_shm->addr + arg->params[1].u.rmem.offs;
172  	rsp_size = arg->params[1].u.rmem.size;
173  
174  	arg->ret = rpmb_process_request(dev_get_priv(dev), req_buf, req_size,
175  					rsp_buf, rsp_size);
176  }
177  
optee_suppl_rpmb_release(struct udevice * dev)178  void optee_suppl_rpmb_release(struct udevice *dev)
179  {
180  	release_mmc(dev_get_priv(dev));
181  }
182