This patch provides an addtional menu entry that enables the user to control certain aspects of the TPM's state.
If a working TPM has been detected, the boot menu will look like this:
Select boot device:
1. ata0-1: QEMU HARDDISK ATA-7 Hard-Disk (6144 MiBytes) 2. Legacy option rom 3. iPXE (PCI 00:03.0)
t. TPM Menu
Upon pressing t the TPM menu will be shown:
1. Enable TPM 2. Disable TPM 3. Activate TPM 4. Deactivate TPM 5. Clear ownership 6. Allow installation of owner 7. Prevent installation of owner Escape for previous menu. TPM is enabled, active, does not have an owner but one can be installed.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com
--- src/boot.c | 14 ++++++- src/tcgbios.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 2 + src/util.h | 1 + 4 files changed, 129 insertions(+), 3 deletions(-)
diff --git a/src/boot.c b/src/boot.c index ec59c37..bb3bddf 100644 --- a/src/boot.c +++ b/src/boot.c @@ -427,7 +427,7 @@ get_raw_keystroke(void) }
// Read a keystroke - waiting up to 'msec' milliseconds. -static int +int get_keystroke(int msec) { u32 end = irqtimer_calc(msec); @@ -461,7 +461,7 @@ interactive_bootmenu(void)
char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL); int menukey = romfile_loadint("etc/boot-menu-key", 1); - printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n"); + printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n"); free(bootmsg);
u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT); @@ -474,6 +474,7 @@ interactive_bootmenu(void) while (get_keystroke(0) >= 0) ;
+show_boot_menu: printf("Select boot device:\n\n"); wait_threads();
@@ -486,6 +487,9 @@ interactive_bootmenu(void) printf("%d. %s\n", maxmenu , strtcpy(desc, pos->description, ARRAY_SIZE(desc))); } + if (tpm_is_detected()) { + printf("\nt. TPM menu\n"); + }
// Get key press. If the menu key is ESC, do not restart boot unless // 1.5 seconds have passed. Otherwise users (trained by years of @@ -496,6 +500,12 @@ interactive_bootmenu(void) scan_code = get_keystroke(1000); if (scan_code == 1 && !irqtimer_check(esc_accepted_time)) continue; + if (tpm_is_detected() && scan_code == 20 /* t */) { + printf("\n"); + tpm_menu(); + printf("\n"); + goto show_boot_menu; + } if (scan_code >= 1 && scan_code <= maxmenu+1) break; } diff --git a/src/tcgbios.c b/src/tcgbios.c index 3263ec6..24edb44 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -26,6 +26,7 @@ #include "fw/paravirt.h" // runningOnXen #include "std/smbios.h" #include "malloc.h" // malloc_* +#include "stacks.h" // wait_threads
static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR }; static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE }; @@ -142,6 +143,17 @@ probe_tpm(void) } }
+int +tpm_is_detected(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + probe_tpm(); + + return tpm_state.tpm_found; +} + static int has_working_tpm(void) { @@ -1569,7 +1581,8 @@ assert_physical_presence(int verbose) "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n", returnCode);
- if (rc || returnCode) { + /* some TPMs do not support phys. presence enablement */ + if (rc || (returnCode && returnCode != TPM_BAD_PARAMETER)) { if (verbose) printf("Error: Could not enable physical presence.\n\n"); goto err_exit; @@ -2066,3 +2079,103 @@ tpm_ppi_process(void) } } } + + +static void +show_tpm_state(void) +{ + struct tpm_permanent_flags pf; + u8 has_owner; + + if (read_permanent_flags((char *)&pf, sizeof(pf)) || + read_has_owner(&has_owner)) + return; + + printf("TPM is "); + + if (pf.flags[PERM_FLAG_IDX_DISABLE]) + printf("disabled"); + else + printf("enabled"); + + if (pf.flags[PERM_FLAG_IDX_DEACTIVATED]) + printf(", deactivated"); + else + printf(", active"); + + if (has_owner) + printf(" and has an owner.\n"); + else { + printf(", does not have an owner "); + if (pf.flags[PERM_FLAG_IDX_OWNERSHIP]) + printf("but one can be installed.\n"); + else + printf("and an owner cannot be installed.\n"); + } + +} + + +void +tpm_menu(void) +{ + if (!CONFIG_TCGBIOS) + return; + + int scan_code; + u32 rc, returnCode; + u8 next_step; + tpm_bios_cfg_t cfg = { + .op = 0, + }; + + while (get_keystroke(0) >= 0) + ; + wait_threads(); + + for (;;) { + if (has_working_tpm()) { + printf("1. Enable TPM\n" + "2. Disable TPM\n" + "3. Activate TPM\n" + "4. Deactivate TPM\n" + "5. Clear ownership\n" + "6. Allow installation of owner\n" + "7. Prevent installation of owner\n"); + } else { + printf("TPM is not working correctly.\n"); + } + + printf("Escape for previous menu.\n"); + + if (has_working_tpm()) { + show_tpm_state(); + } + + cfg.op = 0; + + while ((scan_code = get_keystroke(1000)) == ~0) + ; + + switch (scan_code) { + case 1: + // ESC + return; + case 2 ... 6: + cfg.op = scan_code - 1; + break; + case 7 ... 8: + cfg.op = scan_code + 1; + break; + default: + continue; + } + + if (has_working_tpm()) { + rc = tpm_process_cfg(&cfg, 1, &returnCode, &next_step); + + if (rc) + printf("An error occurred: 0x%x\n", rc); + } + } +} diff --git a/src/tcgbios.h b/src/tcgbios.h index 0fcca15..28c646a 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -434,5 +434,7 @@ u32 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length); u32 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length); u32 tpm_add_cdrom_catalog(const u8 *addr, u32 length); u32 tpm_option_rom(const void *addr, u32 len); +int tpm_is_detected(void); +void tpm_menu(void);
#endif /* TCGBIOS_H */ diff --git a/src/util.h b/src/util.h index 2244090..bb24744 100644 --- a/src/util.h +++ b/src/util.h @@ -36,6 +36,7 @@ int bootprio_find_pci_rom(struct pci_device *pci, int instance); int bootprio_find_named_rom(const char *name, int instance); struct usbdevice_s; int bootprio_find_usb(struct usbdevice_s *usbdev, int lun); +int get_keystroke(int msec);
// bootsplash.c void enable_vga_console(void);