The following 2 patches add support for the TPM's physial presence interface (PPI). The patches require the recently posted QEMU patch for support of PPI:
http://lists.nongnu.org/archive/html/qemu-devel/2018-01/msg01884.html
We assume a device at 0xffff 0000 - 0xffff 00ff where the OS can write a code into that SeaBIOS needs to find and act upon after a reboot.
I have previously tried to use a memory location allocated within the ACPI stream but that causes problems for finding the location after reboot since the ACPI is completely rewritten and all memory it covers erased, thus leaving no trace of the code the OS wrote into the memory. Per Kevin's suggestion we are now using a device at that well known address.
The patches are functional with Linux. One missing part is that the result code from the last TPM operation should be put into the shared memory block so that the user can see the code. However, currently the TPM error code from the responses are not passed back from the function calls, so in case of failure I am simply returning 0x0badc0de.
Stefan
Stefan Berger (2): tcgbios: Add physical presence interface support tcgbios: extend physical presence interface with more functions
src/post.c | 4 ++ src/std/tcg.h | 25 +++++++++++++ src/tcgbios.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 3 ++ 4 files changed, 145 insertions(+), 2 deletions(-)
Add support for TPM 1.2 and TPM 2 physical presence interface (PPI). A shared memory structure is located at 0xffff 0000 - 0xffff 00ff that SeaBIOS initializes unless it has already been intialized and then searches for a code it is supposed to act upon. A code typically requires that one or more TPM commands are being sent.
The underlying spec can be accessed from this page here:
https://trustedcomputinggroup.org/tcg-physical-presence-interface-specificat...
Version 1.20 is implemented.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/post.c | 4 ++++ src/std/tcg.h | 18 ++++++++++++++++++ src/tcgbios.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tcgbios.h | 3 +++ 4 files changed, 86 insertions(+)
diff --git a/src/post.c b/src/post.c index f93106a..f451013 100644 --- a/src/post.c +++ b/src/post.c @@ -201,6 +201,7 @@ maininit(void)
// Setup platform devices. platform_hardware_setup(); + tpm_ppi_init();
// Start hardware initialization (if threads allowed during optionroms) if (threads_during_optionroms()) @@ -220,6 +221,9 @@ maininit(void) // Run option roms optionrom_setup();
+ // Process user-requested TPM state change + tpm_ppi_process(); + // Allow user to modify overall boot order. interactive_bootmenu(); wait_threads(); diff --git a/src/std/tcg.h b/src/std/tcg.h index 09a92d8..0aeafe8 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -551,4 +551,22 @@ struct pcctes_romex #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
+#define TPM_PPI_ADDR_BASE 0xffff0000 + +struct tpm_ppi { + u8 ppin; // 1 = initialized + u32 ppip; // not used + u32 pprp; // response from TPM; set by BIOS + u32 pprq; // opcode; set by ACPI + u32 pprm; // parameter for opcode; set by ACPI + u32 lppr; // last opcode; set by BIOS + u32 fret; // not used + u8 res1; // reserved + u32 res[4]; // reserved + u32 fail; // set by BIOS (0 = success) +} PACKED; + +void tpm_ppi_init(void); +void tpm_ppi_process(void); + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index 40b3028..2adca71 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1774,6 +1774,18 @@ tpm20_process_cfg(tpm_ppi_code msgCode, int verbose) }
static int +tpm_process_cfg(tpm_ppi_code msgCode, int verbose) +{ + switch (TPM_version) { + case TPM_VERSION_1_2: + return tpm12_process_cfg(msgCode, verbose); + case TPM_VERSION_2: + return tpm20_process_cfg(msgCode, verbose); + } + return -1; +} + +static int tpm12_get_tpm_state(void) { int state = 0; @@ -2012,3 +2024,52 @@ tpm_can_show_menu(void) } return 0; } + +static struct tpm_ppi *tp; +static u8 next_step; /* next opcode to execute after reboot */ + +void +tpm_ppi_init(void) +{ + tp = (struct tpm_ppi *)TPM_PPI_ADDR_BASE; + + dprintf(DEBUG_tcg, "TCGBIOS: TPM PPI struct at %p\n", tp); + + if (!tp->ppin) { + tp->ppin = 1; + tp->pprq = 0; + tp->lppr = 0; + tp->fail = 0; + } +} + +void +tpm_ppi_process(void) +{ + tpm_ppi_code op; + + if (tp) { + op = tp->pprq; + if (!op) { + /* intermediate step after a reboot? */ + op = next_step; + } else { + /* last full opcode */ + tp->lppr = op; + } + if (op) { + /* + * Reset the opcode so we don't permanently reboot upon + * code 3 (Activate). + */ + tp->pprq = 0; + + printf("Processing TPM PPI opcode %d\n", op); + tp->fail = (tpm_process_cfg(op, 0) != 0); + if (tp->fail) + tp->pprp = 0x0badc0de; + else + tp->pprp = 0; + } + } +} diff --git a/src/tcgbios.h b/src/tcgbios.h index 32fb941..52b86f2 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -16,4 +16,7 @@ void tpm_option_rom(const void *addr, u32 len); int tpm_can_show_menu(void); void tpm_menu(void);
+void tpm_ppi_init(void); +void tpm_ppi_process(void); + #endif /* TCGBIOS_H */
Implement more functions of the physical presence interface. Some of the added functions will automatically reboot the machine. Thus we need to save the next step after the reboot in an additional variable.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/std/tcg.h | 7 +++++++ src/tcgbios.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/src/std/tcg.h b/src/std/tcg.h index 0aeafe8..459cbd4 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -548,8 +548,15 @@ struct pcctes_romex #define TPM_PPI_OP_ACTIVATE 3 #define TPM_PPI_OP_DEACTIVATE 4 #define TPM_PPI_OP_CLEAR 5 +#define TPM_PPI_OP_ENABLE_ACTIVATE 6 +#define TPM_PPI_OP_DEACTIVATE_DISABLE 7 #define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 #define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9 +#define TPM_PPI_OP_ENABLE_ACTIVATE_SET_OWNERINSTALL_TRUE 10 +#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE_DEACTIVATE_DISABLE 11 +#define TPM_PPI_OP_CLEAR_ENABLE_ACTIVATE 14 +#define TPM_PPI_OP_ENABLE_ACTIVATE_CLEAR 21 +#define TPM_PPI_OP_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE 22
#define TPM_PPI_ADDR_BASE 0xffff0000
diff --git a/src/tcgbios.c b/src/tcgbios.c index 2adca71..d45716a 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1646,7 +1646,7 @@ tpm12_set_owner_install(int allow, int verbose) }
static int -tpm12_process_cfg(tpm_ppi_code msgCode, int verbose) +tpm12_process_cfg(tpm_ppi_code msgCode, int verbose, u8 *next_step) { int ret = 0;
@@ -1674,6 +1674,18 @@ tpm12_process_cfg(tpm_ppi_code msgCode, int verbose) ret = tpm12_force_clear(1, 0, verbose); break;
+ case TPM_PPI_OP_ENABLE_ACTIVATE: + ret = tpm12_enable_tpm(1, verbose); + if (!ret) + ret = tpm12_activate_tpm(1, 1, verbose); + break; + + case TPM_PPI_OP_DEACTIVATE_DISABLE: + ret = tpm12_activate_tpm(0, 1, verbose); + if (!ret) + ret = tpm12_enable_tpm(0, verbose); + break; + case TPM_PPI_OP_SET_OWNERINSTALL_TRUE: ret = tpm12_set_owner_install(1, verbose); break; @@ -1682,6 +1694,43 @@ tpm12_process_cfg(tpm_ppi_code msgCode, int verbose) ret = tpm12_set_owner_install(0, verbose); break;
+ case TPM_PPI_OP_ENABLE_ACTIVATE_SET_OWNERINSTALL_TRUE: + *next_step = TPM_PPI_OP_SET_OWNERINSTALL_TRUE; + ret = tpm12_enable_activate(1, verbose); + if (!ret) + ret = tpm12_set_owner_install(1, verbose); + break; + + case TPM_PPI_OP_SET_OWNERINSTALL_FALSE_DEACTIVATE_DISABLE: + ret = tpm12_set_owner_install(0, verbose); + if (!ret) + ret = tpm12_activate_tpm(0, 0, verbose); + if (!ret) + ret = tpm12_enable_tpm(0, verbose); + break; + + case TPM_PPI_OP_CLEAR_ENABLE_ACTIVATE: + ret = tpm12_force_clear(0, 1, verbose); + break; + + case TPM_PPI_OP_ENABLE_ACTIVATE_CLEAR: + *next_step = TPM_PPI_OP_CLEAR; + ret = tpm12_enable_activate(1, verbose); + /* no reboot happened */ + if (!ret) + ret = tpm12_force_clear(0, 0, verbose); + break; + + case TPM_PPI_OP_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + *next_step = TPM_PPI_OP_CLEAR_ENABLE_ACTIVATE; + ret = tpm12_enable_activate(1, verbose); + /* no reboot happened */ + if (!ret) { + *next_step = TPM_PPI_OP_NONE; + ret = tpm12_force_clear(0, 1, verbose); + } + break; + default: break; } @@ -1774,11 +1823,11 @@ tpm20_process_cfg(tpm_ppi_code msgCode, int verbose) }
static int -tpm_process_cfg(tpm_ppi_code msgCode, int verbose) +tpm_process_cfg(tpm_ppi_code msgCode, int verbose, u8 *next_step) { switch (TPM_version) { case TPM_VERSION_1_2: - return tpm12_process_cfg(msgCode, verbose); + return tpm12_process_cfg(msgCode, verbose, next_step); case TPM_VERSION_2: return tpm20_process_cfg(msgCode, verbose); } @@ -1950,7 +1999,8 @@ tpm12_menu(void) break;
if (next_scancodes[i] == scancode) { - tpm12_process_cfg(msgCode, 1); + u8 ignore; + tpm12_process_cfg(msgCode, 1, &ignore); waitkey = 0; break; } @@ -2026,7 +2076,7 @@ tpm_can_show_menu(void) }
static struct tpm_ppi *tp; -static u8 next_step; /* next opcode to execute after reboot */ +static u8 next_step = TPM_PPI_OP_NONE; /* opcode to execute after reboot */
void tpm_ppi_init(void) @@ -2065,7 +2115,7 @@ tpm_ppi_process(void) tp->pprq = 0;
printf("Processing TPM PPI opcode %d\n", op); - tp->fail = (tpm_process_cfg(op, 0) != 0); + tp->fail = (tpm_process_cfg(op, 0, &next_step) != 0); if (tp->fail) tp->pprp = 0x0badc0de; else