1 /*
2  * Copyright (C) 2018-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdbool.h>
11 #include <errno.h>
12 
13 #include "acpi.h"
14 #include "vmmapi.h"
15 #include "tpm.h"
16 #include "tpm_internal.h"
17 #include "log.h"
18 #include "mmio_dev.h"
19 #include "dm.h"
20 
21 static int tpm_debug;
22 #define LOG_TAG "tpm: "
23 #define DPRINTF(fmt, args...) \
24 	do { if (tpm_debug) pr_dbg(LOG_TAG "%s:" fmt, __func__, ##args); } while (0)
25 #define WPRINTF(fmt, args...) \
26 	do { pr_err(LOG_TAG "%s:" fmt, __func__, ##args); } while (0)
27 
28 #define STR_MAX_LEN 1024U
29 static char *sock_path = NULL;
30 static uint32_t vtpm_crb_mmio_addr = 0U;
31 struct acpi_dev_pt_ops pt_acpi_dev;
32 
33 #define TPM2_TABLE_SYSFS_PATH	"/sys/firmware/acpi/tables/TPM2"
34 
checksum(uint8_t * buf,size_t size)35 static inline int checksum(uint8_t *buf, size_t size)
36 {
37 	size_t i;
38 	uint8_t sum = 0;
39 	for (i = 0; i < size; i++)
40 		sum += buf[i];
41 	return sum == 0;
42 }
43 
read_sysfs_tpm2_table(struct acpi_table_tpm2 * tpm2_out)44 static int read_sysfs_tpm2_table(struct acpi_table_tpm2 *tpm2_out)
45 {
46 	FILE *fp;
47 	size_t ch_read;
48 	struct acpi_table_tpm2 tpm2 = { 0 };
49 
50 	fp = fopen(TPM2_TABLE_SYSFS_PATH, "r");
51 	if (!fp)
52 		return -errno;
53 
54 	ch_read = fread(&tpm2, 1, sizeof(tpm2), fp);
55 	fclose(fp);
56 
57 	/* we may read less than sizeof(tpm2) as laml and lasa are optional */
58 	if (!ch_read)
59 		return -errno;
60 
61 	if (strncmp(tpm2.header.signature, "TPM2", 4) ||
62 		!checksum((uint8_t *)&tpm2, tpm2.header.length))
63 		return -EINVAL;
64 
65 	memcpy(tpm2_out, &tpm2, ch_read);
66 
67 	return 0;
68 }
69 
is_tpm2_eventlog_supported(struct acpi_table_tpm2 * tpm2)70 static int is_tpm2_eventlog_supported(struct acpi_table_tpm2 *tpm2)
71 {
72 	/* Per TCG ACPI spec ver 1.2 rev 8, if LAML and LASA field are present, length is 76 */
73 	return ((tpm2->header.length == 76) && tpm2->lasa && tpm2->laml);
74 }
75 
is_hid_tpm2_device(char * opts)76 static int is_hid_tpm2_device(char *opts)
77 {
78 	int ret;
79 	struct acpi_dev_pt_ops *ops = &pt_acpi_dev;
80 	uint32_t uid = 0;
81 	char *devopts, *hid, *vtopts;
82 
83 	if (!opts || !*opts)
84 		return false;
85 
86 	devopts = vtopts = strdup(opts);
87 	hid = strsep(&vtopts, ",");
88 	uid = (vtopts != NULL) ? atoi(vtopts) : 0;
89 
90 	ret = get_more_acpi_dev_info(hid, uid, ops);
91 	free(devopts);
92 	if (ret)
93 		return false;
94 	return (strstr(ops->modalias, "MSFT0101") != NULL);
95 }
96 
97 /**
98  * Add TPM2 device with HID hid to tpm2dev to be passed-through.
99  * If eventlog is also supported, it will be added to the second resource of the
100  * tpm2dev->dev.
101  *
102  * @pre: hid should be a valid HID of the TPM2 device being passed-through.
103  * @pre: tpm2dev != NULL
104  */
init_tpm2_pt(char * opts,struct mmio_dev * tpm2dev)105 static int init_tpm2_pt(char *opts, struct mmio_dev *tpm2dev)
106 {
107 	int err = 0;
108 	uint64_t tpm2_buffer_hpa, tpm2_buffer_size;
109 	uint32_t base = 0;
110 	struct acpi_table_tpm2 tpm2 = { 0 };
111 	char *devopts, *vtopts = NULL;
112 
113 	/* TODO: Currently we did not validate if the opts is a valid one.
114 	 * We trust it to be valid as specifying --acpidev_pt is regarded
115 	 * as root user operation.
116 	 */
117 	if (!opts || !*opts) {
118 		return -EINVAL;
119 	}
120 
121 	devopts = strdup(opts);
122 	if (devopts == NULL) {
123 		return -EINVAL;
124 	}
125 	vtopts = strstr(devopts,",");
126 
127 	/* Check whether user set the uid to identify same hid devices for
128 	 * several instances.
129 	 */
130 	if (vtopts != NULL ){
131 		vtopts[0] = ':';
132 	}
133 
134 	/* parse /proc/iomem to find the address and size of tpm buffer */
135 	if (!get_mmio_hpa_resource(devopts, &tpm2_buffer_hpa, &tpm2_buffer_size)) {
136 		free(devopts);
137 		return -ENODEV;
138 	}
139 
140 	free(devopts);
141 
142 	err = read_sysfs_tpm2_table(&tpm2);
143 	if (err)
144 		return err;
145 
146 	if ((tpm2.start_method != 6) && (tpm2.start_method != 7)) {
147 		pr_err("TPM2 start method %d not supported.\n", tpm2.start_method);
148 		return -EINVAL;
149 	}
150 
151 	if ((tpm2.control_address < tpm2_buffer_hpa) ||
152 		(tpm2.control_address > tpm2_buffer_hpa + tpm2_buffer_size)) {
153 		pr_err("TPM2 control area address 0x%016lX outside of the \
154 			requested address region 0x%016lX-0x%016lX\n", tpm2.control_address,
155 			tpm2_buffer_hpa, tpm2_buffer_hpa + tpm2_buffer_size);
156 		return -EINVAL;
157 	}
158 
159 	if ((tpm2.control_address >= MMIO_DEV_BASE) && (tpm2.control_address <= MMIO_DEV_LIMIT)) {
160 		/* we don't support if tpm2 buffer falls in MMIO region */
161 		return -EINVAL;
162 	}
163 
164 	strncpy(tpm2dev->name, "MSFT0101", 8);
165 	strncpy(tpm2dev->dev.name, "tpm2", 4);
166 	tpm2dev->dev.res[0].host_pa = tpm2_buffer_hpa;
167 	tpm2dev->dev.res[0].user_vm_pa = tpm2_buffer_hpa;
168 	tpm2dev->dev.res[0].size = tpm2_buffer_size;
169 
170 	/* Search for eventlog */
171 	if (is_tpm2_eventlog_supported(&tpm2) &&
172 		!mmio_dev_alloc_gpa_resource32(&base, tpm2.laml)) {
173 		tpm2dev->dev.res[1].host_pa = tpm2.lasa;
174 		tpm2dev->dev.res[1].user_vm_pa = base;
175 		tpm2dev->dev.res[1].size = tpm2.laml;
176 	}
177 
178 	pt_tpm2 = true;
179 
180 	return 0;
181 }
182 
get_vtpm_crb_mmio_addr(void)183 uint32_t get_vtpm_crb_mmio_addr(void) {
184 	return vtpm_crb_mmio_addr;
185 }
186 
get_tpm2_mmio_dev()187 static struct acrn_mmiodev *get_tpm2_mmio_dev()
188 {
189 	struct mmio_dev *dev = get_mmiodev("MSFT0101");
190 	return dev ? &dev->dev : NULL;
191 }
192 
get_tpm_crb_mmio_addr(void)193 uint32_t get_tpm_crb_mmio_addr(void)
194 {
195 	uint32_t base;
196 
197 	if (pt_tpm2) {
198 		struct acrn_mmiodev *d = get_tpm2_mmio_dev();
199 		base = d ? (uint32_t)d->res[0].host_pa : 0U;
200 	} else {
201 		base = get_vtpm_crb_mmio_addr();
202 	}
203 
204 	return base;
205 }
206 
get_tpm_crb_mmio_size(void)207 static uint32_t get_tpm_crb_mmio_size(void)
208 {
209 	struct acrn_mmiodev *d = get_tpm2_mmio_dev();
210 	return (pt_tpm2 && d) ? d->res[0].size : TPM_CRB_MMIO_SIZE;
211 }
212 
get_tpm2_table_minimal_log_length(void)213 static uint32_t get_tpm2_table_minimal_log_length(void)
214 {
215 	struct acrn_mmiodev *d = get_tpm2_mmio_dev();
216 	return (pt_tpm2 && d && d->res[1].host_pa) ? d->res[1].size : 0U;
217 }
218 
get_tpm2_table_log_address(void)219 static uint64_t get_tpm2_table_log_address(void)
220 {
221 	struct acrn_mmiodev *d = get_tpm2_mmio_dev();
222 	return (pt_tpm2 && d && d->res[1].host_pa) ? d->res[1].user_vm_pa : 0UL;
223 }
224 
225 enum {
226 	SOCK_PATH_OPT = 0
227 };
228 
229 char *const token[] = {
230 	[SOCK_PATH_OPT] = "sock_path",
231 	NULL
232 };
233 
acrn_parse_vtpm2(char * arg)234 int acrn_parse_vtpm2(char *arg)
235 {
236 	char *value;
237 	size_t len = strnlen(arg, STR_MAX_LEN);
238 
239 	if (len == STR_MAX_LEN)
240 		return -1;
241 
242 	if (SOCK_PATH_OPT == getsubopt(&arg, token, &value)) {
243 		if (value == NULL) {
244 			DPRINTF("Invalid vtpm socket path\n");
245 			return -1;
246 		}
247 		sock_path = calloc(len + 1, 1);
248 		if (!sock_path)
249 			return -1;
250 		strncpy(sock_path, value, len + 1);
251 	}
252 	vtpm2 = true;
253 
254 	return 0;
255 }
256 
init_vtpm2(struct vmctx * ctx)257 void init_vtpm2(struct vmctx *ctx)
258 {
259 	if (!sock_path) {
260 		WPRINTF("Invalid socket path!\n");
261 		return;
262 	}
263 
264 	if (init_tpm_emulator(sock_path) < 0) {
265 		WPRINTF("Failed init tpm emulator!\n");
266 		return;
267 	}
268 
269 	if (mmio_dev_alloc_gpa_resource32(&vtpm_crb_mmio_addr, TPM_CRB_MMIO_SIZE) < 0) {
270 		WPRINTF("Failed allocate gpa resorce!\n");
271 		return;
272 	}
273 
274 	if (init_tpm_crb(ctx) < 0) {
275 		WPRINTF("Failed init tpm emulator!\n");
276 	}
277 }
278 
deinit_vtpm2(struct vmctx * ctx)279 void deinit_vtpm2(struct vmctx *ctx)
280 {
281 	if (ctx->tpm_dev) {
282 		deinit_tpm_crb(ctx);
283 
284 		deinit_tpm_emulator();
285 	}
286 }
287 
tpm_write_dsdt(struct vmctx * ctx)288 static void tpm_write_dsdt(struct vmctx *ctx)
289 {
290 	if (ctx->tpm_dev || pt_tpm2) {
291 		dsdt_line("  Scope (\\_SB)");
292 		dsdt_line("  {");
293 		dsdt_line("    Device (TPM)");
294 		dsdt_line("    {");
295 		dsdt_line("      Name (_HID, \"MSFT0101\" /* TPM 2.0 Security Device */)  // _HID: Hardware ID");
296 		dsdt_line("      Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings");
297 		dsdt_line("      {");
298 		dsdt_indent(4);
299 		dsdt_fixed_mem32(get_tpm_crb_mmio_addr(), get_tpm_crb_mmio_size());
300 		dsdt_unindent(4);
301 		dsdt_line("      })");
302 		dsdt_line("      Method (_STA, 0, NotSerialized)  // _STA: Status");
303 		dsdt_line("      {");
304 		dsdt_line("        Return (0x0F)");
305 		dsdt_line("      }");
306 		dsdt_line("    }");
307 		dsdt_line("  }");
308 	}
309 }
310 
basl_fwrite_tpm2(FILE * fp,struct vmctx * ctx)311 int basl_fwrite_tpm2(FILE *fp, struct vmctx *ctx)
312 {
313 	EFPRINTF(fp, "/*\n");
314 	EFPRINTF(fp, " * dm TPM2 template\n");
315 	EFPRINTF(fp, " */\n");
316 
317 	EFPRINTF(fp, "[0004]\t\tSignature : \"TPM2\"\n");
318 	EFPRINTF(fp, "[0004]\t\tTable Length : 0000004C\n");
319 	EFPRINTF(fp, "[0001]\t\tRevision : 00\n");
320 	EFPRINTF(fp, "[0001]\t\tChecksum : 00\n");
321 	EFPRINTF(fp, "[0006]\t\tOem ID : \"ACRNDM\"\n");
322 	EFPRINTF(fp, "[0008]\t\tOem Table ID : \"DMTPM2  \"\n");
323 	EFPRINTF(fp, "[0004]\t\tOem Revision : 00000000\n");
324 
325 	/* iasl will fill the compiler ID/revision fields */
326 	EFPRINTF(fp, "[0004]\t\tAsl Compiler ID : \"xxxx\"\n");
327 	EFPRINTF(fp, "[0004]\t\tAsl Compiler Revision : 00000000\n");
328 
329 	EFPRINTF(fp, "[0002]\t\tPlatform Class : 0000\n");
330 	EFPRINTF(fp, "[0002]\t\tReserved : 0000\n");
331 	EFPRINTF(fp, "[0008]\t\tControl Address : %016lX\n", get_tpm_crb_mmio_addr() + (long)CRB_REGS_CTRL_REQ);
332 	EFPRINTF(fp, "[0004]\t\tStart Method : 00000007\n");
333 
334 	EFPRINTF(fp, "[0012]\t\tMethod Parameters : 00 00 00 00 00 00 00 00 00 00 00 00\n");
335 	EFPRINTF(fp, "[0004]\t\tMinimum Log Length : %08X\n", get_tpm2_table_minimal_log_length());
336 	EFPRINTF(fp, "[0008]\t\tLog Address : %016lX\n", get_tpm2_table_log_address());
337 
338 	EFFLUSH(fp);
339 
340 	return 0;
341 }
342 
343 struct acpi_dev_pt_ops pt_tpm2_dev_ops = {
344 	.match = is_hid_tpm2_device,
345 	.init = init_tpm2_pt,
346 	.write_dsdt = tpm_write_dsdt,
347 };
348 DEFINE_ACPI_PT_DEV(pt_tpm2_dev_ops);
349