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