blob: 6f12b411bac11b71aa79e6cffb3af2ae71078b7c [file] [log] [blame]
Patrick Rudolph39d69272020-09-21 09:49:31 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <types.h>
Patrick Rudolph39d69272020-09-21 09:49:31 +02004#include <acpi/acpigen.h>
5#include <acpi/acpi_device.h>
6#include <cbmem.h>
7#include <console/console.h>
8
9#include "tpm_ppi.h"
10
11#define BCD(x, y) (((x) << 4) | ((y) << 0))
12
13static void set_package_element_op(const char *package_name, unsigned int element,
14 uint8_t src_op)
15{
16 acpigen_write_store();
17 acpigen_emit_byte(src_op);
18 acpigen_emit_byte(INDEX_OP);
19 acpigen_emit_namestring(package_name);
20 acpigen_write_integer(element);
21 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
22}
23
24static void set_package_element_name(const char *package_name, unsigned int element,
25 const char *src)
26{
27 acpigen_write_store();
28 acpigen_emit_namestring(src);
29 acpigen_emit_byte(INDEX_OP);
30 acpigen_emit_namestring(package_name);
31 acpigen_write_integer(element);
32 acpigen_emit_byte(ZERO_OP); /* Ignore Index() Destination */
33}
34
35/* PPI function is passed in src_op. Converted to Local2. Clobbers Local1 and Local2 */
36static void verify_supported_ppi(uint8_t src_op)
37{
38 /*
39 * Old OSes incorrectly pass a Buffer instead of a Package.
40 * See TCG Physical Presence Interface Specification Chapter 8.1.2 for details.
41 */
42
43 /* If (ObjectType(Arg3) == Package) */
44 acpigen_write_store();
45 acpigen_emit_byte(OBJ_TYPE_OP);
46 acpigen_emit_byte(src_op);
47 acpigen_emit_byte(LOCAL1_OP);
48 acpigen_write_if_lequal_op_int(LOCAL1_OP, 4);
49 acpigen_get_package_op_element(src_op, 0, LOCAL2_OP);
50 acpigen_pop_len();
51
52 /* If (ObjectType(Arg3) == Buffer) */
53 acpigen_write_store();
54 acpigen_emit_byte(OBJ_TYPE_OP);
55 acpigen_emit_byte(src_op);
56 acpigen_emit_byte(LOCAL1_OP);
57 acpigen_write_if_lequal_op_int(LOCAL1_OP, 3);
58 acpigen_write_to_integer(src_op, LOCAL2_OP);
59 acpigen_pop_len();
60
61 /* Check if it's a valid PPI function */
62 acpigen_write_store();
63 acpigen_emit_namestring("^FSUP");
64 acpigen_emit_byte(LOCAL2_OP);
65 acpigen_emit_byte(CONFIG(TPM1) ? ONE_OP : ZERO_OP);
66 acpigen_emit_byte(LOCAL1_OP);
67 acpigen_write_if_lequal_op_int(LOCAL1_OP, 0);
68
69 /*
70 * Note: Must fake success for 1-4, 6-13, 15-16, 19-20
71 * see "Trusted Execution Environment ACPI Profile"
72 *
73 * Even if not available, the TPM 1.2 PPI must be advertised as
74 * supported. Tests showed that Windows relies on it, even when
75 * a TPM2.0 is present!
76 * The functions aren't actually used when a TPM2.0 is present...
77 * Without this the Windows TPM 2.0 stack refuses to work.
78 */
79
80 /*
81 * Check if we have TPM1.2 but a TPM2 PPI function was called
82 * or if we have TPM2.0 but a TPM1.2 PPI function was called.
83 */
84 acpigen_write_store();
85 acpigen_emit_namestring("^FSUP");
86 acpigen_emit_byte(LOCAL2_OP);
87 acpigen_emit_byte(CONFIG(TPM1) ? ZERO_OP : ONE_OP);
88 acpigen_emit_byte(LOCAL1_OP);
89
90 acpigen_write_if_lequal_op_int(LOCAL1_OP, 1);
91 acpigen_write_return_integer(PPI2_RET_SUCCESS); /* As per TPM spec */
92 acpigen_pop_len();
93 acpigen_write_return_integer(PPI2_RET_NOT_SUPPORTED);
94
95 acpigen_pop_len();
96}
97
98/* TPM PPI functions */
99
100static void tpm_ppi_func0_cb(void *arg)
101{
102 /* Functions 1-8. */
103 u8 buf[] = {0xff, 0x01};
104 acpigen_write_return_byte_buffer(buf, 2);
105}
106
107 /*
108 * PPI 1.0: 2.1.1 Get Physical Presence Interface Version
109 *
110 * Arg2 (Integer): Function Index = 1
111 * Arg3 (Package): Arguments = Empty Package
112 *
113 * Returns: Type: String
114 */
115static void tpm_ppi_func1_cb(void *arg)
116{
117 if (CONFIG(TPM2))
118 /* Interface version: 1.3 */
119 acpigen_write_return_string("1.3");
120 else
121 /* Interface version: 1.2 */
122 acpigen_write_return_string("1.2");
123}
124
125/*
126 * Submit TPM Operation Request to Pre-OS Environment [Windows optional]
127 * PPI 1.0: 2.1.3 Submit TPM Operation Request to Pre-OS Environment
128 *
129 * Supported Revisions: 1
130 * Arg1 (Integer): Revision
131 * Arg2 (Integer): Function Index = 2
132 * Arg3 (Package): Arguments = Package: Type: Integer
133 * Operation Value of the Request
134 *
135 * Returns: Type: Integer
136 * 0: Success
137 * 1: Operation Value of the Request Not Supported
138 * 2: General Failure
139 */
140static void tpm_ppi_func2_cb(void *arg)
141{
142 /* Revision 1 */
143 acpigen_write_to_integer(ARG1_OP, LOCAL0_OP);
144 acpigen_write_if_lequal_op_int(LOCAL0_OP, 1);
145
146 /* Local2 = ConvertAndVerify(Arg3) */
147 verify_supported_ppi(ARG3_OP);
148
149 acpigen_write_store_op_to_namestr(LOCAL2_OP, "^CMDR");
150 acpigen_write_store_op_to_namestr(ZERO_OP, "^OARG");
151 acpigen_write_store_op_to_namestr(ZERO_OP, "^USER");
152
153 acpigen_write_return_integer(PPI2_RET_SUCCESS);
154 acpigen_pop_len();
155
156 acpigen_write_return_integer(PPI2_RET_GENERAL_FAILURE);
157}
158
159/*
160 * PPI 1.0: 2.1.4 Get Pending TPM Operation Requested By the OS
161 *
162 * Supported Revisions: 1, 2
163 * Arg1 (Integer): Revision
164 * Arg2 (Integer): Function Index = 3
165 * Arg3 (Package): Empty package
166 *
167 * Returns: Type: Package(Integer, Integer, Integer (optional))
168 * Integer 1:
169 * 0: Success
170 * 1: General Failure
171 * Integer 2:
172 * Pending TPM operation requested by OS
173 * Integer 3:
174 * Pending TPM operation argument requested by OS
175 */
176static void tpm_ppi_func3_cb(void *arg)
177{
178 acpigen_write_store();
179 acpigen_write_integer(PPI3_RET_GENERAL_FAILURE);
180 acpigen_emit_byte(LOCAL0_OP);
181
182 /* ^TPM3 [0] = PPI3_RET_GENERAL_FAILURE */
183 set_package_element_op("^TPM3", 0, LOCAL0_OP);
184
185 /* ^TPM2 [0] = PPI3_RET_GENERAL_FAILURE */
186 set_package_element_op("^TPM2", 0, LOCAL0_OP);
187
188 acpigen_write_to_integer(ARG1_OP, LOCAL0_OP);
189
190 /* Revision 1 */
191 acpigen_write_if_lequal_op_int(LOCAL0_OP, 1);
192
193 /* ^TPM2 [0] = PPI3_RET_SUCCESS */
194 acpigen_write_store();
195 acpigen_write_integer(PPI3_RET_SUCCESS);
196 acpigen_emit_byte(LOCAL1_OP);
197 set_package_element_op("^TPM2", 0, LOCAL1_OP);
198
199 /* ^TPM2 [1] = ^CMDR */
200 set_package_element_name("^TPM2", 1, "^CMDR");
201
202 acpigen_emit_byte(RETURN_OP);
203 acpigen_emit_namestring("^TPM2");
204 acpigen_pop_len();
205
206 /*
207 * A return value of {0, 23, 1} indicates that operation 23
208 * with argument 1 is pending.
209 */
210
211 /* Revision 2 */
212 acpigen_write_if_lequal_op_int(LOCAL0_OP, 2);
213
214 /* ^TPM3 [0] = PPI3_RET_SUCCESS */
215 acpigen_write_store();
216 acpigen_write_integer(PPI3_RET_SUCCESS);
217 acpigen_emit_byte(LOCAL1_OP);
218 set_package_element_op("^TPM3", 0, LOCAL1_OP);
219
220 /* ^TPM3 [1] = ^CMDR */
221 set_package_element_name("^TPM3", 1, "^CMDR");
222
223 /* ^TPM3 [2] = ^OARG */
224 set_package_element_name("^TPM3", 2, "^OARG");
225
226 acpigen_emit_byte(RETURN_OP);
227 acpigen_emit_namestring("^TPM3");
228 acpigen_pop_len();
229
230 acpigen_emit_byte(RETURN_OP);
231 acpigen_emit_namestring("^TPM3");
232}
233
234/*
235 * PPI 1.0: 2.1.5 Get Platform-Specific Action to Transition to Pre-OS Environment
236 *
237 * Arg1 (Integer): Revision
238 * Arg2 (Integer): Function Index = 4
239 * Arg3 (Package): Empty package
240 *
241 * Returns: Type: Integer
242 * 0: None
243 * 1: Shutdown
244 * 2: Reboot
245 * 3: Vendor specific
246 */
247static void tpm_ppi_func4_cb(void *arg)
248{
249 /* Pre-OS transition method: reboot. */
250 acpigen_write_return_byte(PPI4_RET_REBOOT);
251}
252
253/*
254 * PPI 1.0: 2.1.6 Return TPM Operation Response to OS Environment
255 *
256 * Supported Revisions: 1
257 * Arg1 (Integer): Revision
258 * Arg2 (Integer): Function Index = 5
259 * Arg3 (Package): Empty package
260 *
261 * Returns: Type: Package(Integer, Integer, Integer)
262 * Integer 1:
263 * 0: Success
264 * 1: General Failure
265 * Integer 2:
266 * Most recent TPM operation requested by OS
267 * Integer 3:
268 * Response to most recent TPM operation requested by OS
269 */
270static void tpm_ppi_func5_cb(void *arg)
271{
272 /* ^TPM3 [0] = PPI5_RET_GENERAL_FAILURE */
273 acpigen_write_store();
274 acpigen_write_integer(PPI5_RET_GENERAL_FAILURE);
275 acpigen_emit_byte(LOCAL1_OP);
276 set_package_element_op("^TPM3", 0, LOCAL1_OP);
277
278 acpigen_write_to_integer(ARG1_OP, LOCAL0_OP);
279
280 /* Revision 1 */
281 acpigen_write_if_lequal_op_int(LOCAL0_OP, 1);
282
283 /* ^TPM3 [0] = PPI5_RET_SUCCESS */
284 acpigen_write_store();
285 acpigen_write_integer(PPI5_RET_SUCCESS);
286 acpigen_emit_byte(LOCAL1_OP);
287 set_package_element_op("^TPM3", 0, LOCAL1_OP);
288
289 /* ^TPM3 [1] = ^LCMD */
290 set_package_element_name("^TPM3", 1, "^LCMD");
291
292 /* ^TPM3 [2] = ^RESU */
293 set_package_element_name("^TPM3", 2, "^RESU");
294
295 acpigen_pop_len();
296
297 acpigen_emit_byte(RETURN_OP);
298 acpigen_emit_namestring("^TPM3");
299}
300
301/*
302 * PPI 1.2: 2.1.6 Submit preferred user language [Windows optional]
303 *
304 * Arg1 (Integer): Revision
305 * Arg2 (Integer): Function Index = 5
306 * Arg3 (Package): Empty package
307 */
308static void tpm_ppi_func6_cb(void *arg)
309{
310 /*
311 * Set preferred user language: deprecated and must return 3 aka
312 * "not implemented".
313 */
314 acpigen_write_return_byte(PPI6_RET_NOT_IMPLEMENTED);
315}
316
317/*
318 * PPI 1.2: 2.1.7 Submit TPM Operation Request to Pre-OS Environment 2
319 *
320 * Supported Revisions: 1, 2
321 * Arg1 (Integer): Revision
322 * Arg2 (Integer): Function Index = 7
323 * Arg3 (Package): Integer
324 *
325 * Returns: Type: Integer
326 * 0: Success
327 * 1: Not implemented
328 * 2: General Failure
329 * 3: Blocked by current BIOS settings
330 */
331static void tpm_ppi_func7_cb(void *arg)
332{
333 acpigen_write_to_integer(ARG1_OP, LOCAL0_OP);
334
335 /* Local2 = ConvertAndVerify(Arg3) */
336 verify_supported_ppi(ARG3_OP);
337
338 /* If (ObjectType(Arg3) == Buffer) */
339 acpigen_write_store();
340 acpigen_emit_byte(OBJ_TYPE_OP);
341 acpigen_emit_byte(ARG3_OP);
342 acpigen_emit_byte(LOCAL1_OP);
343 acpigen_write_if_lequal_op_int(LOCAL1_OP, 3);
344
345 /* Enforce use of Revision 1 that doesn't take an optional argument. */
346
347 /* Local0 = One */
348 acpigen_write_store();
349 acpigen_emit_byte(ONE_OP);
350 acpigen_emit_byte(LOCAL0_OP);
351
352 acpigen_pop_len();
353
354 // FIXME: Only advertise supported functions
355
356 /* Revision 1 */
357 acpigen_write_if_lequal_op_int(LOCAL0_OP, 1);
358
359 /* ^CMDR = Local2 */
360 acpigen_write_store_op_to_namestr(LOCAL2_OP, "^CMDR");
361
362 /* ^OARG = Zero */
363 acpigen_write_store_op_to_namestr(ZERO_OP, "^OARG");
364
365 acpigen_write_return_byte(PPI7_RET_SUCCESS);
366 acpigen_pop_len();
367
368 /* Revision 2 */
369 acpigen_write_if_lequal_op_int(LOCAL0_OP, 2);
370 /* ^CMDR = Local2 */
371 acpigen_write_store_op_to_namestr(LOCAL2_OP, "^CMDR");
372
373 /* ^OARG = Arg3 [1] */
374 acpigen_get_package_op_element(ARG3_OP, 1, LOCAL3_OP);
375 acpigen_write_store();
376 acpigen_emit_byte(LOCAL3_OP);
377 acpigen_emit_namestring("^OARG");
378
379 acpigen_write_return_byte(PPI7_RET_SUCCESS);
380 acpigen_pop_len();
381
382 acpigen_write_return_byte(PPI7_RET_GENERAL_FAILURE);
383}
384
385/*
386 * PPI 1.2: 2.1.8 Get User Confirmation Status for Operation
387 *
388 * Returns if a command is supported and allowed by firmware
389 * Supported Revisions: 1
390 * Arg1 (Integer): Revision
391 * Arg2 (Integer): Function Index = 7
392 * Arg3 (Package): Integer
393 *
394 * Returns: Type: Integer
395 * 0: Not implemented
396 * 1: BIOS only
397 * 2: Blocked for OS by BIOS settings
398 * 3: Allowed and physical present user required
399 * 4: Allowed and physical present user not required
400 */
401static void tpm_ppi_func8_cb(void *arg)
402{
403 acpigen_write_to_integer(ARG1_OP, LOCAL0_OP);
404
405 /* Revision 1 */
406 acpigen_write_if_lequal_op_int(LOCAL0_OP, 1);
407 acpigen_get_package_op_element(ARG3_OP, 0, LOCAL2_OP);
408
409 /* Check if it's a valid PPI function */
410 acpigen_write_store();
411 acpigen_emit_namestring("^FSUP");
412 acpigen_emit_byte(LOCAL2_OP);
413 acpigen_emit_byte(CONFIG(TPM1) ? ONE_OP : ZERO_OP);
414 acpigen_emit_byte(LOCAL1_OP);
415 acpigen_write_if_lequal_op_int(LOCAL1_OP, 0);
416 acpigen_write_return_byte(0); /* Not implemented */
417 acpigen_pop_len();
418
419 // FIXME: Only advertise supported functions
420
421 if (CONFIG(TPM1)) {
422 /*
423 * Some functions do not require PP depending on configuration.
424 * Those aren't listed here, so the 'required PP' is always set for those.
425 */
426 static const u32 tpm1_funcs[] = {
427 TPM_NOOP,
428 TPM_SET_NOPPICLEAR_TRUE,
429 TPM_SET_NOPPIMAINTAINANCE_TRUE,
430 TPM_SET_NOPPIPROVISION_TRUE,
431 };
432 for (size_t i = 0; i < ARRAY_SIZE(tpm1_funcs); i++) {
433 acpigen_write_if_lequal_op_int(LOCAL2_OP, tpm1_funcs[i]);
434 acpigen_write_return_integer(PPI8_RET_ALLOWED);
435 acpigen_pop_len(); /* Pop : If */
436 }
437 } else if (CONFIG(TPM2)) {
438 /*
439 * Some functions do not require PP depending on configuration.
440 * Those aren't listed here, so the 'required PP' is always set for those.
441 */
442 static const u32 tpm2_funcs[] = {
443 TPM2_NOOP,
444 TPM2_SET_PP_REQUIRED_FOR_CLEAR_TRUE,
445 TPM2_SET_PP_REQUIRED_FOR_CHANGE_PCRS_TRUE,
446 TPM2_SET_PP_REQUIRED_FOR_TURN_ON_TRUE,
447 TPM2_SET_PP_REQUIRED_FOR_CHANGE_EPS_TRUE,
448 TPM2_SET_PP_REQUIRED_FOR_TURN_OFF_TRUE,
449 TPM2_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_TRUE,
450 TPM2_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_TRUE,
451 };
452 for (size_t i = 0; i < ARRAY_SIZE(tpm2_funcs); i++) {
453 acpigen_write_if_lequal_op_int(LOCAL2_OP, tpm2_funcs[i]);
454 acpigen_write_return_integer(PPI8_RET_ALLOWED);
455 acpigen_pop_len(); /* Pop : If */
456 }
457 }
458 acpigen_write_return_integer(PPI8_RET_ALLOWED_WITH_PP);
459
460 acpigen_pop_len();
461
462 acpigen_write_return_integer(PPI8_RET_NOT_IMPLEMENTED);
463}
464
465static void (*tpm_ppi_callbacks[])(void *) = {
466 tpm_ppi_func0_cb,
467 tpm_ppi_func1_cb,
468 tpm_ppi_func2_cb,
469 tpm_ppi_func3_cb,
470 tpm_ppi_func4_cb,
471 tpm_ppi_func5_cb,
472 tpm_ppi_func6_cb,
473 tpm_ppi_func7_cb,
474 tpm_ppi_func8_cb,
475};
476
477static void tpm_mci_func0_cb(void *arg)
478{
479 /* Function 1. */
480 acpigen_write_return_singleton_buffer(0x3);
481}
482static void tpm_mci_func1_cb(void *arg)
483{
484 /* Just return success. */
485 acpigen_write_return_byte(0);
486}
487
488static void (*tpm_mci_callbacks[])(void *) = {
489 tpm_mci_func0_cb,
490 tpm_mci_func1_cb,
491};
492
493void tpm_ppi_acpi_fill_ssdt(const struct device *dev)
494{
495 struct cb_tpm_ppi_payload_handshake *ppib;
496
497 static const struct fieldlist list[] = {
498 FIELDLIST_OFFSET(0x100),// FIXME: Add support for func
499 FIELDLIST_NAMESTR("PPIN", 8),// Not used
500 FIELDLIST_NAMESTR("PPIP", 32),// Not used
501 FIELDLIST_NAMESTR("RESU", 32),// Result of the last operation (TPM error code)
502 FIELDLIST_NAMESTR("CMDR", 32),// The command requested by OS. 0 for NOP
503 FIELDLIST_NAMESTR("OARG", 32),// The command optional argument requested by OS
504 FIELDLIST_NAMESTR("LCMD", 32),// The last command requested by OS.
505 FIELDLIST_NAMESTR("FRET", 32),// Not used
506 };
507 static const u8 tpm1_funcs[] = {
508 TPM_NOOP,
509 TPM_ENABLE,
510 TPM_DISABLE,
511 TPM_ACTIVATE,
512 TPM_DEACTIVATE,
513 TPM_CLEAR,
514 TPM_ENABLE_ACTIVATE,
515 TPM_DEACTIVATE_DISABLE,
516 TPM_SETOWNERINSTALL_TRUE,
517 TPM_SETOWNERINSTALL_FALSE,
518 TPM_ENABLE_ACTIVATE_SETOWNERINSTALL_TRUE,
519 TPM_SETOWNERINSTALL_FALSE_DEACTIVATE_DISABLE,
520 TPM_CLEAR_ENABLE_ACTIVATE,
521 TPM_SET_NOPPIPROVISION_FALSE,
522 TPM_SET_NOPPIPROVISION_TRUE,
523 TPM_ENABLE_ACTIVE_CLEAR,
524 TPM_ENABLE_ACTIVE_CLEAR_ENABLE_ACTIVE,
525 };
526 static const u8 tpm2_funcs[] = {
527 TPM2_NOOP,
528 TPM2_ENABLE,
529 TPM2_DISABLE,
530 TPM2_CLEAR,
531 TPM2_CLEAR_ENABLE_ACTIVE,
532 TPM2_SET_PP_REQUIRED_FOR_CLEAR_TRUE,
533 TPM2_SET_PP_REQUIRED_FOR_CLEAR_FALSE,
534 TPM2_ENABLE_CLEAR,
535 TPM2_ENABLE_CLEAR2,
536 TPM2_SET_PCR_BANKS,
537 TPM2_CHANGE_EPS,
538 TPM2_SET_PP_REQUIRED_FOR_CHANGE_PCRS_FALSE,
539 TPM2_SET_PP_REQUIRED_FOR_CHANGE_PCRS_TRUE,
540 TPM2_SET_PP_REQUIRED_FOR_TURN_ON_FALSE,
541 TPM2_SET_PP_REQUIRED_FOR_TURN_ON_TRUE,
542 TPM2_SET_PP_REQUIRED_FOR_TURN_OFF_FALSE,
543 TPM2_SET_PP_REQUIRED_FOR_TURN_OFF_TRUE,
544 TPM2_SET_PP_REQUIRED_FOR_CHANGE_EPS_FALSE,
545 TPM2_SET_PP_REQUIRED_FOR_CHANGE_EPS_TRUE,
546 TPM2_LOG_ALL_DIGEST,
547 TPM2_DISABLE_ENDORSMENT_ENABLE_STORAGE_HISTORY,
548 TPM2_ENABLE_BLOCK_SID,
549 TPM2_DISABLE_BLOCK_SID,
550 TPM2_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_TRUE,
551 TPM2_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FALSE,
552 TPM2_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_TRUE,
553 TPM2_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FALSE,
554 };
555
556 /*
557 * On hot reset/ACPI S3 the contents are preserved.
558 */
559 ppib = (void *)cbmem_add(CBMEM_ID_TPM_PPI, sizeof(*ppib));
560 if (!ppib) {
561 printk(BIOS_ERR, "PPI: Failed to add CBMEM\n");
562 return;
563 }
564 printk(BIOS_DEBUG, "PPI: Pending OS request: 0x%x (0x%x)\n", ppib->pprq, ppib->pprm);
565 printk(BIOS_DEBUG, "PPI: OS response: CMD 0x%x = 0x%x\n", ppib->lppr, ppib->pprp);
566
567 /* Clear unsupported fields */
568 ppib->next_step = 0;
569 ppib->ppin = 1; // Not used by ACPI. Read by EDK-2, must be 1.
570 ppib->ppip = 0;
571 ppib->fret = 0;
572 ppib->next_step = 0;
573
574 bool found = false;
575 /* Fill in defaults, the TPM command executor may overwrite this list */
576 memset(ppib->func, 0, sizeof(ppib->func));
577 if (CONFIG(TPM1)) {
578 for (size_t i = 0; i < ARRAY_SIZE(tpm1_funcs); i++) {
579 ppib->func[tpm1_funcs[i]] = 1;
580 if (ppib->pprq == tpm1_funcs[i])
581 found = true;
582 }
583 } else {
Patrick Rudolph39d69272020-09-21 09:49:31 +0200584 for (size_t i = 0; i < ARRAY_SIZE(tpm2_funcs); i++) {
585 ppib->func[tpm2_funcs[i]] = 1;
586 if (ppib->pprq == tpm2_funcs[i])
587 found = true;
588 }
589 }
590 if (!found) {
591 // Set sane defaults
592 ppib->pprq = 0;
593 ppib->pprm = 0;
594 ppib->pprp = 0;
595 }
596
597 /* Physical Presence OpRegion */
598 struct opregion opreg = OPREGION("PPOP", SYSTEMMEMORY, (uintptr_t)ppib,
599 sizeof(*ppib));
600
601 acpigen_write_opregion(&opreg);
602 acpigen_write_field(opreg.name, list, ARRAY_SIZE(list),
603 FIELD_ANYACC | FIELD_NOLOCK | FIELD_PRESERVE);
604
605 acpigen_write_name("TPM2");
606 acpigen_write_package(2);
607 acpigen_write_dword(0);
608 acpigen_write_dword(0);
609 acpigen_pop_len(); /* Package */
610
611 acpigen_write_name("TPM3");
612 acpigen_write_package(3);
613 acpigen_write_dword(0);
614 acpigen_write_dword(0);
615 acpigen_write_dword(0);
616 acpigen_pop_len(); /* Package */
617
618 /*
619 * Returns One if the firmware implements this function.
620 *
621 * Arg0: Integer PPI function
622 */
623 acpigen_write_method_serialized("FUNC", 1);
624
625 acpigen_write_to_integer(ARG0_OP, LOCAL0_OP);
626 acpigen_write_to_integer(ARG1_OP, LOCAL1_OP);
627 acpigen_write_if();
628 acpigen_emit_byte(LGREATER_OP);
629 acpigen_emit_byte(LOCAL0_OP);
630 acpigen_write_integer(VENDOR_SPECIFIC_OFFSET);
631 acpigen_write_return_integer(0);
632 acpigen_pop_len(); /* If */
633
634 /* TPPF = CreateField("PPOP", Local0) */
635 acpigen_emit_byte(CREATE_BYTE_OP);
636 acpigen_emit_namestring("PPOP");
637 acpigen_emit_byte(LOCAL0_OP);
638 acpigen_emit_namestring("TPPF");
639
640 /* Local0 = ToInteger("TPPF") */
641 acpigen_emit_byte(TO_INTEGER_OP);
642 acpigen_emit_namestring("TPPF");
643 acpigen_emit_byte(LOCAL0_OP);
644
645 acpigen_write_return_op(LOCAL0_OP);
646 acpigen_pop_len(); /* Method */
647
648 /*
649 * Returns One if the PPI spec supports this functions.
Martin Roth3e25f852023-09-04 15:37:07 -0600650 * That doesn't necessarily mean that the firmware implements it, or the
Patrick Rudolph39d69272020-09-21 09:49:31 +0200651 * TPM can execute the function.
652 *
653 * Arg0: Integer PPI function
654 * Arg1: Integer TPMversion (0: TPM2, 1: TPM1.2)
655 */
656 acpigen_write_method("FSUP", 2);
657
658 acpigen_write_to_integer(ARG0_OP, LOCAL0_OP);
659 acpigen_write_to_integer(ARG1_OP, LOCAL1_OP);
660 acpigen_write_if();
661 acpigen_emit_byte(LGREATER_OP);
662 acpigen_emit_byte(LOCAL0_OP);
663 acpigen_write_integer(VENDOR_SPECIFIC_OFFSET);
664 acpigen_write_return_integer(0);
665 acpigen_pop_len(); /* If */
666
667 acpigen_write_if_lequal_op_int(LOCAL1_OP, 1);
668 for (size_t i = 0; i < ARRAY_SIZE(tpm1_funcs); i++) {
669 acpigen_write_if_lequal_op_int(LOCAL0_OP, tpm1_funcs[i]);
670 acpigen_write_return_integer(1);
671 acpigen_pop_len(); /* Pop : If */
672 }
673 acpigen_pop_len(); /* If */
674
675 acpigen_write_if_lequal_op_int(LOCAL1_OP, 0);
676
677 for (size_t i = 0; i < ARRAY_SIZE(tpm2_funcs); i++) {
678 acpigen_write_if_lequal_op_int(LOCAL0_OP, tpm2_funcs[i]);
679 acpigen_write_return_integer(1);
680 acpigen_pop_len(); /* Pop : If */
681 }
682 acpigen_pop_len(); /* If */
683
684 acpigen_write_return_integer(0);
685 acpigen_pop_len(); /* Method */
686
687 /*
688 * _DSM method
689 */
690 struct dsm_uuid ids[] = {
691 /* Physical presence interface.
692 * This is used to submit commands like "Clear TPM" to
693 * be run at next reboot provided that user confirms
694 * them.
695 */
696 DSM_UUID(TPM_PPI_UUID, &tpm_ppi_callbacks[0],
697 ARRAY_SIZE(tpm_ppi_callbacks), NULL),
698 /* Memory clearing on boot: just a dummy. */
699 DSM_UUID(TPM_MCI_UUID, &tpm_mci_callbacks[0],
700 ARRAY_SIZE(tpm_mci_callbacks), NULL),
701 };
702
703 acpigen_write_dsm_uuid_arr(ids, ARRAY_SIZE(ids));
704}
705
706void lb_tpm_ppi(struct lb_header *header)
707{
708 struct lb_tpm_physical_presence *tpm_ppi;
709 void *ppib;
710
711 ppib = cbmem_find(CBMEM_ID_TPM_PPI);
712 if (!ppib)
713 return;
714
715 tpm_ppi = (struct lb_tpm_physical_presence *)lb_new_record(header);
716 tpm_ppi->tag = LB_TAG_TPM_PPI_HANDOFF;
717 tpm_ppi->size = sizeof(*tpm_ppi);
718 tpm_ppi->ppi_address = (uintptr_t)ppib;
719 tpm_ppi->tpm_version = CONFIG(TPM1) ? LB_TPM_VERSION_TPM_VERSION_1_2 :
720 LB_TPM_VERSION_TPM_VERSION_2;
721
722 tpm_ppi->ppi_version = BCD(1, 3);
723}