This series provides two small fixes and then adds the menu for TPM control.
Regards, Stefan
Stefan Berger (3): Remove check for working TPM from TPM interrupt handler Check length parameter of the array tpm: Add a menu for TPM configuration
src/boot.c | 9 +- src/std/tcg.h | 41 ++++ src/tcgbios.c | 661 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 2 + src/util.h | 1 + 5 files changed, 708 insertions(+), 6 deletions(-)
From: Stefan Berger stefanb@linux.vnet.ibm.com
Remove the check for a working TPM from the TPM interrupt handler. This then allows the individual API calls to return information even if the TPM was not working correctly. Some API calls will still run into the check.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/tcgbios.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/src/tcgbios.c b/src/tcgbios.c index d1a7f6b..c17d80d 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -1102,11 +1102,6 @@ tpm_interrupt_handler32(struct bregs *regs)
set_cf(regs, 0);
- if (!has_working_tpm()) { - regs->eax = TCG_GENERAL_ERROR; - return; - } - switch ((enum irq_ids)regs->al) { case TCG_StatusCheck: if (is_tpm_present() == 0) {
From: Stefan Berger stefanb@linux.vnet.ibm.com
Check the length parameter that indicates the length of the array for whether it has a minimum value of 0x200.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/tcgbios.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/src/tcgbios.c b/src/tcgbios.c index c17d80d..285723c 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -766,6 +766,9 @@ tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length) if (!has_working_tpm()) return TCG_GENERAL_ERROR;
+ if (length < 0x200) + return TCG_INVALID_INPUT_PARA; + const char *string = "Booting BCV device 00h (Floppy)"; if (bootdrv == 0x80) string = "Booting BCV device 80h (HDD)";
From: Stefan Berger stefanb@linux.vnet.ibm.com
This patch adds an new menu entry to the main menu. This menu item enables the user to enter a TPM control menu which allows control of those aspects of the TPM's state that can only be controlled while in the firmware and while physical presence can be asserted.
If the machine has a TPM, the boot menu will look as follows, with the new menu item accessible by pressing the 't' key.
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 submenu will be shown:
The Trusted Platform Module (TPM) is a hardware device in this machine. It can help verify the integrity of system software.
The current state of the TPM is: Enabled and active Ownership has not been taken A user can take ownership of the TPM
Available options are: d. Disable the TPM v. Deactivate the TPM p. Prevent installation of an owner
If no change is desired or if this menu was reached by mistake, press ESC to reboot the machine.
The TPM menu only shows those options that are currently accessible considering the state of the TPM.
The patch adds several functions for sending those messages to the TPM required for supporting those menu items.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/boot.c | 9 +- src/std/tcg.h | 41 ++++ src/tcgbios.c | 653 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tcgbios.h | 2 + src/util.h | 1 + 5 files changed, 705 insertions(+), 1 deletion(-)
diff --git a/src/boot.c b/src/boot.c index e0f73a3..a251eb4 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); @@ -486,6 +486,9 @@ interactive_bootmenu(void) printf("%d. %s\n", maxmenu , strtcpy(desc, pos->description, ARRAY_SIZE(desc))); } + if (tpm_is_working()) { + printf("\nt. TPM Configuration\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 +499,10 @@ interactive_bootmenu(void) scan_code = get_keystroke(1000); if (scan_code == 1 && !irqtimer_check(esc_accepted_time)) continue; + if (tpm_is_working() && scan_code == 20 /* t */) { + printf("\n"); + tpm_menu(); + } if (scan_code >= 1 && scan_code <= maxmenu+1) break; } diff --git a/src/std/tcg.h b/src/std/tcg.h index f6a47c7..d7b3fc4 100644 --- a/src/std/tcg.h +++ b/src/std/tcg.h @@ -292,6 +292,29 @@ struct tpm_res_getcap_perm_flags { struct tpm_permanent_flags perm_flags; } PACKED;
+struct tpm_req_getcap_stclear_flags { + TPM_REQ_HEADER + u32 capArea; + u32 subCapSize; + u32 subCap; +} PACKED; + +struct tpm_stclear_flags { + u16 tag; + u8 flags[5]; +} PACKED; + +#define STCLEAR_FLAG_IDX_DEACTIVATED 0 +#define STCLEAR_FLAG_IDX_DISABLE_FORCE_CLEAR 1 +#define STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE 2 +#define STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE_LOCK 3 +#define STCLEAR_FLAG_IDX_GLOBAL_LOCK 4 + +struct tpm_res_getcap_stclear_flags { + TPM_RSP_HEADER + u32 size; + struct tpm_stclear_flags stclear_flags; +} PACKED;
struct tpm_res_getcap_ownerauth { TPM_RSP_HEADER @@ -325,4 +348,22 @@ struct tpm_res_sha1complete { u8 hash[20]; } PACKED;
+#define TPM_STATE_ENABLED 1 +#define TPM_STATE_ACTIVE 2 +#define TPM_STATE_OWNED 4 +#define TPM_STATE_OWNERINSTALL 8 + +/* + * physical presence interface + */ + +#define TPM_PPI_OP_NOOP 0 +#define TPM_PPI_OP_ENABLE 1 +#define TPM_PPI_OP_DISABLE 2 +#define TPM_PPI_OP_ACTIVATE 3 +#define TPM_PPI_OP_DEACTIVATE 4 +#define TPM_PPI_OP_CLEAR 5 +#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 +#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9 + #endif // tcg.h diff --git a/src/tcgbios.c b/src/tcgbios.c index 285723c..e28d3eb 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -23,6 +23,8 @@ #include "string.h" // checksum #include "tcgbios.h"// tpm_*, prototypes #include "util.h" // printf, get_keystroke +#include "malloc.h" // malloc_* +#include "stacks.h" // wait_threads
static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR }; static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE }; @@ -40,6 +42,11 @@ static const u8 GetCapability_Permanent_Flags[] = { 0x00, 0x00, 0x01, 0x08 };
+static const u8 GetCapability_STClear_Flags[] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x09 +}; + static const u8 GetCapability_OwnerAuth[] = { 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x11 @@ -88,6 +95,12 @@ tpm_state_t tpm_state VARLOW = { .tpm_driver_to_use = TPM_INVALID_DRIVER, };
+typedef struct { + u8 op; +} tpm_bios_cfg; + +extern void reset_vector(void) __noreturn; + static u32 is_preboot_if_shutdown(void) { @@ -136,6 +149,15 @@ has_working_tpm(void) return tpm_state.tpm_working; }
+int +tpm_is_working(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + return tpm_state.tpm_working; +} + static u32 transmit(u8 locty, struct tpm_req_header *req, void *respbuffer, u32 *respbufferlen, @@ -1169,3 +1191,634 @@ tpm_interrupt_handler32(struct bregs *regs)
return; } + +static u32 +read_stclear_flags(char *buf, int buf_len) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_stclear_flags stcf; + + memset(buf, 0, buf_len); + + rc = build_and_send_cmd(0, TPM_ORD_GetCapability, + GetCapability_STClear_Flags, + sizeof(GetCapability_STClear_Flags), + (u8 *)&stcf, sizeof(stcf), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() " + "= 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + memcpy(buf, &stcf.stclear_flags, buf_len); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +assert_physical_presence(int verbose) +{ + u32 rc = 0; + u32 returnCode; + struct tpm_stclear_flags stcf; + + rc = read_stclear_flags((char *)&stcf, sizeof(stcf)); + if (rc) { + dprintf(DEBUG_tcg, + "Error reading STClear flags: 0x%08x\n", rc); + return rc; + } + + if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE]) + /* physical presence already asserted */ + return 0; + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, + "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n", + returnCode); + + if (rc || returnCode) { + if (verbose) + printf("Error: Could not enable physical presence.\n\n"); + goto err_exit; + } + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_PRESENT, + sizeof(PhysicalPresence_PRESENT), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, + "Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n", + returnCode); + + if (rc || returnCode) { + if (verbose) + printf("Error: Could not set presence flag.\n\n"); + goto err_exit; + } + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +read_permanent_flags(char *buf, int buf_len) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_perm_flags pf; + + memset(buf, 0, buf_len); + + rc = build_and_send_cmd(0, TPM_ORD_GetCapability, + GetCapability_Permanent_Flags, + sizeof(GetCapability_Permanent_Flags), + (u8 *)&pf, sizeof(pf), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() " + "= 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + memcpy(buf, &pf.perm_flags, buf_len); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +read_has_owner(int *has_owner) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_ownerauth oauth; + + rc = build_and_send_cmd(0, TPM_ORD_GetCapability, + GetCapability_OwnerAuth, + sizeof(GetCapability_OwnerAuth), + (u8 *)&oauth, sizeof(oauth), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() " + "= 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + *has_owner = oauth.flag; + + return 0; + +err_exit: + dprintf(DEBUG_tcg,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +enable_tpm(int enable, u32 *returnCode, int verbose) +{ + u32 rc; + struct tpm_permanent_flags pf; + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return rc; + + if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable) + return 0; + + rc = assert_physical_presence(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable + : TPM_ORD_PhysicalDisable, + NULL, 0, NULL, 0, returnCode, + TPM_DURATION_TYPE_SHORT); + if (enable) + dprintf(DEBUG_tcg, "Return code from TPM_PhysicalEnable = 0x%08x\n", + *returnCode); + else + dprintf(DEBUG_tcg, "Return code from TPM_PhysicalDisable = 0x%08x\n", + *returnCode); + + if (rc || *returnCode) + goto err_exit; + + return 0; + +err_exit: + if (enable) + dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n"); + else + dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n"); + + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +activate_tpm(int activate, int allow_reset, u32 *returnCode, int verbose) +{ + u32 rc; + struct tpm_permanent_flags pf; + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return rc; + + if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate) + return 0; + + if (pf.flags[PERM_FLAG_IDX_DISABLE]) + return 0; + + rc = assert_physical_presence(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated, + activate ? CommandFlag_FALSE + : CommandFlag_TRUE, + activate ? sizeof(CommandFlag_FALSE) + : sizeof(CommandFlag_TRUE), + NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, + "Return code from PhysicalSetDeactivated(%d) = 0x%08x\n", + activate ? 0 : 1, *returnCode); + + if (rc || *returnCode) + goto err_exit; + + if (activate && allow_reset) { + if (verbose) { + printf("Requiring a reboot to activate the TPM.\n"); + + msleep(2000); + } + reset_vector(); + } + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +enable_activate(int allow_reset, u32 *returnCode, int verbose) +{ + u32 rc; + + rc = enable_tpm(1, returnCode, verbose); + if (rc) + return rc; + + rc = activate_tpm(1, allow_reset, returnCode, verbose); + + return rc; +} + +static u32 +force_clear(int enable_activate_before, int enable_activate_after, + u32 *returnCode, int verbose) +{ + u32 rc; + int has_owner; + + rc = read_has_owner(&has_owner); + if (rc) + return rc; + if (!has_owner) { + if (verbose) + printf("TPM does not have an owner.\n"); + return 0; + } + + if (enable_activate_before) { + rc = enable_activate(0, returnCode, verbose); + if (rc) { + dprintf(DEBUG_tcg, + "TCGBIOS: Enabling/activating the TPM failed.\n"); + return rc; + } + } + + rc = assert_physical_presence(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, TPM_ORD_ForceClear, + NULL, 0, NULL, 0, returnCode, + TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TPM_ForceClear() = 0x%08x\n", + *returnCode); + + if (rc || *returnCode) + goto err_exit; + + if (!enable_activate_after) { + if (verbose) + printf("Owner successfully cleared.\n" + "You will need to enable/activate the TPM again.\n\n"); + return 0; + } + + enable_activate(1, returnCode, verbose); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +set_owner_install(int allow, u32 *returnCode, int verbose) +{ + u32 rc; + int has_owner; + struct tpm_permanent_flags pf; + + rc = read_has_owner(&has_owner); + if (rc) + return rc; + if (has_owner) { + if (verbose) + printf("Must first remove owner.\n"); + return 0; + } + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return rc; + + if (pf.flags[PERM_FLAG_IDX_DISABLE]) { + if (verbose) + printf("TPM must first be enable.\n"); + return 0; + } + + rc = assert_physical_presence(verbose); + if (rc) { + dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n"); + return rc; + } + + rc = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall, + (allow) ? CommandFlag_TRUE : + CommandFlag_FALSE, + sizeof(CommandFlag_TRUE), + NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TPM_SetOwnerInstall() = 0x%08x\n", + *returnCode); + + if (rc || *returnCode) + goto err_exit; + + if (verbose) + printf("Installation of owner %s.\n", allow ? "enabled" : "disabled"); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + tpm_set_failure(); + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + +static u32 +tpm_process_cfg(const tpm_bios_cfg *cfg, int verbose, u32 *returnCode) +{ + u32 rc = 0; + + switch (cfg->op) { + case TPM_PPI_OP_NOOP: /* no-op */ + break; + + case TPM_PPI_OP_ENABLE: + rc = enable_tpm(1, returnCode, verbose); + break; + + case TPM_PPI_OP_DISABLE: + rc = enable_tpm(0, returnCode, verbose); + break; + + case TPM_PPI_OP_ACTIVATE: + rc = activate_tpm(1, 1, returnCode, verbose); + break; + + case TPM_PPI_OP_DEACTIVATE: + rc = activate_tpm(0, 1, returnCode, verbose); + break; + + case TPM_PPI_OP_CLEAR: + rc = force_clear(1, 0, returnCode, verbose); + break; + + case TPM_PPI_OP_SET_OWNERINSTALL_TRUE: + rc = set_owner_install(1, returnCode, verbose); + break; + + case TPM_PPI_OP_SET_OWNERINSTALL_FALSE: + rc = set_owner_install(0, returnCode, verbose); + break; + + default: + break; + } + + if (rc) + printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n", + cfg->op, rc, *returnCode); + + return rc; +} + +static int +get_tpm_state(void) +{ + int state = 0; + struct tpm_permanent_flags pf; + int has_owner; + + if (read_permanent_flags((char *)&pf, sizeof(pf)) || + read_has_owner(&has_owner)) + return ~0; + + if (!pf.flags[PERM_FLAG_IDX_DISABLE]) + state |= TPM_STATE_ENABLED; + + if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED]) + state |= TPM_STATE_ACTIVE; + + if (has_owner) { + state |= TPM_STATE_OWNED; + } else { + if (pf.flags[PERM_FLAG_IDX_OWNERSHIP]) + state |= TPM_STATE_OWNERINSTALL; + } + + return state; +} + +static void +show_tpm_menu(int state, int next_scancodes[7]) +{ + int i = 0; + + printf("\nThe current state of the TPM is:\n"); + + if (state & TPM_STATE_ENABLED) + printf(" Enabled"); + else + printf(" Disabled"); + + if (state & TPM_STATE_ACTIVE) + printf(" and active\n"); + else + printf(" and deactivated\n"); + + if (state & TPM_STATE_OWNED) + printf(" Ownership has been taken\n"); + else { + printf(" Ownership has not been taken\n"); + if (state & TPM_STATE_OWNERINSTALL) + printf(" A user can take ownership of the TPM\n"); + else + printf(" Taking ownership of the TPM has been disabled\n"); + } + + if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) != + (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) { + printf("\nNote: To make use of all functionality, the TPM must be " + "enabled and active.\n"); + } + + printf("\nAvailable options are:\n"); + if (state & TPM_STATE_ENABLED) { + printf(" d. Disable the TPM\n"); + next_scancodes[i++] = 32; + + if (state & TPM_STATE_ACTIVE) { + printf(" v. Deactivate the TPM\n"); + next_scancodes[i++] = 47; + + if (state & TPM_STATE_OWNERINSTALL) { + printf(" p. Prevent installation of an owner\n"); + next_scancodes[i++] = 25; + } else { + printf(" s. Allow installation of an owner\n"); + next_scancodes[i++] = 31; + } + } else { + printf(" a. Activate the TPM\n"); + next_scancodes[i++] = 30; + } + + } else { + printf(" e. Enable the TPM\n"); + next_scancodes[i++] = 18; + } + + if (state & TPM_STATE_OWNED) { + printf(" c. Clear ownership\n"); + next_scancodes[i++] = 46; + } + + next_scancodes[i++] = 0; +} + +void +tpm_menu(void) +{ + if (!CONFIG_TCGBIOS) + return; + + int scancode, next_scancodes[7]; + u32 rc, returnCode; + tpm_bios_cfg cfg = { + .op = TPM_PPI_OP_NOOP, + }; + int state = 0, i; + int waitkey; + + while (get_keystroke(0) >= 0) + ; + wait_threads(); + + printf("The Trusted Platform Module (TPM) is a hardware device in " + "this machine.\n" + "It can help verify the integrity of system software.\n\n"); + + for (;;) { + if ((state = get_tpm_state()) != ~0) { + show_tpm_menu(state, next_scancodes); + } else { + printf("TPM is not working correctly.\n"); + return; + } + + printf("\nIf no change is desired or if this menu was reached by " + "mistake, press ESC to\n" + "reboot the machine.\n"); + + cfg.op = TPM_PPI_OP_NOOP; + + waitkey = 1; + + while (waitkey) { + while ((scancode = get_keystroke(1000)) == ~0) + ; + + switch (scancode) { + case 1: + // ESC + reset_vector(); + break; + case 18: /* e. enable */ + cfg.op = TPM_PPI_OP_ENABLE; + break; + case 32: /* d. disable */ + cfg.op = TPM_PPI_OP_DISABLE; + break; + case 30: /* a. activate */ + cfg.op = TPM_PPI_OP_ACTIVATE; + break; + case 47: /* v. deactivate */ + cfg.op = TPM_PPI_OP_DEACTIVATE; + break; + case 46: /* c. clear owner */ + cfg.op = TPM_PPI_OP_CLEAR; + break; + case 25: /* p. prevent ownerinstall */ + cfg.op = TPM_PPI_OP_SET_OWNERINSTALL_FALSE; + break; + case 31: /* s. allow ownerinstall */ + cfg.op = TPM_PPI_OP_SET_OWNERINSTALL_TRUE; + break; + default: + continue; + } + + /* + * Using the next_scancodes array, check whether the + * pressed key is currently a valid option. + */ + for (i = 0; i < sizeof(next_scancodes); i++) { + if (next_scancodes[i] == 0) + break; + + if (next_scancodes[i] == scancode) { + rc = tpm_process_cfg(&cfg, 1, &returnCode); + + if (rc) + printf("An error occurred: 0x%x\n", rc); + waitkey = 0; + break; + } + } + } + } +} diff --git a/src/tcgbios.h b/src/tcgbios.h index 4d69b1e..7934fc3 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -13,5 +13,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_working(void); +void tpm_menu(void);
#endif /* TCGBIOS_H */ diff --git a/src/util.h b/src/util.h index 7fcd6dc..76db57f 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);
Stefan Berger wrote:
+++ b/src/tcgbios.c +static u32 +read_stclear_flags(char *buf, int buf_len) +{
..
- if (rc || returnCode)
goto err_exit;
..
+err_exit:
- dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
I can't help but think that it would be significantly more useful to turn the "goto err_exit" into a macro everywhere. Something like:
#define malfunc_err_exit() do { \ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); \ goto err_exit; \ } while (0)
..so that the line number of the actual problem is output.
//Peter
On Mon, Nov 30, 2015 at 06:02:45AM +0100, Peter Stuge wrote:
Stefan Berger wrote:
+++ b/src/tcgbios.c +static u32 +read_stclear_flags(char *buf, int buf_len) +{
..
- if (rc || returnCode)
goto err_exit;
..
+err_exit:
- dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
I can't help but think that it would be significantly more useful to turn the "goto err_exit" into a macro everywhere. Something like:
#define malfunc_err_exit() do { \ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); \ goto err_exit; \ } while (0)
..so that the line number of the actual problem is output.
I find goto's out of macros to be confusing, so would prefer to avoid that.
If there is a desire to shrink the number of error messages, the generic warn_internalerror(), warn_timeout(), and warn_noalloc() macros are available. We could add a generic warn_hwerror().
-Kevin
Kevin O'Connor wrote:
+static u32 +read_stclear_flags(char *buf, int buf_len) +{
..
- if (rc || returnCode)
goto err_exit;
..
+err_exit:
- dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
I can't help but think that it would be significantly more useful to turn the "goto err_exit" into a macro everywhere. Something like:
#define malfunc_err_exit() do { \ dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); \ goto err_exit; \ } while (0)
..so that the line number of the actual problem is output.
I find goto's out of macros to be confusing, so would prefer to avoid that.
Fine, there are other ways to accomplish the same thing.
If there is a desire to shrink the number of error messages
There is a desire to make error messages more useful.
The original patch outputs the line number at the error label, ie. always the same line number for a function, regardless of what caused the error.
My suggestion instead outputs the line number at/before the goto. I should also have added %s __func__ there.
//Peter
Sorry, should have sent all in one email.
Stefan Berger wrote:
- if (enable)
dprintf(DEBUG_tcg, "Return code from TPM_PhysicalEnable = 0x%08x\n",
*returnCode);
- else
dprintf(DEBUG_tcg, "Return code from TPM_PhysicalDisable = 0x%08x\n",
*returnCode);
Maybe simplify this to one string with %s + enable ? "Enable" : "Disable" ?
+err_exit:
- if (enable)
dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
- else
dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
Same here.
- dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
See last email. This dprintf() seems a bit redundant with the error in the lines above.
- if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
if (verbose)
printf("TPM must first be enable.\n");
Typo: enabled
+tpm_process_cfg(const tpm_bios_cfg *cfg, int verbose, u32 *returnCode)
..
- if (rc)
printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n",
cfg->op, rc, *returnCode);
Maybe add a %s __func__ or some word about where this happened.
+show_tpm_menu(int state, int next_scancodes[7])
Are scancodes really 32-bit? If you use a fixed size that's presumably to save a bit of memory. I would prefer next_scancodes to be dynamically sized according to some number of possible scancodes in an enum or somesuch which is known at compile time, and for it to be an array of unsigned char/uint8_t or uint16_t, as appropriate for the hardware. IIRC scancodes are 8 bit?
- if (state & TPM_STATE_ENABLED)
printf(" Enabled");
- else
printf(" Disabled");
I'd use %s ? : for these but that's a matter of taste.
+void +tpm_menu(void) +{
..
- printf("The Trusted Platform Module (TPM) is a hardware device in "
"this machine.\n"
This is not universally true. I believe that the ME implements TPM in software on recent platforms.
In this patch there is also an msleep(2000) call. Please avoid adding unneccessary delays to the code.
Thanks!
//Peter
On Mon, Nov 30, 2015 at 06:18:27AM +0100, Peter Stuge wrote:
Sorry, should have sent all in one email.
Stefan Berger wrote:
- if (enable)
dprintf(DEBUG_tcg, "Return code from TPM_PhysicalEnable = 0x%08x\n",
*returnCode);
- else
dprintf(DEBUG_tcg, "Return code from TPM_PhysicalDisable = 0x%08x\n",
*returnCode);
Maybe simplify this to one string with %s + enable ? "Enable" : "Disable" ?
[...]
FYI, I agree with the idea of simplifying the error messages, but I didn't think it was worth it to hold the series up.
-Kevin
On Sun, Nov 29, 2015 at 11:49:43PM -0500, Stefan Berger wrote:
From: Stefan Berger stefanb@linux.vnet.ibm.com
This patch adds an new menu entry to the main menu. This menu item enables the user to enter a TPM control menu which allows control of those aspects of the TPM's state that can only be controlled while in the firmware and while physical presence can be asserted.
[...]
--- a/src/std/tcg.h +++ b/src/std/tcg.h
[...]
@@ -325,4 +348,22 @@ struct tpm_res_sha1complete { u8 hash[20]; } PACKED;
+#define TPM_STATE_ENABLED 1 +#define TPM_STATE_ACTIVE 2 +#define TPM_STATE_OWNED 4 +#define TPM_STATE_OWNERINSTALL 8
+/*
- physical presence interface
- */
+#define TPM_PPI_OP_NOOP 0 +#define TPM_PPI_OP_ENABLE 1 +#define TPM_PPI_OP_DISABLE 2 +#define TPM_PPI_OP_ACTIVATE 3 +#define TPM_PPI_OP_DEACTIVATE 4 +#define TPM_PPI_OP_CLEAR 5 +#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 +#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
Are the above definitions part of the standard, or internal to the implementation? If the latter, they should go into tcgbios.[ch]
--- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -23,6 +23,8 @@ #include "string.h" // checksum #include "tcgbios.h"// tpm_*, prototypes #include "util.h" // printf, get_keystroke +#include "malloc.h" // malloc_* +#include "stacks.h" // wait_threads
Doesn't look like malloc_x() is used in this code.
[...]
+typedef struct {
- u8 op;
+} tpm_bios_cfg;
What is the purpose of this struct?
+extern void reset_vector(void) __noreturn;
The code should use reset() (defined in stacks.h). Directly calling reset_vector() in 32bit mode isn't strictly correct.
Looks good to me. -Kevin
"Kevin O'Connor" kevin@koconnor.net wrote on 11/30/2015 10:05:22 AM:
From: "Kevin O'Connor" kevin@koconnor.net To: Stefan Berger/Watson/IBM@IBMUS Cc: seabios@seabios.org, Stefan Berger stefanb@linux.vnet.ibm.com Date: 11/30/2015 10:05 AM Subject: Re: [PATCH 3/3] tpm: Add a menu for TPM configuration
On Sun, Nov 29, 2015 at 11:49:43PM -0500, Stefan Berger wrote:
From: Stefan Berger stefanb@linux.vnet.ibm.com
This patch adds an new menu entry to the main menu. This menu item
enables
the user to enter a TPM control menu which allows control of those
aspects
of the TPM's state that can only be controlled while in the firmware and while physical presence can be asserted.
[...]
--- a/src/std/tcg.h +++ b/src/std/tcg.h
[...]
@@ -325,4 +348,22 @@ struct tpm_res_sha1complete { u8 hash[20]; } PACKED;
+#define TPM_STATE_ENABLED 1 +#define TPM_STATE_ACTIVE 2 +#define TPM_STATE_OWNED 4 +#define TPM_STATE_OWNERINSTALL 8
+/*
- physical presence interface
- */
+#define TPM_PPI_OP_NOOP 0 +#define TPM_PPI_OP_ENABLE 1 +#define TPM_PPI_OP_DISABLE 2 +#define TPM_PPI_OP_ACTIVATE 3 +#define TPM_PPI_OP_DEACTIVATE 4 +#define TPM_PPI_OP_CLEAR 5 +#define TPM_PPI_OP_SET_OWNERINSTALL_TRUE 8 +#define TPM_PPI_OP_SET_OWNERINSTALL_FALSE 9
Are the above definitions part of the standard, or internal to the implementation? If the latter, they should go into tcgbios.[ch]
These are actually the 'message codes' from the physical presence interface spec that can be sent from the OS to the BIOS and on which the BIOS is supposed to act upon reboot. You may remember the ACPI patches I had for QEMU where ACPI would write one of the above number into an allocated memory area for the BIOS to find. I also built the menu using those 'message codes'.
--- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -23,6 +23,8 @@ #include "string.h" // checksum #include "tcgbios.h"// tpm_*, prototypes #include "util.h" // printf, get_keystroke +#include "malloc.h" // malloc_* +#include "stacks.h" // wait_threads
Doesn't look like malloc_x() is used in this code.
[...]
+typedef struct {
- u8 op;
+} tpm_bios_cfg;
What is the purpose of this struct?
This datatype is used to send messages from menu item selections to the part that processes above 'message codes'.
+extern void reset_vector(void) __noreturn;
The code should use reset() (defined in stacks.h). Directly calling reset_vector() in 32bit mode isn't strictly correct.
Ok, will change it. (Worked so far...)
Stefan
Looks good to me. -Kevin