Vboot wrapper - add recovery reason, refactor timing

Pressing Tab at a firmware screen now displays real data, including
the recovery reason, HWID, and contents of VbNvStorage.

Entry point start/end time tracking in VbSharedData now refers to the
new wrapper APIs.

Added capability for calling firmware to request recovery mode (for
example, if it's unable to initialize RAM, can't find the SSD, etc.).
Previously, calling firmware had no (good) way to do this other than
faking the recovery button being pressed.

BUG=chromium-os:17018
TEST=emerge on x86 and tegra2_seaboard

Change-Id: I7d377f279842b30a10d945d13571c41c464633f1
Reviewed-on: http://gerrit.chromium.org/gerrit/3814
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index c9eeb33..48859e0 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -95,7 +95,11 @@
 #define VB_INIT_FLAG_WP_ENABLED          0x00000004
 /* This is a S3 resume, not a normal boot. */
 #define VB_INIT_FLAG_S3_RESUME           0x00000008
-
+/* Previous boot attempt failed for reasons external to verified boot (RAM
+ * init failure, SSD missing, etc.). */
+/* TODO: add a field to VbInitParams which holds a reason code, and report
+ * that via VbSharedData. */
+#define VB_INIT_FLAG_PREVIOUS_BOOT_FAIL  0x00000010
 
 /* Output flags for VbInitParams.out_flags.  Used to indicate
  * potential boot paths and configuration to the calling firmware
@@ -210,14 +214,6 @@
 VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
                                 VbSelectAndLoadKernelParams* kparams);
 
-/* S3 resume handler.  This only needs to be called if the hardware
- * does not maintain power to the TPM when in S3 (suspend-to-RAM).
- *
- * Returns VBERROR_SUCCESS if success, non-zero if error; on error,
- * caller should reboot. */
-VbError_t VbS3Resume(void);
-
-
 /*****************************************************************************/
 /* Debug output (from utility.h) */
 
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h
index 02f81a7..046dd75 100644
--- a/firmware/include/vboot_nvstorage.h
+++ b/firmware/include/vboot_nvstorage.h
@@ -86,6 +86,9 @@
  * vboot_struct.h. */
 #define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN  0x10
 #define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX  0x1F
+/* Firmware boot failure outside of verified boot (RAM init, missing SSD,
+ * etc.). */
+#define VBNV_RECOVERY_RO_FIRMWARE     0x20
 /* Unspecified/unknown error in read-only firmware */
 #define VBNV_RECOVERY_RO_UNSPECIFIED  0x3F
 /* User manually requested recovery by pressing a key at developer
diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h
index e9336df..0271979 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -280,14 +280,17 @@
   uint64_t kernel_subkey_data_size;   /* Size of kernel subkey data */
 
   /* Timer values from VbExGetTimer().  Unused values are set to 0.
-   * If a function is called mutiple times, these are the times from
-   * the most recent call.  See crosbug.com/17018. */
-  uint64_t timer_load_firmware_start_enter;  /* VbInit() - enter */
-  uint64_t timer_load_firmware_start_exit;   /* VbInit() - exit */
-  uint64_t timer_load_firmware_enter;        /* LoadFirmware() - enter */
-  uint64_t timer_load_firmware_exit;         /* LoadFirmware() - exit */
-  uint64_t timer_load_kernel_enter;          /* LoadKernel() - enter */
-  uint64_t timer_load_kernel_exit;           /* LoadKernel() - exit */
+   * Note that these are now the enter/exit times for the wrapper API entry
+   * points; see crosbug.com/17018. */
+  /* VbInit() enter/exit */
+  uint64_t timer_vb_init_enter;
+  uint64_t timer_vb_init_exit;
+  /* VbSelectFirmware() enter/exit */
+  uint64_t timer_vb_select_firmware_enter;
+  uint64_t timer_vb_select_firmware_exit;
+  /* VbSelectAndLoadKernel() enter/exit */
+  uint64_t timer_vb_select_and_load_kernel_enter;
+  uint64_t timer_vb_select_and_load_kernel_exit;
 
   /* Information stored in TPM, as retrieved by firmware */
   uint32_t fw_version_tpm;            /* Current firmware version in TPM */
diff --git a/firmware/lib/vboot_api_firmware.c b/firmware/lib/vboot_api_firmware.c
index b4c1481..e4e4af0 100644
--- a/firmware/lib/vboot_api_firmware.c
+++ b/firmware/lib/vboot_api_firmware.c
@@ -20,11 +20,15 @@
   VbNvContext vnc;
   int rv;
 
+  /* Start timer */
+  shared->timer_vb_select_firmware_enter = VbExGetTimer();
+
   /* If recovery is requested, go straight to recovery without checking the
    * RW firmware. */
   if (VBNV_RECOVERY_NOT_REQUESTED != shared->recovery_reason) {
     VBDEBUG(("VbSelectFirmware() detected recovery request, reason=%d.\n",
              (int)shared->recovery_reason));
+    shared->timer_vb_select_firmware_exit = VbExGetTimer();
     fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
     return VBERROR_SUCCESS;
   }
@@ -66,6 +70,9 @@
   /* Copy amount of used shared data back to the wrapper API struct */
   cparams->shared_data_size = (uint32_t)p.shared_data_size;
 
+  /* Stop timer */
+  shared->timer_vb_select_firmware_exit = VbExGetTimer();
+
   /* Translate return codes */
   if (LOAD_FIRMWARE_SUCCESS == rv) {
     /* Found good firmware in either A or B */
diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c
index 8bccfe5..890b576 100644
--- a/firmware/lib/vboot_api_init.c
+++ b/firmware/lib/vboot_api_init.c
@@ -17,6 +17,7 @@
 VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
   VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
   VbNvContext vnc;
+  VbError_t retval = VBERROR_SUCCESS;
   uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
   int is_s3_resume = 0;
   uint32_t s3_debug_boot = 0;
@@ -36,7 +37,7 @@
     return 1;
   }
 
-  shared->timer_load_firmware_start_enter = VbExGetTimer();
+  shared->timer_vb_init_enter = VbExGetTimer();
 
   /* Copy boot switch flags */
   shared->flags = 0;
@@ -74,6 +75,15 @@
       VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED);
   }
 
+  /* If the previous boot failed in the firmware somewhere outside of verified
+   * boot, and recovery is not requested for our own reasons, request recovery
+   * mode.  This gives the calling firmware a way to request recovery if it
+   * finds something terribly wrong. */
+  if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
+      iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
+    recovery = VBNV_RECOVERY_RO_FIRMWARE;
+  }
+
   /* If recovery button is pressed, override recovery reason.  Note that we
    * do this in the S3 resume path also. */
   if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
@@ -97,11 +107,15 @@
   /* Copy current recovery reason to shared data */
   shared->recovery_reason = (uint8_t)recovery;
 
-  /* Clear the recovery request, so we won't get stuck in recovery mode */
-  VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED);
-
-  // TODO: Handle S3 resume path ourselves, if VB_INIT_FLAG_S3_RESUME
-  // (I believe we can do this now...)
+  /* If this is a S3 resume, resume the TPM */
+  if (is_s3_resume) {
+    if (TPM_SUCCESS != RollbackS3Resume()) {
+      /* If we can't resume, just do a full reboot.  No need to go to recovery
+       * mode here, since if the TPM is really broken we'll catch it on the
+       * next boot. */
+      retval = 1;
+    }
+  }
 
   /* Tear down NV storage */
   VbNvTeardown(&vnc);
@@ -110,24 +124,7 @@
 
   VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
 
-  shared->timer_load_firmware_start_exit = VbExGetTimer();
+  shared->timer_vb_init_exit = VbExGetTimer();
 
-  return VBERROR_SUCCESS;
-}
-
-
-VbError_t VbS3Resume(void) {
-
-  /* TODO: handle test errors (requires passing in VbNvContext) */
-
-  /* Resume the TPM */
-  uint32_t status = RollbackS3Resume();
-
-  /* If we can't resume, just do a full reboot.  No need to go to recovery
-   * mode here, since if the TPM is really broken we'll catch it on the
-   * next boot. */
-  if (status == TPM_SUCCESS)
-    return VBERROR_SUCCESS;
-  else
-    return 1;
+  return retval;
 }
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 1afac37..738c476 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -219,24 +219,67 @@
   return VbExDisplayScreen(screen);
 }
 
+#define DEBUG_INFO_SIZE 512
 
 static VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key) {
+  VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
+  GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
 
   if ('\t' == key) {
     /* Tab = display debug info */
+    char buf[DEBUG_INFO_SIZE] = "";
+    uint32_t used = 0;
+    uint32_t i;
 
     /* Redisplay the current screen, to overwrite any previous debug output */
     VbDisplayScreen(cparams, disp_current_screen, 1);
 
-    /* TODO: add real data:
-     * - HWID
-     * - Current recovery request
-     * - Boot flags
+    /* Add hardware ID */
+    used += Strncat(buf + used, "HWID: ", DEBUG_INFO_SIZE - used);
+    if (0 == gbb->hwid_size ||
+        gbb->hwid_offset > cparams->gbb_size ||
+        gbb->hwid_offset + gbb->hwid_size > cparams->gbb_size) {
+      VBDEBUG(("VbCheckDisplayKey(): invalid hwid offset/size\n"));
+      used += Strncat(buf + used, "(INVALID)", DEBUG_INFO_SIZE - used);
+    } else {
+      used += Strncat(buf + used, (char*)((uint8_t*)gbb + gbb->hwid_offset),
+                      DEBUG_INFO_SIZE - used);
+    }
+
+    /* Add recovery request */
+    used += Strncat(buf + used, "\nrecovery_request: 0x",
+                    DEBUG_INFO_SIZE - used);
+    used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+                           shared->recovery_reason, 16, 2);
+
+    /* Add VbSharedData flags */
+    used += Strncat(buf + used, "\nVbSD.flags: 0x", DEBUG_INFO_SIZE - used);
+    used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+                           shared->flags, 16, 8);
+
+    /* Add raw contents of VbNvStorage */
+    used += Strncat(buf + used, "\nVbNv.raw:", DEBUG_INFO_SIZE - used);
+    for (i = 0; i < VBNV_BLOCK_SIZE; i++) {
+      used += Strncat(buf + used, " ", DEBUG_INFO_SIZE - used);
+      used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+                             vnc.raw[i], 16, 2);
+    }
+
+    used += Strncat(buf + used, "\n", DEBUG_INFO_SIZE - used);
+
+    /* TODO: add more interesting data:
+     * - TPM firmware and kernel versions.  In the current code, they're
+     *   only filled into VbSharedData by LoadFirmware() and LoadKernel(), and
+     *   since neither of those is called in the recovery path this isn't
+     *   feasible yet.
+     * - SHA1 of kernel subkey (assuming we always set it in VbSelectFirmware,
+     *   even in recovery mode, where we just copy it from the root key)
      * - Information on current disks
-     * - Anything else interesting from cparams and/or nvram
-     *
-     * TODO: Add a VbExSnprintf() function for this? */
-    return VbExDisplayDebugInfo("Testing 1 2 3\nTesting 4 5 6\n");
+     * - Anything else interesting from VbNvStorage */
+
+    buf[DEBUG_INFO_SIZE - 1] = '\0';
+    VBDEBUG(("VbCheckDisplayKey() wants to show '%s'\n", buf));
+    return VbExDisplayDebugInfo(buf);
 
   } else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key) {
     /* Arrow keys = change localization */
@@ -505,6 +548,9 @@
 
   VBDEBUG(("VbSelectAndLoadKernel() start\n"));
 
+  /* Start timer */
+  shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
+
   VbExNvStorageRead(vnc.raw);
   vnc.raw_changed = 0;
 
@@ -563,6 +609,9 @@
   if (vnc.raw_changed)
     VbExNvStorageWrite(vnc.raw);
 
+  /* Stop timer */
+  shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
+
   VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
 
   /* Pass through return value from boot path */
diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c
index 1022ad9..1e989a4 100644
--- a/firmware/lib/vboot_firmware.c
+++ b/firmware/lib/vboot_firmware.c
@@ -64,9 +64,6 @@
   /* Setup NV storage */
   VbNvSetup(vnc);
 
-  /* Start timer */
-  shared->timer_load_firmware_enter = VbExGetTimer();
-
   /* Handle test errors */
   VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err);
   if (VBNV_TEST_ERROR_LOAD_FIRMWARE == test_err) {
@@ -378,8 +375,6 @@
           recovery : VBNV_RECOVERY_NOT_REQUESTED);
   VbNvTeardown(vnc);
 
-  shared->timer_load_firmware_exit = VbExGetTimer();
-
   /* Note that we don't reduce params->shared_data_size to shared->data_used,
    * since we want to leave space for LoadKernel() to add to the shared data
    * buffer. */
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 26c9121..97d32d3 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -145,7 +145,6 @@
 
   int retval = LOAD_KERNEL_RECOVERY;
   int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
-  uint64_t timer_enter = VbExGetTimer();
 
   /* Setup NV storage */
   VbNvSetup(vnc);
@@ -178,38 +177,23 @@
     dev_switch = 0;  /* Always do a fully verified boot */
   }
 
-  if (kBootRecovery == boot_mode) {
-    /* Initialize the shared data structure, since LoadFirmware() didn't do it
-     * for us. */
-    if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
-      /* Error initializing the shared data, but we can keep going.  We just
-       * can't use the shared data. */
-      VBDEBUG(("Shared data init error\n"));
-      params->shared_data_size = 0;
-      shared = NULL;
-    }
-  }
-
-  if (shared) {
-    /* Set up tracking for this call.  This wraps around if called many times,
-     * so we need to initialize the call entry each time. */
-    shcall = shared->lk_calls + (shared->lk_call_count
-                                 & (VBSD_MAX_KERNEL_CALLS - 1));
-    Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
-    shcall->boot_flags = (uint32_t)params->boot_flags;
-    shcall->boot_mode = boot_mode;
-    shcall->sector_size = (uint32_t)params->bytes_per_lba;
-    shcall->sector_count = params->ending_lba + 1;
-    shared->lk_call_count++;
-  }
+  /* Set up tracking for this call.  This wraps around if called many times,
+   * so we need to initialize the call entry each time. */
+  shcall = shared->lk_calls + (shared->lk_call_count
+                               & (VBSD_MAX_KERNEL_CALLS - 1));
+  Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
+  shcall->boot_flags = (uint32_t)params->boot_flags;
+  shcall->boot_mode = boot_mode;
+  shcall->sector_size = (uint32_t)params->bytes_per_lba;
+  shcall->sector_count = params->ending_lba + 1;
+  shared->lk_call_count++;
 
   /* Handle test errors */
   VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err);
   if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) {
     /* Get error code */
     VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err);
-    if (shcall)
-      shcall->test_error_num = (uint8_t)test_err;
+    shcall->test_error_num = (uint8_t)test_err;
     /* Clear test params so we don't repeat the error */
     VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0);
     VbNvSet(vnc, VBNV_TEST_ERROR_NUM, 0);
@@ -237,11 +221,10 @@
   }
 
   if (kBootDev == boot_mode && !dev_switch) {
-    /* Dev firmware should be signed such that it never boots with the dev
-     * switch is off; so something is terribly wrong. */
+      /* Dev firmware should be signed such that it never boots with the dev
+       * switch is off; so something is terribly wrong. */
     VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n"));
-    if (shcall)
-      shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH;
+    shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH;
     recovery = VBNV_RECOVERY_RW_DEV_MISMATCH;
     goto LoadKernelExit;
   }
@@ -253,17 +236,14 @@
     /* Let the TPM know if we're in recovery mode */
     if (0 != RollbackKernelRecovery(dev_switch)) {
       VBDEBUG(("Error setting up TPM for recovery kernel\n"));
-      if (shcall)
-        shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR;
+      shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR;
       /* Ignore return code, since we need to boot recovery mode to
        * fix the TPM. */
     }
 
     /* Read the key indices from the TPM; ignore any errors */
-    if (shared) {
-      RollbackFirmwareRead(&shared->fw_version_tpm);
-      RollbackKernelRead(&shared->kernel_version_tpm);
-    }
+    RollbackFirmwareRead(&shared->fw_version_tpm);
+    RollbackKernelRead(&shared->kernel_version_tpm);
   } else {
     /* Use the kernel subkey passed from LoadFirmware(). */
     kernel_subkey = &shared->kernel_subkey;
@@ -279,8 +259,7 @@
         recovery = VBNV_RECOVERY_RW_TPM_ERROR;
       goto LoadKernelExit;
     }
-    if (shared)
-      shared->kernel_version_tpm = tpm_version;
+    shared->kernel_version_tpm = tpm_version;
   }
 
   do {
@@ -289,16 +268,14 @@
     gpt.drive_sectors = params->ending_lba + 1;
     if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
       VBDEBUG(("Unable to read GPT data\n"));
-      if (shcall)
-        shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
+      shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
       break;
     }
 
     /* Initialize GPT library */
     if (GPT_SUCCESS != GptInit(&gpt)) {
       VBDEBUG(("Error parsing GPT\n"));
-      if (shcall)
-        shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
+      shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
       break;
     }
 
@@ -323,19 +300,17 @@
       VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
               part_start, part_size));
 
-      if (shcall) {
-        /* Set up tracking for this partition.  This wraps around if called
-         * many times, so initialize the partition entry each time. */
-        shpart = shcall->parts + (shcall->kernel_parts_found
-                                 & (VBSD_MAX_KERNEL_PARTS - 1));
-        Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
-        shpart->sector_start = part_start;
-        shpart->sector_count = part_size;
-        /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
-         * Adjust here, until cgptlib is fixed. */
-        shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
-        shcall->kernel_parts_found++;
-      }
+      /* Set up tracking for this partition.  This wraps around if called
+       * many times, so initialize the partition entry each time. */
+      shpart = shcall->parts + (shcall->kernel_parts_found
+                                & (VBSD_MAX_KERNEL_PARTS - 1));
+      Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
+      shpart->sector_start = part_start;
+      shpart->sector_count = part_size;
+      /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
+       * Adjust here, until cgptlib is fixed. */
+      shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
+      shcall->kernel_parts_found++;
 
       /* Found at least one kernel partition. */
       found_partitions++;
@@ -343,16 +318,14 @@
       /* Read the first part of the kernel partition. */
       if (part_size < kbuf_sectors) {
         VBDEBUG(("Partition too small to hold kernel.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
+        shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
         goto bad_kernel;
       }
 
       if (0 != VbExDiskRead(params->disk_handle, part_start, kbuf_sectors,
                             kbuf)) {
         VBDEBUG(("Unable to read start of partition.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_READ_START;
+        shpart->check_result = VBSD_LKP_CHECK_READ_START;
         goto bad_kernel;
       }
 
@@ -360,8 +333,7 @@
       key_block = (VbKeyBlockHeader*)kbuf;
       if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) {
         VBDEBUG(("Verifying key block signature failed.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
+        shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
 
         key_block_valid = 0;
 
@@ -373,8 +345,7 @@
          * block is valid. */
         if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) {
           VBDEBUG(("Verifying key block hash failed.\n"));
-          if (shpart)
-            shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH;
+          shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH;
           goto bad_kernel;
         }
       }
@@ -384,16 +355,14 @@
             (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
              KEY_BLOCK_FLAG_DEVELOPER_0))) {
         VBDEBUG(("Key block developer flag mismatch.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
+        shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
         key_block_valid = 0;
       }
       if (!(key_block->key_block_flags &
             (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
              KEY_BLOCK_FLAG_RECOVERY_0))) {
         VBDEBUG(("Key block recovery flag mismatch.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
+        shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
         key_block_valid = 0;
       }
 
@@ -402,8 +371,7 @@
       if (kBootRecovery != boot_mode) {
         if (key_version < (tpm_version >> 16)) {
           VBDEBUG(("Key version too old.\n"));
-          if (shpart)
-            shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
+          shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
           key_block_valid = 0;
         }
       }
@@ -418,8 +386,7 @@
       data_key = PublicKeyToRSA(&key_block->data_key);
       if (!data_key) {
         VBDEBUG(("Data key bad.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
+        shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
         goto bad_kernel;
       }
 
@@ -429,8 +396,7 @@
                                      KBUF_SIZE - key_block->key_block_size,
                                      data_key))) {
         VBDEBUG(("Preamble verification failed.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
+        shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
         goto bad_kernel;
       }
 
@@ -438,13 +404,11 @@
        * rollback of the kernel version. */
       combined_version = ((key_version << 16) |
                           (preamble->kernel_version & 0xFFFF));
-      if (shpart)
-        shpart->combined_version = (uint32_t)combined_version;
+      shpart->combined_version = (uint32_t)combined_version;
       if (key_block_valid && kBootRecovery != boot_mode) {
         if (combined_version < tpm_version) {
           VBDEBUG(("Kernel version too low.\n"));
-          if (shpart)
-            shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK;
+          shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK;
           /* If we're not in developer mode, kernel version must be valid. */
           if (kBootDev != boot_mode)
             goto bad_kernel;
@@ -452,8 +416,7 @@
       }
 
       VBDEBUG(("Kernel preamble is good.\n"));
-      if (shpart)
-        shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
+      shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
 
       /* Check for lowest version from a valid header. */
       if (key_block_valid && lowest_version > combined_version)
@@ -473,8 +436,7 @@
       if ((preamble->body_load_address != (size_t)params->kernel_buffer) &&
           !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) {
         VBDEBUG(("Wrong body load address.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS;
+        shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS;
         goto bad_kernel;
       }
 
@@ -482,8 +444,7 @@
       body_offset = key_block->key_block_size + preamble->preamble_size;
       if (0 != body_offset % blba) {
         VBDEBUG(("Kernel body not at multiple of sector size.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
+        shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
         goto bad_kernel;
       }
       body_offset_sectors = body_offset / blba;
@@ -492,16 +453,14 @@
       body_sectors = (preamble->body_signature.data_size + blba - 1) / blba;
       if (body_sectors * blba > params->kernel_buffer_size) {
         VBDEBUG(("Kernel body doesn't fit in memory.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
+        shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
         goto bad_kernel;
       }
 
       /* Verify kernel body fits in the partition */
       if (body_offset_sectors + body_sectors > part_size) {
         VBDEBUG(("Kernel body doesn't fit in partition.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
+        shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
         goto bad_kernel;
       }
 
@@ -512,8 +471,7 @@
                             body_sectors, params->kernel_buffer)) {
         VBDEBUG(("Unable to read kernel data.\n"));
         VBPERFEND("VB_RKD");
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
+        shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
         goto bad_kernel;
       }
       VBPERFEND("VB_RKD");
@@ -523,8 +481,7 @@
                           params->kernel_buffer_size,
                           &preamble->body_signature, data_key)) {
         VBDEBUG(("Kernel data verification failed.\n"));
-        if (shpart)
-          shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
+        shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
         goto bad_kernel;
       }
 
@@ -535,11 +492,9 @@
       /* If we're still here, the kernel is valid. */
       /* Save the first good partition we find; that's the one we'll boot */
       VBDEBUG(("Partition is good.\n"));
-      if (shpart) {
-        shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
-        if (key_block_valid)
-          shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
-      }
+      shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
+      if (key_block_valid)
+        shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
 
       good_partition_key_block_valid = key_block_valid;
       /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
@@ -597,8 +552,7 @@
   /* Handle finding a good partition */
   if (good_partition >= 0) {
     VBDEBUG(("Good_partition >= 0\n"));
-    if (shcall)
-      shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
+    shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
 
     /* See if we need to update the TPM */
     if ((kBootNormal == boot_mode) &&
@@ -619,8 +573,7 @@
             recovery = VBNV_RECOVERY_RW_TPM_ERROR;
           goto LoadKernelExit;
         }
-        if (shared)
-          shared->kernel_version_tpm = (uint32_t)lowest_version;
+        shared->kernel_version_tpm = (uint32_t)lowest_version;
       }
     }
 
@@ -641,10 +594,9 @@
     /* Success! */
     retval = LOAD_KERNEL_SUCCESS;
   } else {
-    if (shcall)
-      shcall->check_result = (found_partitions > 0
-                              ? VBSD_LKC_CHECK_INVALID_PARTITIONS
-                              : VBSD_LKC_CHECK_NO_PARTITIONS);
+    shcall->check_result = (found_partitions > 0
+                            ? VBSD_LKC_CHECK_INVALID_PARTITIONS
+                            : VBSD_LKC_CHECK_NO_PARTITIONS);
 
     /* TODO: differentiate between finding an invalid kernel
      * (found_partitions>0) and not finding one at all.  Right now we
@@ -659,20 +611,14 @@
           recovery : VBNV_RECOVERY_NOT_REQUESTED);
   VbNvTeardown(vnc);
 
-  if (shared) {
-    if (shcall)
-      shcall->return_code = (uint8_t)retval;
+  shcall->return_code = (uint8_t)retval;
 
-    /* Save whether the good partition's key block was fully verified */
-    if (good_partition_key_block_valid)
-      shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
+  /* Save whether the good partition's key block was fully verified */
+  if (good_partition_key_block_valid)
+    shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
 
-    /* Save timer values */
-    shared->timer_load_kernel_enter = timer_enter;
-    shared->timer_load_kernel_exit = VbExGetTimer();
-    /* Store how much shared data we used, if any */
-    params->shared_data_size = shared->data_used;
-  }
+  /* Store how much shared data we used, if any */
+  params->shared_data_size = shared->data_used;
 
   return retval;
 }
diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c
index 49500b7..4aae27d 100644
--- a/firmware/linktest/main.c
+++ b/firmware/linktest/main.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
@@ -65,7 +65,6 @@
   TlclGetPermissions(0, 0);
 
   /* vboot_api.h - entry points INTO vboot_reference */
-  VbS3Resume();
   VbInit(0, 0);
   VbSelectFirmware(0, 0);
   VbUpdateFirmwareBodyHash(0, 0, 0);