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