blob: 7350e1c4d525dfefb895eeedb26cfea402249707 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassed3f5a32013-11-10 10:27:05 -07002/*
3 * Copyright (c) 2013 Google, Inc
Simon Glassed3f5a32013-11-10 10:27:05 -07004 */
5
6#include <common.h>
Simon Glass4e4bf942022-07-31 12:28:48 -06007#include <display_options.h>
Simon Glass21baf152015-08-22 18:31:35 -06008#include <dm.h>
Miquel Raynald677bfe2018-05-15 11:57:06 +02009#include <tpm-v1.h>
Simon Glassed3f5a32013-11-10 10:27:05 -070010#include <asm/state.h>
11#include <asm/unaligned.h>
Simon Glassc3a4d1c2019-11-14 12:57:14 -070012#include <u-boot/crc.h>
Simon Glass974c98f2021-07-18 14:17:57 -060013#include "sandbox_common.h"
Simon Glassed3f5a32013-11-10 10:27:05 -070014
15#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
16
Simon Glassed3f5a32013-11-10 10:27:05 -070017/*
18 * Information about our TPM emulation. This is preserved in the sandbox
19 * state file if enabled.
20 */
21static struct tpm_state {
Simon Glassef8a2502018-10-01 11:55:18 -060022 bool valid;
23 struct nvdata_state nvdata[NV_SEQ_COUNT];
Simon Glass1db235a2021-07-18 14:17:58 -060024} s_state, *g_state;
Simon Glassed3f5a32013-11-10 10:27:05 -070025
26/**
27 * sandbox_tpm_read_state() - read the sandbox EC state from the state file
28 *
29 * If data is available, then blob and node will provide access to it. If
30 * not this function sets up an empty TPM.
31 *
32 * @blob: Pointer to device tree blob, or NULL if no data to read
33 * @node: Node offset to read from
34 */
35static int sandbox_tpm_read_state(const void *blob, int node)
36{
Simon Glass1db235a2021-07-18 14:17:58 -060037 struct tpm_state *state = &s_state;
Simon Glassed3f5a32013-11-10 10:27:05 -070038 const char *prop;
39 int len;
40 int i;
41
42 if (!blob)
43 return 0;
44
45 for (i = 0; i < NV_SEQ_COUNT; i++) {
Simon Glass1db235a2021-07-18 14:17:58 -060046 struct nvdata_state *nvd = &state->nvdata[i];
Simon Glassed3f5a32013-11-10 10:27:05 -070047 char prop_name[20];
48
49 sprintf(prop_name, "nvdata%d", i);
50 prop = fdt_getprop(blob, node, prop_name, &len);
Simon Glass1db235a2021-07-18 14:17:58 -060051 if (len >= NV_DATA_SIZE)
52 return log_msg_ret("nvd", -E2BIG);
53 if (prop) {
54 memcpy(nvd->data, prop, len);
55 nvd->length = len;
56 nvd->present = true;
Simon Glassef8a2502018-10-01 11:55:18 -060057 }
Simon Glassed3f5a32013-11-10 10:27:05 -070058 }
Simon Glass1db235a2021-07-18 14:17:58 -060059
60 s_state.valid = true;
Simon Glassed3f5a32013-11-10 10:27:05 -070061
62 return 0;
63}
64
65/**
Simon Glass1db235a2021-07-18 14:17:58 -060066 * sandbox_tpm_write_state() - Write out our state to the state file
Simon Glassed3f5a32013-11-10 10:27:05 -070067 *
68 * The caller will ensure that there is a node ready for the state. The node
69 * may already contain the old state, in which case it is overridden.
70 *
71 * @blob: Device tree blob holding state
72 * @node: Node to write our state into
73 */
74static int sandbox_tpm_write_state(void *blob, int node)
75{
Simon Glass1db235a2021-07-18 14:17:58 -060076 const struct tpm_state *state = g_state;
Simon Glassed3f5a32013-11-10 10:27:05 -070077 int i;
78
Simon Glass1db235a2021-07-18 14:17:58 -060079 if (!state)
80 return 0;
81
Simon Glassed3f5a32013-11-10 10:27:05 -070082 /*
83 * We are guaranteed enough space to write basic properties.
84 * We could use fdt_add_subnode() to put each set of data in its
85 * own node - perhaps useful if we add access informaiton to each.
86 */
87 for (i = 0; i < NV_SEQ_COUNT; i++) {
Simon Glass1db235a2021-07-18 14:17:58 -060088 const struct nvdata_state *nvd = &state->nvdata[i];
Simon Glassed3f5a32013-11-10 10:27:05 -070089 char prop_name[20];
90
Simon Glass1db235a2021-07-18 14:17:58 -060091 if (nvd->present) {
92 snprintf(prop_name, sizeof(prop_name), "nvdata%d", i);
93 fdt_setprop(blob, node, prop_name, nvd->data,
94 nvd->length);
Simon Glassef8a2502018-10-01 11:55:18 -060095 }
Simon Glassed3f5a32013-11-10 10:27:05 -070096 }
97
98 return 0;
99}
100
101SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
102 sandbox_tpm_write_state);
103
Simon Glassef8a2502018-10-01 11:55:18 -0600104static void handle_cap_flag_space(u8 **datap, uint index)
105{
106 struct tpm_nv_data_public pub;
107
108 /* TPM_NV_PER_PPWRITE */
109 memset(&pub, '\0', sizeof(pub));
110 pub.nv_index = __cpu_to_be32(index);
111 pub.pcr_info_read.pcr_selection.size_of_select = __cpu_to_be16(
112 sizeof(pub.pcr_info_read.pcr_selection.pcr_select));
113 pub.permission.attributes = __cpu_to_be32(1);
114 pub.pcr_info_write = pub.pcr_info_read;
115 memcpy(*datap, &pub, sizeof(pub));
116 *datap += sizeof(pub);
117}
118
Simon Glass21baf152015-08-22 18:31:35 -0600119static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
120 size_t send_size, uint8_t *recvbuf,
121 size_t *recv_len)
Simon Glassed3f5a32013-11-10 10:27:05 -0700122{
Simon Glass21baf152015-08-22 18:31:35 -0600123 struct tpm_state *tpm = dev_get_priv(dev);
Simon Glassed3f5a32013-11-10 10:27:05 -0700124 uint32_t code, index, length, type;
125 uint8_t *data;
126 int seq;
127
128 code = get_unaligned_be32(sendbuf + sizeof(uint16_t) +
129 sizeof(uint32_t));
Simon Glass04488c42018-11-06 15:21:23 -0700130#ifdef DEBUG
Simon Glassed3f5a32013-11-10 10:27:05 -0700131 printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
132 *recv_len, code);
133 print_buffer(0, sendbuf, 1, send_size, 0);
Simon Glass04488c42018-11-06 15:21:23 -0700134#endif
Simon Glassed3f5a32013-11-10 10:27:05 -0700135 switch (code) {
Simon Glass998af312018-10-01 11:55:17 -0600136 case TPM_CMD_GET_CAPABILITY:
Simon Glassed3f5a32013-11-10 10:27:05 -0700137 type = get_unaligned_be32(sendbuf + 14);
138 switch (type) {
Simon Glass998af312018-10-01 11:55:17 -0600139 case TPM_CAP_FLAG:
Simon Glassed3f5a32013-11-10 10:27:05 -0700140 index = get_unaligned_be32(sendbuf + 18);
141 printf("Get flags index %#02x\n", index);
142 *recv_len = 22;
143 memset(recvbuf, '\0', *recv_len);
Simon Glass7f350a92021-07-18 14:18:00 -0600144 data = recvbuf + TPM_HDR_LEN + sizeof(uint32_t);
Simon Glassed3f5a32013-11-10 10:27:05 -0700145 switch (index) {
146 case FIRMWARE_NV_INDEX:
147 break;
148 case KERNEL_NV_INDEX:
Simon Glassef8a2502018-10-01 11:55:18 -0600149 handle_cap_flag_space(&data, index);
Simon Glass7f350a92021-07-18 14:18:00 -0600150 *recv_len = data - recvbuf;
Simon Glassef8a2502018-10-01 11:55:18 -0600151 break;
152 case TPM_CAP_FLAG_PERMANENT: {
153 struct tpm_permanent_flags *pflags;
154
155 pflags = (struct tpm_permanent_flags *)data;
156 memset(pflags, '\0', sizeof(*pflags));
157 put_unaligned_be32(TPM_TAG_PERMANENT_FLAGS,
158 &pflags->tag);
159 *recv_len = TPM_HEADER_SIZE + 4 +
160 sizeof(*pflags);
Simon Glassed3f5a32013-11-10 10:27:05 -0700161 break;
162 }
Simon Glassef8a2502018-10-01 11:55:18 -0600163 default:
164 printf(" ** Unknown flags index %x\n", index);
165 return -ENOSYS;
166 }
Simon Glass7f350a92021-07-18 14:18:00 -0600167 put_unaligned_be32(*recv_len, recvbuf + TPM_HDR_LEN);
Simon Glassed3f5a32013-11-10 10:27:05 -0700168 break;
Simon Glass998af312018-10-01 11:55:17 -0600169 case TPM_CAP_NV_INDEX:
Simon Glassed3f5a32013-11-10 10:27:05 -0700170 index = get_unaligned_be32(sendbuf + 18);
171 printf("Get cap nv index %#02x\n", index);
Simon Glass7f350a92021-07-18 14:18:00 -0600172 put_unaligned_be32(22, recvbuf + TPM_HDR_LEN);
Simon Glassed3f5a32013-11-10 10:27:05 -0700173 break;
174 default:
175 printf(" ** Unknown 0x65 command type %#02x\n",
176 type);
Simon Glass998af312018-10-01 11:55:17 -0600177 return -ENOSYS;
Simon Glassed3f5a32013-11-10 10:27:05 -0700178 }
179 break;
Simon Glass998af312018-10-01 11:55:17 -0600180 case TPM_CMD_NV_WRITE_VALUE:
Simon Glassed3f5a32013-11-10 10:27:05 -0700181 index = get_unaligned_be32(sendbuf + 10);
182 length = get_unaligned_be32(sendbuf + 18);
Simon Glass974c98f2021-07-18 14:17:57 -0600183 seq = sb_tpm_index_to_seq(index);
Simon Glassed3f5a32013-11-10 10:27:05 -0700184 if (seq < 0)
Simon Glass998af312018-10-01 11:55:17 -0600185 return -EINVAL;
Simon Glassed3f5a32013-11-10 10:27:05 -0700186 printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
Simon Glass974c98f2021-07-18 14:17:57 -0600187 sb_tpm_write_data(tpm->nvdata, seq, sendbuf, 22, length);
Simon Glassed3f5a32013-11-10 10:27:05 -0700188 break;
Simon Glass998af312018-10-01 11:55:17 -0600189 case TPM_CMD_NV_READ_VALUE: /* nvread */
Simon Glassed3f5a32013-11-10 10:27:05 -0700190 index = get_unaligned_be32(sendbuf + 10);
191 length = get_unaligned_be32(sendbuf + 18);
Simon Glass974c98f2021-07-18 14:17:57 -0600192 seq = sb_tpm_index_to_seq(index);
Simon Glassed3f5a32013-11-10 10:27:05 -0700193 if (seq < 0)
Simon Glass998af312018-10-01 11:55:17 -0600194 return -EINVAL;
Simon Glassef8a2502018-10-01 11:55:18 -0600195 printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
196 length, seq);
Simon Glass974c98f2021-07-18 14:17:57 -0600197 *recv_len = TPM_HDR_LEN + sizeof(uint32_t) + length;
Simon Glassed3f5a32013-11-10 10:27:05 -0700198 memset(recvbuf, '\0', *recv_len);
Simon Glass974c98f2021-07-18 14:17:57 -0600199 put_unaligned_be32(length, recvbuf + TPM_HDR_LEN);
200 sb_tpm_read_data(tpm->nvdata, seq, recvbuf, TPM_HDR_LEN + 4,
201 length);
Simon Glassed3f5a32013-11-10 10:27:05 -0700202 break;
Simon Glassef8a2502018-10-01 11:55:18 -0600203 case TPM_CMD_EXTEND:
204 *recv_len = 30;
205 memset(recvbuf, '\0', *recv_len);
206 break;
207 case TPM_CMD_NV_DEFINE_SPACE:
Simon Glassf9143c12021-07-18 14:17:59 -0600208 index = get_unaligned_be32(sendbuf + 12);
209 length = get_unaligned_be32(sendbuf + 77);
210 seq = sb_tpm_index_to_seq(index);
211 if (seq < 0)
212 return -EINVAL;
213 printf("tpm: define_space index=%#02x, len=%#02x, seq=%#02x\n",
214 index, length, seq);
215 sb_tpm_define_data(tpm->nvdata, seq, length);
216 *recv_len = 12;
217 memset(recvbuf, '\0', *recv_len);
218 break;
Simon Glassed3f5a32013-11-10 10:27:05 -0700219 case 0x15: /* pcr read */
220 case 0x5d: /* force clear */
221 case 0x6f: /* physical enable */
222 case 0x72: /* physical set deactivated */
223 case 0x99: /* startup */
Simon Glassef8a2502018-10-01 11:55:18 -0600224 case 0x50: /* self test full */
Simon Glassed3f5a32013-11-10 10:27:05 -0700225 case 0x4000000a: /* assert physical presence */
226 *recv_len = 12;
227 memset(recvbuf, '\0', *recv_len);
228 break;
229 default:
230 printf("Unknown tpm command %02x\n", code);
Simon Glass998af312018-10-01 11:55:17 -0600231 return -ENOSYS;
Simon Glassed3f5a32013-11-10 10:27:05 -0700232 }
Simon Glass04488c42018-11-06 15:21:23 -0700233#ifdef DEBUG
234 printf("tpm: rx recv_len %zd\n", *recv_len);
235 print_buffer(0, recvbuf, 1, *recv_len, 0);
236#endif
Simon Glassed3f5a32013-11-10 10:27:05 -0700237
238 return 0;
239}
240
Simon Glass21baf152015-08-22 18:31:35 -0600241static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
Simon Glassed3f5a32013-11-10 10:27:05 -0700242{
Simon Glass21baf152015-08-22 18:31:35 -0600243 if (size < 15)
244 return -ENOSPC;
245
246 return snprintf(buf, size, "sandbox TPM");
247}
248
249static int sandbox_tpm_probe(struct udevice *dev)
250{
251 struct tpm_state *tpm = dev_get_priv(dev);
252
Simon Glass1db235a2021-07-18 14:17:58 -0600253 if (s_state.valid)
254 memcpy(tpm, &s_state, sizeof(*tpm));
255 g_state = tpm;
Simon Glass21baf152015-08-22 18:31:35 -0600256
Simon Glassed3f5a32013-11-10 10:27:05 -0700257 return 0;
258}
259
Simon Glass21baf152015-08-22 18:31:35 -0600260static int sandbox_tpm_open(struct udevice *dev)
Simon Glassed3f5a32013-11-10 10:27:05 -0700261{
Simon Glassed3f5a32013-11-10 10:27:05 -0700262 return 0;
263}
264
Simon Glass21baf152015-08-22 18:31:35 -0600265static int sandbox_tpm_close(struct udevice *dev)
Simon Glassed3f5a32013-11-10 10:27:05 -0700266{
Simon Glassed3f5a32013-11-10 10:27:05 -0700267 return 0;
268}
Simon Glass21baf152015-08-22 18:31:35 -0600269
270static const struct tpm_ops sandbox_tpm_ops = {
271 .open = sandbox_tpm_open,
272 .close = sandbox_tpm_close,
273 .get_desc = sandbox_tpm_get_desc,
274 .xfer = sandbox_tpm_xfer,
275};
276
277static const struct udevice_id sandbox_tpm_ids[] = {
278 { .compatible = "google,sandbox-tpm" },
279 { }
280};
281
Walter Lozanoe3e24702020-06-25 01:10:04 -0300282U_BOOT_DRIVER(google_sandbox_tpm) = {
283 .name = "google_sandbox_tpm",
Simon Glass21baf152015-08-22 18:31:35 -0600284 .id = UCLASS_TPM,
285 .of_match = sandbox_tpm_ids,
286 .ops = &sandbox_tpm_ops,
287 .probe = sandbox_tpm_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700288 .priv_auto = sizeof(struct tpm_state),
Simon Glass21baf152015-08-22 18:31:35 -0600289};