Skip to content

Commit fc2a6a1

Browse files
committed
drivers/tpm/ppi: Add driver to convey PPI request via SMM
Some platforms do not maintain RAM contents after warm reset. They have to rely on non-volatile solutions like SPI flash. Use EFI variables to store the PPI requests coming from OS. They will be handled by EDK2 payload. Upstream-Status: Pending Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
1 parent 24753d2 commit fc2a6a1

19 files changed

Lines changed: 788 additions & 19 deletions

File tree

payloads/external/edk2/Kconfig.dasharo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ config EDK2_USE_UEFIVAR_BACKED_TPM_PPI
403403
bool "Use UEFI variable-backed TPM PPI"
404404
default n
405405
depends on !EDK2_DISABLE_TPM
406+
select TPM_PPI_UEFIVAR_BACKED
406407
help
407408
Tell UEFIPayload to use TPM PPI buffer in UEFI variables. Workaround
408409
for platform-specific issues causing the RAM to not be preserved

src/cpu/x86/smi_trigger.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ static void apmc_log(const char *fn, u8 cmd)
2626
break;
2727
case APM_CNT_SMMINFO:
2828
break;
29+
case APM_CNT_TPM_PPI:
30+
break;
2931
default:
3032
printk(BIOS_DEBUG, "%s: Unknown APMC 0x%02x.\n", fn, cmd);
3133
break;

src/drivers/tpm/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,13 @@ config TPM_PPI
1919
This driver automatically generates ACPI tables for the Physical
2020
Presence Interface defined by the TCG. If not activated only a stub
2121
will be generated without any functionality.
22+
23+
config TPM_PPI_UEFIVAR_BACKED
24+
bool "Use EFI variables to convey TPM PPI request"
25+
depends on TPM_PPI
26+
depends on DRIVERS_EFI_VARIABLE_STORE && SMMSTORE_V2
27+
help
28+
Select this option to use UEFI variables to convey TPM PPI request
29+
information from ACPI to pre-OS environement. Sometimes the request
30+
may not survive warm reboto in CBMEM memory on certain platforms.
31+
That is when this option becomes helpful.

src/drivers/tpm/Makefile.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ramstage-$(CONFIG_TPM_INIT_RAMSTAGE) += tpm.c
66

77
ifeq ($(CONFIG_TPM_PPI),y)
88
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += ppi.c
9+
smm-$(CONFIG_TPM_PPI_UEFIVAR_BACKED) += ppi_smm.c
910
else
1011
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += ppi_stub.c
1112
endif

src/drivers/tpm/ppi.c

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
#include <types.h>
44
#include <acpi/acpigen.h>
55
#include <acpi/acpi_device.h>
6+
#include <cpu/x86/smm.h>
67
#include <cbmem.h>
78
#include <console/console.h>
89
#include <security/tpm/tss.h>
10+
#include <smm_call.h>
911

1012
#include "tpm_ppi.h"
1113

@@ -153,7 +155,14 @@ static void tpm_ppi_func2_cb(void *arg)
153155
acpigen_write_store_op_to_namestr(ZERO_OP, "^OARG");
154156
acpigen_write_store_op_to_namestr(ZERO_OP, "^USER");
155157

156-
acpigen_write_return_integer(PPI2_RET_SUCCESS);
158+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
159+
acpigen_write_store_op_to_namestr(ARG2_OP, "^PPIP");
160+
acpigen_write_store_namestr_to_namestr( "^PPIN", "^SMI");
161+
acpigen_write_return_namestr("^FRET");
162+
} else {
163+
acpigen_write_return_integer(PPI2_RET_SUCCESS);
164+
}
165+
157166
acpigen_pop_len();
158167

159168
acpigen_write_return_integer(PPI2_RET_GENERAL_FAILURE);
@@ -289,6 +298,11 @@ static void tpm_ppi_func5_cb(void *arg)
289298
acpigen_emit_byte(LOCAL1_OP);
290299
set_package_element_op("^TPM3", 0, LOCAL1_OP);
291300

301+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
302+
acpigen_write_store_op_to_namestr(ARG2_OP, "^PPIP");
303+
acpigen_write_store_namestr_to_namestr( "^PPIN", "^SMI");
304+
}
305+
292306
/* ^TPM3 [1] = ^LCMD */
293307
set_package_element_name("^TPM3", 1, "^LCMD");
294308

@@ -345,12 +359,13 @@ static void tpm_ppi_func7_cb(void *arg)
345359
acpigen_emit_byte(LOCAL1_OP);
346360
acpigen_write_if_lequal_op_int(LOCAL1_OP, 3);
347361

348-
/* Enforce use of Revision 1 that doesn't take an optional argument. */
349-
350-
/* Local0 = One */
351-
acpigen_write_store();
352-
acpigen_emit_byte(ONE_OP);
353-
acpigen_emit_byte(LOCAL0_OP);
362+
if (!CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
363+
/* Enforce use of Revision 1 that doesn't take an optional argument. */
364+
/* Local0 = One */
365+
acpigen_write_store();
366+
acpigen_emit_byte(ONE_OP);
367+
acpigen_emit_byte(LOCAL0_OP);
368+
}
354369

355370
acpigen_pop_len();
356371

@@ -365,7 +380,14 @@ static void tpm_ppi_func7_cb(void *arg)
365380
/* ^OARG = Zero */
366381
acpigen_write_store_op_to_namestr(ZERO_OP, "^OARG");
367382

368-
acpigen_write_return_byte(PPI7_RET_SUCCESS);
383+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
384+
acpigen_write_store_op_to_namestr(ARG2_OP, "^PPIP");
385+
acpigen_write_store_namestr_to_namestr( "^PPIN", "^SMI");
386+
acpigen_write_return_namestr("^FRET");
387+
} else {
388+
acpigen_write_return_byte(PPI7_RET_SUCCESS);
389+
}
390+
369391
acpigen_pop_len();
370392

371393
/* Revision 2 */
@@ -379,7 +401,14 @@ static void tpm_ppi_func7_cb(void *arg)
379401
acpigen_emit_byte(LOCAL3_OP);
380402
acpigen_emit_namestring("^OARG");
381403

382-
acpigen_write_return_byte(PPI7_RET_SUCCESS);
404+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
405+
acpigen_write_store_op_to_namestr(ARG2_OP, "^PPIP");
406+
acpigen_write_store_namestr_to_namestr( "^PPIN", "^SMI");
407+
acpigen_write_return_namestr("^FRET");
408+
} else {
409+
acpigen_write_return_byte(PPI7_RET_SUCCESS);
410+
}
411+
383412
acpigen_pop_len();
384413

385414
acpigen_write_return_byte(PPI7_RET_GENERAL_FAILURE);
@@ -430,9 +459,9 @@ static void tpm_ppi_func8_cb(void *arg)
430459
*/
431460
static const u32 tpm1_funcs[] = {
432461
TPM_NOOP,
433-
TPM_SET_NOPPICLEAR_TRUE,
434-
TPM_SET_NOPPIMAINTAINANCE_TRUE,
435-
TPM_SET_NOPPIPROVISION_TRUE,
462+
TPM_SET_NOPPIPROVISION_FALSE,
463+
TPM_SET_NOPPICLEAR_FALSE,
464+
TPM_SET_NOPPIMAINTAINANCE_FALSE,
436465
};
437466
for (size_t i = 0; i < ARRAY_SIZE(tpm1_funcs); i++) {
438467
acpigen_write_if_lequal_op_int(LOCAL2_OP, tpm1_funcs[i]);
@@ -460,7 +489,15 @@ static void tpm_ppi_func8_cb(void *arg)
460489
acpigen_pop_len(); /* Pop : If */
461490
}
462491
}
463-
acpigen_write_return_integer(PPI8_RET_ALLOWED_WITH_PP);
492+
493+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
494+
acpigen_write_store_op_to_namestr(ARG2_OP, "^PPIP");
495+
acpigen_write_store_op_to_namestr(LOCAL2_OP, "^UCRQ");
496+
acpigen_write_store_namestr_to_namestr( "^PPIN", "^SMI");
497+
acpigen_write_return_namestr("^FRET");
498+
} else {
499+
acpigen_write_return_integer(PPI8_RET_ALLOWED_WITH_PP);
500+
}
464501

465502
acpigen_pop_len();
466503

@@ -501,13 +538,18 @@ void tpm_ppi_acpi_fill_ssdt(const struct device *dev)
501538

502539
static const struct fieldlist list[] = {
503540
FIELDLIST_OFFSET(0x100),// FIXME: Add support for func
504-
FIELDLIST_NAMESTR("PPIN", 8),// Not used
505-
FIELDLIST_NAMESTR("PPIP", 32),// Not used
541+
FIELDLIST_NAMESTR("PPIN", 8), // SMI interrupt to use
542+
FIELDLIST_NAMESTR("PPIP", 32),// ACPI function index to pass to SMM code
506543
FIELDLIST_NAMESTR("RESU", 32),// Result of the last operation (TPM error code)
507544
FIELDLIST_NAMESTR("CMDR", 32),// The command requested by OS. 0 for NOP
508545
FIELDLIST_NAMESTR("OARG", 32),// The command optional argument requested by OS
509546
FIELDLIST_NAMESTR("LCMD", 32),// The last command requested by OS.
510-
FIELDLIST_NAMESTR("FRET", 32),// Not used
547+
FIELDLIST_NAMESTR("FRET", 32),// Result code from SMM function
548+
FIELDLIST_NAMESTR("MCIN", 8), // SMI interrupt for Memory Clear Interface
549+
FIELDLIST_NAMESTR("MCIP", 32),// Used for save the Mor parameter
550+
FIELDLIST_NAMESTR("MORD", 32),// Memory Overwrite Request Data
551+
FIELDLIST_NAMESTR("MRET", 32),// Memory Overwrite function return code
552+
FIELDLIST_NAMESTR("UCRQ", 32),// Physical Presence request operation to Get User Confirmation Status
511553
};
512554
static const u8 tpm1_funcs[] = {
513555
TPM_NOOP,
@@ -577,7 +619,8 @@ void tpm_ppi_acpi_fill_ssdt(const struct device *dev)
577619

578620
/* Clear unsupported fields */
579621
ppib->next_step = 0;
580-
ppib->ppin = 1; // Not used by ACPI. Read by EDK-2, must be 1.
622+
/* Read by EDK-2, must be non-zero. */
623+
ppib->ppin = CONFIG(TPM_PPI_UEFIVAR_BACKED) ? APM_CNT_TPM_PPI : 1;
581624
ppib->ppip = 0;
582625
ppib->fret = 0;
583626

@@ -612,6 +655,19 @@ void tpm_ppi_acpi_fill_ssdt(const struct device *dev)
612655
acpigen_write_field(opreg.name, list, ARRAY_SIZE(list),
613656
FIELD_ANYACC | FIELD_NOLOCK | FIELD_PRESERVE);
614657

658+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED)) {
659+
const struct opregion smi_opreg = OPREGION("TSMI", SYSTEMIO,
660+
pm_acpi_smi_cmd_port(),
661+
sizeof(uint16_t));
662+
const struct fieldlist smi_port[] = {
663+
FIELDLIST_NAMESTR("SMI", 16),
664+
};
665+
666+
acpigen_write_opregion(&smi_opreg);
667+
acpigen_write_field(smi_opreg.name, smi_port, ARRAY_SIZE(smi_port),
668+
FIELD_WORDACC | FIELD_NOLOCK | FIELD_PRESERVE);
669+
}
670+
615671
acpigen_write_name("TPM2");
616672
acpigen_write_package(2);
617673
acpigen_write_dword(0);
@@ -732,8 +788,11 @@ void lb_tpm_ppi(struct lb_header *header)
732788
void *ppib;
733789

734790
ppib = cbmem_find(CBMEM_ID_TPM_PPI);
735-
if (!ppib)
791+
if (!ppib) {
792+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED))
793+
call_smm(APM_CNT_TPM_PPI, 0, NULL);
736794
return;
795+
}
737796

738797
family = tlcl_get_family();
739798
if (family == TPM_UNKNOWN) {
@@ -749,4 +808,7 @@ void lb_tpm_ppi(struct lb_header *header)
749808
LB_TPM_VERSION_TPM_VERSION_2;
750809

751810
tpm_ppi->ppi_version = BCD(1, 3);
811+
812+
if (CONFIG(TPM_PPI_UEFIVAR_BACKED))
813+
call_smm(APM_CNT_TPM_PPI, 0, (void *)ppib);
752814
}

0 commit comments

Comments
 (0)