qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Stefan Berger <stefanb@linux.vnet.ibm.com>
To: stefanb@linux.vnet.ibm.com, seabios@seabios.org
Cc: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH V6 7/9] Add a menu for TPM control
Date: Wed, 10 Aug 2011 12:51:29 -0400	[thread overview]
Message-ID: <20110810165140.923984567@linux.vnet.ibm.com> (raw)
In-Reply-To: 20110810165122.639452836@linux.vnet.ibm.com

[-- Attachment #1: tcgbios_menu.diff --]
[-- Type: text/plain, Size: 15040 bytes --]

This patch provides an addtional menu entry that enables the user to control
certain aspects of the TPM.

If a working TPM has been detected, the top level BIOS menu
will look like this:

Press F12 for boot menu.
Press F11 to TPM menu.

Upon pressing F11 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.

The code for the above 7 menu items is part of this patch.

v6:
  - passing durations of commands to the transmission function

v5:
  - fixed an indentation

v2:
  - use if (!CONFIG_TCGBIOS) ... in all non-static functions
  - use dprintf(DEBUG_tcg, ...) for printing of debugging info
  - removing some code used for a future patch

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>


---
 src/boot.c    |   10 +
 src/tcgbios.c |  504 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tcgbios.h |    1 
 3 files changed, 514 insertions(+), 1 deletion(-)

Index: seabios/src/tcgbios.c
===================================================================
--- seabios.orig/src/tcgbios.c
+++ seabios/src/tcgbios.c
@@ -84,6 +84,10 @@ static tcpa_state_t tcpa_state = {
 
 extern struct tpm_driver tpm_drivers[];
 
+typedef struct {
+    u8  op;
+} tpm_bios_cfg_t;
+
 
 /********************************************************
   Extensions for TCG-enabled BIOS
@@ -1450,3 +1454,503 @@ tcpa_ipl(enum ipltype bootcd, const u8 *
 
 
 
+static u32
+assert_physical_presence(void)
+{
+    u32 rc = 0;
+    u32 returnCode;
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+                            PhysicalPresence_CMD_ENABLE,
+                            sizeof(PhysicalPresence_CMD_ENABLE),
+                            NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+    dprintf(DEBUG_tcg,
+           "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n",
+           returnCode);
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+                            PhysicalPresence_PRESENT,
+                            sizeof(PhysicalPresence_PRESENT),
+                            NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+    dprintf(DEBUG_tcg,
+           "Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n",
+           returnCode);
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    return 0;
+
+err_exit:
+    dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+    tcpa_state.tpm_working = 0;
+    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, 0x0, buf_len);
+
+    rc = build_and_send_cmd(TPM_ORD_GetCapability,
+                            GetCapability_Permanent_Flags,
+                            sizeof(GetCapability_Permanent_Flags),
+                            (u8 *)&pf,
+                            sizeof(struct tpm_res_getcap_perm_flags),
+                            &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__);
+
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+read_has_owner(u8 *has_owner)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_res_getcap_ownerauth oauth;
+
+    rc = build_and_send_cmd(TPM_ORD_GetCapability,
+                            GetCapability_OwnerAuth,
+                            sizeof(GetCapability_OwnerAuth),
+                            (u8 *)&oauth,
+                            sizeof(struct tpm_res_getcap_ownerauth),
+                            &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__);
+
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+disable_tpm(int disable, int verbose)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_permanent_flags pf;
+
+    rc = read_permanent_flags((char *)&pf, sizeof(pf));
+    if (rc)
+        return rc;
+
+    if (!!pf.flags[PERM_FLAG_IDX_DISABLE] == !!disable) {
+        if (verbose)
+            printf("TPM is already %s.\n,",
+                   disable ? "disabled" : "enabled");
+        return 0;
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+        dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
+        return rc;
+    }
+
+    rc = build_and_send_cmd(disable ? TPM_ORD_PhysicalDisable
+                                    : TPM_ORD_PhysicalEnable,
+                            NULL, 0, NULL, 10, &returnCode,
+                            TPM_DURATION_TYPE_SHORT);
+    dprintf(DEBUG_tcg, "Return code from TPM_Physical%sable = 0x%08x\n",
+            disable ? "Dis" : "En", returnCode);
+
+    if (rc || returnCode)
+        goto err_exit;
+
+
+    return 0;
+
+err_exit:
+    dprintf(DEBUG_tcg, "TCGBIOS: %sabling the TPM failed.\n",
+            disable ? "Dis" : "En");
+    dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+deactivate_tpm(int deactivate, int allow_reset, int verbose)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_permanent_flags pf;
+
+    rc = read_permanent_flags((char *)&pf, sizeof(pf));
+    if (rc)
+        return rc;
+
+    if (!!pf.flags[PERM_FLAG_IDX_DEACTIVATED] == !!deactivate) {
+        if (verbose)
+            printf("TPM is already %s.\n",
+                   deactivate ? "deactivated" : "activated");
+        return 0;
+    }
+
+    if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
+        if (verbose)
+            printf("TPM must first be enabled.\n");
+        return 0;
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+        dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
+        return rc;
+    }
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalSetDeactivated,
+                            deactivate ? CommandFlag_TRUE
+                                       : CommandFlag_FALSE,
+                            deactivate ? sizeof(CommandFlag_TRUE)
+                                       : sizeof(CommandFlag_FALSE),
+                            NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT);
+
+    dprintf(DEBUG_tcg,
+            "Return code from PhysicalSetDeactivated(%d) = 0x%08x\n",
+            deactivate ? 1 : 0, returnCode);
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    if (!deactivate && 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__);
+
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+enable_activate(int allow_reset, int verbose)
+{
+    u32 rc;
+
+    rc = disable_tpm(0, verbose);
+    if (rc)
+        return rc;
+
+    rc = deactivate_tpm(0, allow_reset, verbose);
+
+    return rc;
+}
+
+
+static u32
+force_clear(int enable_activate_before, int enable_activate_after, int verbose)
+{
+    u32 rc;
+    u32 returnCode;
+    u8 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, verbose);
+        if (rc) {
+            dprintf(DEBUG_tcg,
+                    "TCGBIOS: Enabling/activating the TPM failed.\n");
+            return rc;
+        }
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+        dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
+        return rc;
+    }
+
+    rc = build_and_send_cmd(TPM_ORD_ForceClear,
+                            NULL, 0, NULL, 10, &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, verbose);
+
+    return 0;
+
+err_exit:
+    dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+set_owner_install(int allow, int verbose)
+{
+    u32 rc, returnCode;
+    u8 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();
+    if (rc) {
+        dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
+        return rc;
+    }
+
+    rc = build_and_send_cmd(TPM_ORD_SetOwnerInstall,
+                            (allow) ? CommandFlag_TRUE :
+                                      CommandFlag_FALSE,
+                            sizeof(CommandFlag_TRUE),
+                            NULL, 10, &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__);
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+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");
+    }
+
+}
+
+
+static u32
+tcpa_process_cfg(const tpm_bios_cfg_t *cfg, int verbose)
+{
+    u32 rc = 0;
+
+    switch (cfg->op) {
+        case 0: /* no-op */
+            break;
+
+        case 1:
+            rc = disable_tpm(0, verbose);
+            break;
+
+        case 2:
+            rc = disable_tpm(1, verbose);
+            break;
+
+        case 3:
+            rc = deactivate_tpm(0, 1, verbose);
+            break;
+
+        case 4:
+            rc = deactivate_tpm(1, 1, verbose);
+            break;
+
+        case 5:
+            rc = force_clear(1, 0, verbose);
+            break;
+
+        case 6:
+            rc = set_owner_install(1, verbose);
+            break;
+
+        case 7:
+            rc = set_owner_install(0, verbose);
+            break;
+
+        default:
+            break;
+    }
+
+    if (rc)
+        printf("Op %d: An error occurred: 0x%x\n", cfg->op, rc);
+
+    return rc;
+}
+
+
+void
+tcpa_menu(void)
+{
+    if (!CONFIG_TCGBIOS)
+        return;
+
+    int show_menu = 1;
+    int scan_code;
+    u32 rc;
+    tpm_bios_cfg_t cfg = {
+        .op  = 0,
+    };
+
+    while (get_keystroke(0) >= 0)
+        ;
+    wait_threads();
+
+    for (;;) {
+        if (show_menu) {
+            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"
+                   "Escape for previous menu.\n");
+            show_menu = 0;
+            show_tpm_state();
+        }
+
+        cfg.op = 0;
+
+        scan_code = get_keystroke(1000);
+
+        switch (scan_code) {
+        case 1:
+            // ESC
+            return;
+        case 2 ... 8:
+            cfg.op = scan_code - 1;
+            break;
+        default:
+            continue;
+        }
+
+        rc = tcpa_process_cfg(&cfg, 1);
+
+        if (rc)
+            printf("An error occurred: 0x%x\n", rc);
+
+        show_menu = 1;
+    }
+}
+
+
Index: seabios/src/tcgbios.h
===================================================================
--- seabios.orig/src/tcgbios.h
+++ seabios/src/tcgbios.h
@@ -390,6 +390,7 @@ u32 tcpa_ipl(enum ipltype bootcd, const 
 u32 tcpa_start_option_rom_scan(void);
 u32 tcpa_option_rom(const void *addr, u32 len);
 u32 tcpa_smbios_measure(void);
+void tcpa_menu(void);
 
 
 #endif /* TCGBIOS_H */
Index: seabios/src/boot.c
===================================================================
--- seabios.orig/src/boot.c
+++ seabios/src/boot.c
@@ -377,12 +377,20 @@ interactive_bootmenu(void)
     while (get_keystroke(0) >= 0)
         ;
 
-    printf("Press F12 for boot menu.\n\n");
+again:
+    printf("Press F12 for boot menu.\n");
+    if (has_working_tpm())
+        printf("Press F11 to TPM menu.\n");
+    printf("\n");
 
     u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
     enable_bootsplash();
     int scan_code = get_keystroke(menutime);
     disable_bootsplash();
+    if (has_working_tpm() && scan_code == 0x85) {
+         tcpa_menu();
+         goto again;
+    }
     if (scan_code != 0x86)
         /* not F12 */
         return;

  parent reply	other threads:[~2011-08-10 16:52 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-08-10 16:51 [Qemu-devel] [PATCH V6 0/9] Add TPM support to SeaBIOS Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 1/9] Add an implementation of a TPM TIS driver Stefan Berger
2011-08-12 14:39   ` [Qemu-devel] [SeaBIOS] " Andreas Niederl
2011-08-16 15:33     ` Stefan Berger
2011-08-19 17:33   ` Marc Jones
2011-08-19 19:13     ` Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 2/9] Provide ACPI SSDT table for TPM device + S3 resume support Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 3/9] Add public get_rsdp function Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 4/9] Implementation of the TCG BIOS extensions Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 5/9] Support for BIOS interrupt handler Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 6/9] Add measurement code to the BIOS Stefan Berger
2011-08-10 16:51 ` Stefan Berger [this message]
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 8/9] Support for Qemu-provided measurements Stefan Berger
2011-08-10 16:51 ` [Qemu-devel] [PATCH V6 9/9] Optional tests for the TIS interface Stefan Berger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110810165140.923984567@linux.vnet.ibm.com \
    --to=stefanb@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=seabios@seabios.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).