blob: a0c8c4bf5afc0c449049ea1348cd984cea676983 [file] [log] [blame]
Balint Dobszay943c6b52024-11-21 13:52:27 +01001// SPDX-License-Identifier: BSD-3-Clause
2/*
3 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
4 */
5
6#include <stdint.h>
7#include <string.h>
8#include "rpc/tpm_crb_ffa/common/tpm_crb_ffa.h"
9#include "tpm_crb_provider.h"
10#include "trace.h"
11#include "util.h"
12
13#define CRB_DATA_BUF_SIZE (size_t)0x800
14
15/* CRB register definitions based on TCG PC Client Platform TPM Profile Specification for TPM 2.0 */
16
17/* TPM_LOC_STATE_x: Locality State Register */
18#define LOC_STATE_TPM_ESTABLISHED BIT32(0)
19#define LOC_STATE_LOC_ASSIGNED BIT32(1)
20#define LOC_STATE_ACTIVE_LOCALITY_SHIFT UINT32_C(2)
21#define LOC_STATE_ACTIVE_LOCALITY_MASK GENMASK_32(2, 0)
22#define LOC_STATE_TPM_REG_VALID_STATUS BIT32(7)
23
24/* TPM_LOC_CTRL_x: Locality Control Register for Localities 0 - 3 */
25#define LOC_CTRL_REQUEST_ACCESS BIT32(0)
26#define LOC_CTRL_RELINQUISH BIT32(1)
27#define LOC_CTRL_SEIZE BIT32(2)
28#define LOC_CTRL_RESET_ESTABLISHMENT_BIT BIT32(3)
29
30/* TPM_LOC_CTRL_4: Locality Control Register for Locality 4 */
31#define LOC_CTRL_4_HASH_START BIT32(0)
32#define LOC_CTRL_4_HASH_DATA BIT32(1)
33#define LOC_CTRL_4_HASH_END BIT32(2)
34#define LOC_CTRL_4_RESET_ESTABLISHMENT_BIT BIT32(3)
35
36/* TPM_LOC_STS_x: Locality Status Register */
37#define LOC_STS_GRANTED BIT32(0)
38#define LOC_STS_BEEN_SEIZED BIT32(1)
39
40/* TPM_CRB_CTRL_REQ_x: Control Area Request Register */
41#define CRB_CTRL_REQ_CMD_READY BIT32(0)
42#define CRB_CTRL_REQ_GO_IDLE BIT32(1)
43
44/* TPM_CRB_CTRL_STS_x: Control Area Status Register */
45#define CRB_CTRL_STS_TPM_STATUS BIT32(0)
46#define CRB_CTRL_STS_TPM_IDLE BIT32(1)
47
48/* TPM_CRB_CTRL_CANCEL_x: Control Area Status Register */
49#define CRB_CTRL_CANCEL_COMMAND BIT32(0)
50
51/* TPM_CRB_CTRL_START_x: Control Area Status Register */
52#define CRB_CTRL_START_COMMAND BIT32(0)
53
54struct loc_and_crb_ctrl {
55 // Offset 0x00 - 0x03: Used to determine current state of locality of the TPM. This register
56 // is aliased across all localities. Read-only.
57 uint32_t loc_state;
58 // Offset 0x04 - 0x07: Reserved
59 uint8_t _res4[4];
60 // Offset 0x08 - 0x0b: Used to gain control of the TPM by this locality.
61 uint32_t loc_ctrl;
62 // Offset 0x0c - 0x0f: Used to determine whether locality has been granted or Seized.
63 // Read-only. This register SHALL NOT be aliased.
64 uint32_t loc_status;
65 // Offset 0x10 - 0x2f: Reserved
66 uint8_t _res10[32];
67 // Offset 0x30 - 0x37: Used to identify the Interface types supported by the TPM as well as
68 // the Vendor ID, Device ID and Revision ID.
69 uint64_t interface_id;
70 // Offset 0x38 - 0x3f: Optional Register used in low memory environments prior to
71 // CRB_DATA_BUFFER availability. This field is not implemented in hardware TPMs. This field
72 // is only available in Locality 0.
73 uint64_t ctrl_ext;
74 // Offset 0x40 - 0x43: Register used to initiate transactions for the CRB interface. This
75 // register may be aliased across localities.
76 uint32_t ctrl_request;
77 // Offset 0x44 - 0x47: Register used by the TPM to provide status of the CRB interface. This
78 // register may be aliased across localities.
79 uint32_t ctrl_status;
80 // Offset 0x48 - 0x4b: Register used by Software to cancel command processing. This register
81 // may be aliased across localities.
82 uint32_t ctrl_cancel;
83 // Offset 0x4c - 0x4f: Register used to indicate presence of command or response data in the
84 // CRB buffer. This register may be aliased across localities.
85 uint32_t ctrl_start;
86 // Offset 0x50 - 0x53: Register used to configure interrupts. This register may be aliased
87 // across localities.
88 uint32_t ctrl_int_enable;
89 // Offset 0x54 - 0x57: Register used to respond to interrupts. This register may be aliased
90 // across localities.
91 uint32_t ctrl_int_status;
92 // Offset 0x58 - 0x5b: Size of the Command buffer. This register may be aliased across
93 // localities.
94 uint32_t ctrl_cmd_size;
95 // Offset 0x5c - 0x5f: Lower 32bits of the Command buffer start address for the locality.
96 // This register may be aliased across localities.
97 uint32_t ctrl_cmd_addr_lo;
98 // Offset 0x60 - 0x63: Upper 32bits of the Command buffer start address for the locality.
99 // This register may be aliased across localities.
100 uint32_t ctrl_cmd_addr_hi;
101 // Offset 0x64 - 0x67: Size of the Response buffer. Note: If command and response buffers
102 // are implemented as a single buffer, this field SHALL be identical to the value in the
103 // TPM_CRB_CTRL_CMD_SIZE_x buffer. This register may be aliased across localities.
104 uint32_t ctrl_resp_size;
105 // Offset 0x68 - 0x6f: Address of the start of the Response buffer. Note: If command and
106 // response buffers are implemented as a single buffer, this field SHALL contain the same
107 // address contained in TPM_CRB_CTRL_CMD_HADDR_x and TPM_CRB_CMD_LADDR_x. This register may
108 // be aliased across localities.
109 uint64_t ctrl_resp_addr;
110 // Offset 0x70 - 0x7f: Reserved
111 uint8_t _res70[16];
112 // Offset 0x80 - 0x880: Command/Response Data may be defined as large as 3968. This is
113 // implementation-specific. However, the full address space has been reserved. This buffer
114 // may be aliased across localities. This field accepts data transfers from 1B up to the
115 // size indicated by TPM_CRB_INTF_ID_x.CapDataXferSizeSupport (see section 6.4.2.2 CRB
116 // Interface Identifier Register).
117 uint8_t data_buffer[CRB_DATA_BUF_SIZE];
118} __packed __aligned(__alignof(uint32_t));
119
120void set_loc_state_all(struct loc_and_crb_ctrl *loc_ptr[5], uint32_t loc_state)
121{
122 /* The TPM_LOC_STATE_x register is aliased across all localities, set in one step */
123 for (unsigned i = 0; i < 5; i++)
124 loc_ptr[i]->loc_state = loc_state;
125}
126
127/* Service request handlers */
128static rpc_status_t command_handler(void *context, struct rpc_request *req);
129static rpc_status_t locality_req_handler(void *context, struct rpc_request *req);
130
131/* Handler mapping table for service */
132static const struct service_handler handler_table[] = {
133 { TPM_START_QUALIFIER_COMMAND, command_handler },
134 { TPM_START_QUALIFIER_LOCALITY_REQ, locality_req_handler },
135};
136
137static inline uint32_t tpm_get_request_length(uint8_t *buf)
138{
139 if (!buf)
140 return 0;
141
142 return (uint32_t)((buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8 ) + buf[5]);
143}
144
145static rpc_status_t command_handler(void *context, struct rpc_request *req)
146{
147 struct tpm_crb_provider *this_instance = (struct tpm_crb_provider *)context;
148 struct loc_and_crb_ctrl *req_loc = NULL;
149 uint8_t locality = req->client_id;
150 uint8_t *resp_data = NULL;
151 uint8_t *req_data = NULL;
152 size_t resp_max_size = 0;
153 size_t resp_len = 0;
154 size_t req_len = 0;
155 size_t crb_size = 4096; /* TODO: this config should come from the build system */
156
157 DMSG("Processing TPM service command at locality %d", locality);
158
159 /* The locality which made the request */
160 req_loc = this_instance->loc_ptr[locality];
161
162 if (!(req_loc->ctrl_start & CRB_CTRL_START_COMMAND)) {
163 req->service_status = TPM_ERROR_INV_CRB_CTRL_DATA;
164 return RPC_ERROR_INTERNAL;
165 }
166
167 req_len = tpm_get_request_length(req_loc->data_buffer);
168 if (req_len == 0 || crb_size < req_len) {
169 req->service_status = TPM_ERROR_INV_CRB_CTRL_DATA;
170 return RPC_ERROR_INTERNAL;
171 }
172
173 req_data = req_loc->data_buffer;
174 resp_data = req_loc->data_buffer;
175 resp_max_size = crb_size;
176
177 ms_tpm_backend_execute_command(req_data, req_len, &resp_data, &resp_len, resp_max_size);
178
179 /* All operations done, clear the pending request */
180 req_loc->ctrl_start &= ~CRB_CTRL_START_COMMAND;
181 req->service_status = TPM_STATUS_OK;
182
183 return RPC_SUCCESS;
184}
185
186static rpc_status_t locality_req_handler(void *context, struct rpc_request *req)
187{
188 struct tpm_crb_provider *this_instance = (struct tpm_crb_provider *)context;
189 struct loc_and_crb_ctrl *req_loc = NULL;
190 uint8_t locality = req->client_id;
191
192 if (locality == 4) {
193 EMSG("Locality 4 handling is currently not supported");
194 req->service_status = TPM_ERROR_NOTSUP;
195 return RPC_ERROR_INTERNAL;
196 }
197
198 DMSG("Processing TPM service locality request at locality %d", locality);
199
200 /* The locality which made the request */
201 req_loc = this_instance->loc_ptr[locality];
202
203 if (req_loc->loc_ctrl & LOC_CTRL_REQUEST_ACCESS) {
204 uint32_t loc_state = req_loc->loc_state;
205
206 DMSG("Locality access request");
207
208 /* TODO: execute locality arbitration algorithm */
209
210 /* Clear the valid status bit before manipulating register contents */
211 loc_state &= ~LOC_STATE_TPM_REG_VALID_STATUS;
212 set_loc_state_all(this_instance->loc_ptr, loc_state);
213
214 /* Clear current active locality and set the new */
215 loc_state &= ~SHIFT_U32(LOC_STATE_ACTIVE_LOCALITY_MASK,
216 LOC_STATE_ACTIVE_LOCALITY_SHIFT);
217 loc_state |= SHIFT_U32(locality & LOC_STATE_ACTIVE_LOCALITY_MASK,
218 LOC_STATE_ACTIVE_LOCALITY_SHIFT);
219 loc_state |= LOC_STATE_LOC_ASSIGNED;
220 set_loc_state_all(this_instance->loc_ptr, loc_state);
221
222 /* Set the valid status bit */
223 loc_state |= LOC_STATE_TPM_REG_VALID_STATUS;
224 set_loc_state_all(this_instance->loc_ptr, loc_state);
225
226 /* Set the locality status to granted */
227 req_loc->loc_status |= LOC_STS_GRANTED;
228
229 /* All operations done, clear the pending request */
230 req_loc->loc_ctrl &= ~LOC_CTRL_REQUEST_ACCESS;
231 }
232
233 if (req_loc->loc_ctrl & LOC_CTRL_RELINQUISH) {
234 uint32_t loc_state = req_loc->loc_state;
235
236 DMSG("Locality relinquish");
237
238 /* Clear the valid status bit before manipulating register contents */
239 loc_state &= ~LOC_STATE_TPM_REG_VALID_STATUS;
240 set_loc_state_all(this_instance->loc_ptr, loc_state);
241
242 /* Clear current active locality and the locality assigned bit */
243 loc_state &= ~SHIFT_U32(LOC_STATE_ACTIVE_LOCALITY_MASK,
244 LOC_STATE_ACTIVE_LOCALITY_SHIFT);
245 loc_state &= ~LOC_STATE_LOC_ASSIGNED;
246 set_loc_state_all(this_instance->loc_ptr, loc_state);
247
248 /* Set the valid status bit */
249 loc_state |= LOC_STATE_TPM_REG_VALID_STATUS;
250 set_loc_state_all(this_instance->loc_ptr, loc_state);
251
252 /* Clear the locality granted bit */
253 req_loc->loc_status &= ~LOC_STS_GRANTED;
254
255 /* All operations done, clear the pending request */
256 req_loc->loc_ctrl &= ~LOC_CTRL_RELINQUISH;
257 }
258
259 req->service_status = TPM_STATUS_OK;
260
261 return RPC_SUCCESS;
262}
263
264struct rpc_service_interface *tpm_provider_init(struct tpm_crb_provider *context,
265 uint8_t *ns_crb, size_t ns_crb_size,
266 uint8_t* s_crb, size_t s_crb_size)
267{
268 const struct rpc_uuid tpm_crb_service_uuid = {
269 .uuid = TPM_CRB_FFA_UUID
270 };
271
272 if (!context || !ns_crb || ns_crb_size == 0 || !s_crb || s_crb_size == 0)
273 return NULL;
274
275 /* All of the locality and CRB control registers should be cleared an power on */
276 memset(ns_crb, 0, ns_crb_size);
277 memset(s_crb, 0, s_crb_size);
278
279 /* Note: these are the CRB VAs that we got from the SP boot info */
280 context->loc_ptr[0] = (struct loc_and_crb_ctrl *)ns_crb;
281 context->loc_ptr[1] = (struct loc_and_crb_ctrl *)(ns_crb + 0x1000);
282 context->loc_ptr[2] = (struct loc_and_crb_ctrl *)(ns_crb + 0x2000);
283 context->loc_ptr[3] = (struct loc_and_crb_ctrl *)(ns_crb + 0x3000);
284 context->loc_ptr[4] = (struct loc_and_crb_ctrl *)s_crb;
285
286 for (unsigned i = 0; i <= 4; i++) {
287 uint64_t data_buf_addr = 0;
288
289 /* Note: here we have to use the CRB PAs that's fixed at compile time */
290 if (i < 4) {
291 data_buf_addr = TPM_CRB_NS_PA + i * 0x1000 +
292 offsetof(struct loc_and_crb_ctrl, data_buffer);
293 } else {
294 data_buf_addr = TPM_CRB_S_PA +
295 offsetof(struct loc_and_crb_ctrl, data_buffer);
296 }
297
298 context->loc_ptr[i]->ctrl_cmd_addr_lo = data_buf_addr & UINT32_MAX;
299 context->loc_ptr[i]->ctrl_cmd_addr_hi = data_buf_addr >> 32;
300 context->loc_ptr[i]->ctrl_cmd_size = CRB_DATA_BUF_SIZE;
301 context->loc_ptr[i]->ctrl_resp_addr = data_buf_addr;
302 context->loc_ptr[i]->ctrl_resp_size = CRB_DATA_BUF_SIZE;
303 }
304
305 /* Set the valid bit in Locality State Register for all localities */
306 set_loc_state_all(context->loc_ptr, LOC_STATE_TPM_REG_VALID_STATUS);
307
308 service_provider_init(&context->base_provider, context, &tpm_crb_service_uuid,
309 handler_table, ARRAY_SIZE(handler_table));
310
311 return service_provider_get_rpc_interface(&context->base_provider);
312}