Add more specific recovery reasons for RW firmware invalid (with fix)

BUG=chrome-os-partner:3698
TEST=manual

1. Run the firmware key/version autoupdate test; this rolls forward your stored TPM version numbers.
2. Put back the original firmware.
3. Reboot.
4. Press TAB at recovery screen.
5. Should see Recovery Reason 0x14.

Reviewed-on: http://gerrit.chromium.org/gerrit/567
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
(cherry picked from commit 9243e616d727c3e57525f8dec2b5f22840900451)

Also:

Fix build break

BUG=none
TEST=emerge-x86-generic vboot_reference

Reviewed-on: http://gerrit.chromium.org/gerrit/608
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
(cherry picked from commit 4dd03035c2cd9deeaebac68bf7181fe50dc30237)

Change-Id: Ifbf26ee58169f707a776e1528a3638d5f1ef88dc
Reviewed-on: http://gerrit.chromium.org/gerrit/1059
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Tested-by: Bill Richardson <wfrichar@chromium.org>
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h
index c2a722f..6018349 100644
--- a/firmware/include/vboot_nvstorage.h
+++ b/firmware/include/vboot_nvstorage.h
@@ -80,6 +80,12 @@
 #define VBNV_RECOVERY_RO_TEST_LFS     0x08
 /* Test error from LoadFirmware() */
 #define VBNV_RECOVERY_RO_TEST_LF      0x09
+/* RW firmware failed signature check (neither RW firmware slot was valid).
+ * Recovery reason is VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + the check value
+ * for the slot which came closest to validating; see VBSD_LF_CHECK_* in
+ * vboot_struct.h. */
+#define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN  0x10
+#define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX  0x1F
 /* 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/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c
index 4be4cb2..d56cba7 100644
--- a/firmware/lib/vboot_firmware.c
+++ b/firmware/lib/vboot_firmware.c
@@ -368,9 +368,20 @@
     shared->firmware_index = (uint8_t)params->firmware_index;
     retval = LOAD_FIRMWARE_SUCCESS;
   } else {
+    uint8_t a = shared->check_fw_a_result;
+    uint8_t b = shared->check_fw_b_result;
+    uint8_t best_check;
+
     /* No good firmware, so go to recovery mode. */
     VBDEBUG(("Alas, no good firmware.\n"));
     recovery = VBNV_RECOVERY_RO_INVALID_RW;
+
+    /* If the best check result fits in the range of recovery reasons, provide
+     * more detail on how far we got in validation. */
+    best_check = (a > b ? a : b) + VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN;
+    if (best_check >= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN &&
+        best_check <= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX)
+      recovery = best_check;
   }
 
 LoadFirmwareExit: