vboot: move recovery reason strings to vboot2 namespace

Make recovery reason strings more widely available, and
print them in kernel verification console messages.
Note that we purposely do not print strings in firmware
verification in order to avoid linking recovery reason
strings into coreboot stages.

BUG=b:124141368, chromium:968464
TEST=make clean && make runtests
TEST=trigger recovery, check console logs
BRANCH=none

Change-Id: Ica82a60075da53e4ad0a0403eb8a88685c3bdbd6
Signed-off-by: Joel Kitching <kitching@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2112321
Reviewed-by: Joel Kitching <kitching@chromium.org>
Commit-Queue: Joel Kitching <kitching@chromium.org>
Tested-by: Joel Kitching <kitching@chromium.org>
diff --git a/Makefile b/Makefile
index 913f4ac..cee35bd 100644
--- a/Makefile
+++ b/Makefile
@@ -361,6 +361,7 @@
 	firmware/2lib/2kernel.c \
 	firmware/2lib/2misc.c \
 	firmware/2lib/2nvstorage.c \
+	firmware/2lib/2recovery_reasons.c \
 	firmware/2lib/2rsa.c \
 	firmware/2lib/2secdata_firmware.c \
 	firmware/2lib/2secdata_fwmp.c \
@@ -486,6 +487,7 @@
 	firmware/2lib/2hmac.c \
 	firmware/2lib/2kernel.c \
 	firmware/2lib/2nvstorage.c \
+	firmware/2lib/2recovery_reasons.c \
 	firmware/2lib/2rsa.c \
 	firmware/2lib/2sha1.c \
 	firmware/2lib/2sha256.c \
@@ -707,6 +709,7 @@
 	tests/vb2_misc_tests \
 	tests/vb2_nvstorage_tests \
 	tests/vb2_rsa_utility_tests \
+	tests/vb2_recovery_reasons_tests \
 	tests/vb2_secdata_firmware_tests \
 	tests/vb2_secdata_fwmp_tests \
 	tests/vb2_secdata_kernel_tests \
@@ -883,6 +886,7 @@
 	${Q}${INSTALL} -t ${UI_DIR} -m644 \
 		host/include/* \
 		firmware/2lib/include/2crypto.h \
+		firmware/2lib/include/2recovery_reasons.h \
 		firmware/2lib/include/2sysincludes.h \
 		firmware/include/gpt.h \
 		firmware/include/tlcl.h \
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index 2df4f2e..7a2def3 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -9,6 +9,7 @@
 #include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
+#include "2recovery_reasons.h"
 #include "2rsa.h"
 #include "2secdata.h"
 #include "2sha.h"
@@ -160,7 +161,7 @@
 	/* If recovery reason is non-zero, tell caller we need recovery mode */
 	if (sd->recovery_reason) {
 		ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
-		VB2_DEBUG("We have a recovery request: %#x / %#x\n",
+		VB2_DEBUG("We have a recovery request: %#x / %#xn",
 			  sd->recovery_reason,
 			  vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE));
 	}
@@ -422,8 +423,9 @@
 	uint32_t subcode = vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE);
 
 	if (reason || subcode)
-		VB2_DEBUG("Clearing recovery request: %#x / %#x\n",
-			  reason, subcode);
+		VB2_DEBUG("Clearing recovery request: %#x / %#x  %s\n",
+			  reason, subcode,
+			  vb2_get_recovery_reason_string(reason));
 
 	/* Clear recovery request for both manual and non-manual. */
 	vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, VB2_RECOVERY_NOT_REQUESTED);
diff --git a/firmware/2lib/2recovery_reasons.c b/firmware/2lib/2recovery_reasons.c
new file mode 100644
index 0000000..bf64d51
--- /dev/null
+++ b/firmware/2lib/2recovery_reasons.c
@@ -0,0 +1,179 @@
+/* Copyright 2020 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.
+ *
+ * Recovery reason string mapping.
+ */
+
+#include "2recovery_reasons.h"
+#include "2sysincludes.h"
+
+const char *vb2_get_recovery_reason_string(uint8_t code)
+{
+	switch ((enum vb2_nv_recovery)code) {
+	/* 0x00 */ case VB2_RECOVERY_NOT_REQUESTED:
+		return "Recovery not requested";
+	/* 0x01 */ case VB2_RECOVERY_LEGACY:
+		return "Recovery requested from legacy utility";
+	/* 0x02 */ case VB2_RECOVERY_RO_MANUAL:
+		return "Recovery button pressed";
+	/* 0x03 */ case VB2_RECOVERY_RO_INVALID_RW:
+		return "RW firmware failed signature check";
+	/* 0x04 */ case VB2_RECOVERY_DEPRECATED_RO_S3_RESUME:
+		return "S3 resume failed";
+	/* 0x05 */ case VB2_RECOVERY_DEPRECATED_RO_TPM_ERROR:
+		return "TPM error in read-only firmware";
+	/* 0x06 */ case VB2_RECOVERY_RO_SHARED_DATA:
+		return "Shared data error in read-only firmware";
+	/* 0x07 */ case VB2_RECOVERY_DEPRECATED_RO_TEST_S3:
+		return "Test error from S3Resume()";
+	/* 0x08 */ case VB2_RECOVERY_DEPRECATED_RO_TEST_LFS:
+		return "Test error from LoadFirmwareSetup()";
+	/* 0x09 */ case VB2_RECOVERY_DEPRECATED_RO_TEST_LF:
+		return "Test error from LoadFirmware()";
+	/* 0x10 */ case VB2_RECOVERY_DEPRECATED_RW_NOT_DONE:
+		return "RW firmware check not done";
+	/* 0x11 */ case VB2_RECOVERY_DEPRECATED_RW_DEV_FLAG_MISMATCH:
+		return "RW firmware developer flag mismatch";
+	/* 0x12 */ case VB2_RECOVERY_DEPRECATED_RW_REC_FLAG_MISMATCH:
+		return "RW firmware recovery flag mismatch";
+	/* 0x13 */ case VB2_RECOVERY_FW_KEYBLOCK:
+		return "RW firmware unable to verify keyblock";
+	/* 0x14 */ case VB2_RECOVERY_FW_KEY_ROLLBACK:
+		return "RW firmware key version rollback detected";
+	/* 0x15 */ case VB2_RECOVERY_DEPRECATED_RW_DATA_KEY_PARSE:
+		return "RW firmware unable to parse data key";
+	/* 0x16 */ case VB2_RECOVERY_FW_PREAMBLE:
+		return "RW firmware unable to verify preamble";
+	/* 0x17 */ case VB2_RECOVERY_FW_ROLLBACK:
+		return "RW firmware version rollback detected";
+	/* 0x18 */ case VB2_RECOVERY_DEPRECATED_FW_HEADER_VALID:
+		return "RW firmware header is valid";
+	/* 0x19 */ case VB2_RECOVERY_DEPRECATED_FW_GET_FW_BODY:
+		return "RW firmware unable to get firmware body";
+	/* 0x1a */ case VB2_RECOVERY_DEPRECATED_FW_HASH_WRONG_SIZE:
+		return "RW firmware hash is wrong size";
+	/* 0x1b */ case VB2_RECOVERY_FW_BODY:
+		return "RW firmware unable to verify firmware body";
+	/* 0x1c */ case VB2_RECOVERY_DEPRECATED_FW_VALID:
+		return "RW firmware is valid";
+	/* 0x1d */ case VB2_RECOVERY_DEPRECATED_FW_NO_RO_NORMAL:
+		return "RW firmware read-only normal path is not supported";
+	/* 0x20 */ case VB2_RECOVERY_RO_FIRMWARE:
+		return "Firmware problem outside of verified boot";
+	/* 0x21 */ case VB2_RECOVERY_RO_TPM_REBOOT:
+		return "TPM requires a system reboot (should be transient)";
+	/* 0x22 */ case VB2_RECOVERY_EC_SOFTWARE_SYNC:
+		return "EC software sync error";
+	/* 0x23 */ case VB2_RECOVERY_EC_UNKNOWN_IMAGE:
+		return "EC software sync unable to determine active EC image";
+	/* 0x24 */ case VB2_RECOVERY_DEPRECATED_EC_HASH:
+		return "EC software sync error obtaining EC image hash";
+	/* 0x25 */ case VB2_RECOVERY_DEPRECATED_EC_EXPECTED_IMAGE:
+		return "EC software sync error "
+			"obtaining expected EC image from BIOS";
+	/* 0x26 */ case VB2_RECOVERY_EC_UPDATE:
+		return "EC software sync error updating EC";
+	/* 0x27 */ case VB2_RECOVERY_EC_JUMP_RW:
+		return "EC software sync unable to jump to EC-RW";
+	/* 0x28 */ case VB2_RECOVERY_EC_PROTECT:
+		return "EC software sync protection error";
+	/* 0x29 */ case VB2_RECOVERY_EC_EXPECTED_HASH:
+		return "EC software sync error "
+			"obtaining expected EC hash from BIOS";
+	/* 0x2a */ case VB2_RECOVERY_DEPRECATED_EC_HASH_MISMATCH:
+		return "EC software sync error "
+			"comparing expected EC hash and image";
+	/* 0x2b */ case VB2_RECOVERY_SECDATA_FIRMWARE_INIT:
+		return "Firmware secure NVRAM (TPM) initialization error";
+	/* 0x2c */ case VB2_RECOVERY_GBB_HEADER:
+		return "Error parsing GBB header";
+	/* 0x2d */ case VB2_RECOVERY_TPM_CLEAR_OWNER:
+		return "Error trying to clear TPM owner";
+	/* 0x2e */ case VB2_RECOVERY_DEV_SWITCH:
+		return "Error reading or updating developer switch";
+	/* 0x2f */ case VB2_RECOVERY_FW_SLOT:
+		return "Error selecting RW firmware slot";
+	/* 0x30 */ case VB2_RECOVERY_AUX_FW_UPDATE:
+		return "Error updating AUX firmware";
+	/* 0x3f */ case VB2_RECOVERY_RO_UNSPECIFIED:
+		return "Unspecified/unknown error in RO firmware";
+	/* 0x41 */ case VB2_RECOVERY_DEPRECATED_RW_DEV_SCREEN:
+		return "User requested recovery from dev-mode warning screen";
+	/* 0x42 */ case VB2_RECOVERY_DEPRECATED_RW_NO_OS:
+		return "No OS kernel detected (or kernel rollback attempt?)";
+	/* 0x43 */ case VB2_RECOVERY_RW_INVALID_OS:
+		return "OS kernel or rootfs failed signature check";
+	/* 0x44 */ case VB2_RECOVERY_DEPRECATED_RW_TPM_ERROR:
+		return "TPM error in rewritable firmware";
+	/* 0x45 */ case VB2_RECOVERY_DEPRECATED_RW_DEV_MISMATCH:
+		return "RW firmware in dev mode, but dev switch is off";
+	/* 0x46 */ case VB2_RECOVERY_RW_SHARED_DATA:
+		return "Shared data error in rewritable firmware";
+	/* 0x47 */ case VB2_RECOVERY_DEPRECATED_RW_TEST_LK:
+		return "Test error from LoadKernel()";
+	/* 0x48 */ case VB2_RECOVERY_DEPRECATED_RW_NO_DISK:
+		return "No bootable storage device in system";
+	/* 0x49 */ case VB2_RECOVERY_TPM_E_FAIL:
+		return "TPM error that was not fixed by reboot";
+	/* 0x50 */ case VB2_RECOVERY_RO_TPM_S_ERROR:
+		return "TPM setup error in read-only firmware";
+	/* 0x51 */ case VB2_RECOVERY_RO_TPM_W_ERROR:
+		return "TPM write error in read-only firmware";
+	/* 0x52 */ case VB2_RECOVERY_RO_TPM_L_ERROR:
+		return "TPM lock error in read-only firmware";
+	/* 0x53 */ case VB2_RECOVERY_RO_TPM_U_ERROR:
+		return "TPM update error in read-only firmware";
+	/* 0x54 */ case VB2_RECOVERY_RW_TPM_R_ERROR:
+		return "TPM read error in rewritable firmware";
+	/* 0x55 */ case VB2_RECOVERY_RW_TPM_W_ERROR:
+		return "TPM write error in rewritable firmware";
+	/* 0x56 */ case VB2_RECOVERY_RW_TPM_L_ERROR:
+		return "TPM lock error in rewritable firmware";
+	/* 0x57 */ case VB2_RECOVERY_EC_HASH_FAILED:
+		return "EC software sync unable to get EC image hash";
+	/* 0x58 */ case VB2_RECOVERY_EC_HASH_SIZE:
+		return "EC software sync invalid image hash size";
+	/* 0x59 */ case VB2_RECOVERY_LK_UNSPECIFIED:
+		return "Unspecified error while trying to load kernel";
+	/* 0x5a */ case VB2_RECOVERY_RW_NO_DISK:
+		return "No bootable storage device in system";
+	/* 0x5b */ case VB2_RECOVERY_RW_NO_KERNEL:
+		return "No bootable kernel found on disk";
+	/* 0x5c */ case VB2_RECOVERY_DEPRECATED_RW_BCB_ERROR:
+		return "BCB partition error on disk";
+	/* 0x5d */ case VB2_RECOVERY_SECDATA_KERNEL_INIT:
+		return "Kernel secure NVRAM (TPM) initialization error";
+	/* 0x5e */ case VB2_RECOVERY_DEPRECATED_FW_FASTBOOT:
+		return "Fastboot-mode requested in firmware";
+	/* 0x5f */ case VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR:
+		return "Recovery hash space lock error in RO firmware";
+	/* 0x60 */ case VB2_RECOVERY_TPM_DISABLE_FAILED:
+		return "Failed to disable TPM before running untrusted code";
+	/* 0x61 */ case VB2_RECOVERY_ALTFW_HASH_FAILED:
+		return "Verification of alternative firmware payload failed";
+	/* 0x62 */ case VB2_RECOVERY_SECDATA_FWMP_INIT:
+		return "FWMP secure NVRAM (TPM) initialization error";
+	/* 0x63 */ case VB2_RECOVERY_CR50_BOOT_MODE:
+		return "Failed to get boot mode from Cr50";
+	/* 0x64 */ case VB2_RECOVERY_ESCAPE_NO_BOOT:
+		return "Attempt to escape from NO_BOOT mode was detected";
+	/* 0x7f */ case VB2_RECOVERY_RW_UNSPECIFIED:
+		return "Unspecified/unknown error in RW firmware";
+	/* 0x81 */ case VB2_RECOVERY_DEPRECATED_KE_DM_VERITY:
+		return "DM-verity error";
+	/* 0xbf */ case VB2_RECOVERY_DEPRECATED_KE_UNSPECIFIED:
+		return "Unspecified/unknown error in kernel";
+	/* 0xc1 */ case VB2_RECOVERY_US_TEST:
+		return "Recovery mode test from user-mode";
+	/* 0xc2 */ case VB2_RECOVERY_DEPRECATED_BCB_USER_MODE:
+		return "User-mode requested recovery via BCB";
+	/* 0xc3 */ case VB2_RECOVERY_DEPRECATED_US_FASTBOOT:
+		return "User-mode requested fastboot mode";
+	/* 0xc4 */ case VB2_RECOVERY_TRAIN_AND_REBOOT:
+		return "User-mode requested DRAM train and reboot";
+	/* 0xff */ case VB2_RECOVERY_US_UNSPECIFIED:
+		return "Unspecified/unknown error in user-mode";
+	}
+	return "Unknown error code";
+}
diff --git a/firmware/2lib/include/2recovery_reasons.h b/firmware/2lib/include/2recovery_reasons.h
index 99ed478..de64e59 100644
--- a/firmware/2lib/include/2recovery_reasons.h
+++ b/firmware/2lib/include/2recovery_reasons.h
@@ -2,12 +2,22 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  *
- * Recovery reasons
+ * Recovery reasons.
  */
 
 #ifndef VBOOT_REFERENCE_2RECOVERY_REASONS_H_
 #define VBOOT_REFERENCE_2RECOVERY_REASONS_H_
 
+#include "2sysincludes.h"
+
+/**
+ * Return a description of the recovery reason code.
+ *
+ * @param		recovery reason code
+ * @returns A string literal with English description of the recovery reason
+ */
+const char *vb2_get_recovery_reason_string(uint8_t code);
+
 /* Recovery reason codes */
 enum vb2_nv_recovery {
 
@@ -56,11 +66,17 @@
 
 	/*
 	 * RW firmware failed signature check (neither RW firmware slot was
-	 * valid).  Recovery reason is VB2_RECOVERY_RO_INVALID_RW_CHECK_MIN +
+	 * valid).  Recovery reason is VB2_RECOVERY_DEPRECATED_RW_NOT_DONE +
 	 * the check value for the slot which came closest to validating; see
 	 * VBSD_LF_CHECK_* in vboot_struct.h (deprecated).
 	 */
-	VB2_RECOVERY_DEPRECATED_RO_INVALID_RW_CHECK_MIN = 0x10,
+	VB2_RECOVERY_DEPRECATED_RW_NOT_DONE = 0x10,
+
+	/* Latest tried RW firmware developer flag mismatch */
+	VB2_RECOVERY_DEPRECATED_RW_DEV_FLAG_MISMATCH = 0x11,
+
+	/* Latest tried RW firmware recovery flag mismatch */
+	VB2_RECOVERY_DEPRECATED_RW_REC_FLAG_MISMATCH = 0x12,
 
 	/* Latest tried RW firmware keyblock verification failed */
 	VB2_RECOVERY_FW_KEYBLOCK = 0x13,
@@ -68,17 +84,32 @@
 	/* Latest tried RW firmware key version too old */
 	VB2_RECOVERY_FW_KEY_ROLLBACK = 0x14,
 
+	/* Latest tried RW firmware unable to parse data key */
+	VB2_RECOVERY_DEPRECATED_RW_DATA_KEY_PARSE = 0x15,
+
 	/* Latest tried RW firmware preamble verification failed */
 	VB2_RECOVERY_FW_PREAMBLE = 0x16,
 
 	/* Latest tried RW firmware version too old */
 	VB2_RECOVERY_FW_ROLLBACK = 0x17,
 
+	/* Latest tried RW firmware header valid */
+	VB2_RECOVERY_DEPRECATED_FW_HEADER_VALID = 0x18,
+
+	/* Latest tried RW firmware unable to get firmware body */
+	VB2_RECOVERY_DEPRECATED_FW_GET_FW_BODY = 0x19,
+
+	/* Latest tried RW firmware hash wrong size */
+	VB2_RECOVERY_DEPRECATED_FW_HASH_WRONG_SIZE = 0x1a,
+
 	/* Latest tried RW firmware body verification failed */
 	VB2_RECOVERY_FW_BODY = 0x1b,
 
-	/* Highest reason for failed RW firmware signature check */
-	VB2_RECOVERY_RO_INVALID_RW_CHECK_MAX = 0x1f,
+	/* Latest tried RW firmware valid */
+	VB2_RECOVERY_DEPRECATED_FW_VALID = 0x1c,
+
+	/* Latest tried RW firmware RO normal path not supported */
+	VB2_RECOVERY_DEPRECATED_FW_NO_RO_NORMAL = 0x1d,
 
 	/*
 	 * Firmware boot failure outside of verified boot (RAM init, missing
diff --git a/firmware/lib/include/vboot_display.h b/firmware/lib/include/vboot_display.h
index 8621d86..c5af967 100644
--- a/firmware/lib/include/vboot_display.h
+++ b/firmware/lib/include/vboot_display.h
@@ -17,9 +17,4 @@
 vb2_error_t VbCheckDisplayKey(struct vb2_context *ctx, uint32_t key,
 			    const VbScreenData *data);
 
-/**
- * Return a description of the recovery reason code.
- */
-const char *RecoveryReasonString(uint8_t code);
-
 #endif  /* VBOOT_REFERENCE_VBOOT_DISPLAY_H_ */
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index 07e1da0..e10a421 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -8,6 +8,7 @@
 #include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
+#include "2recovery_reasons.h"
 #include "2sha.h"
 #include "2sysincludes.h"
 #include "vboot_api.h"
@@ -107,114 +108,6 @@
 	*outbuf = '\0';
 }
 
-const char *RecoveryReasonString(uint8_t code)
-{
-	switch(code) {
-	case VB2_RECOVERY_NOT_REQUESTED:
-		return "Recovery not requested";
-	case VB2_RECOVERY_LEGACY:
-		return "Recovery requested from legacy utility";
-	case VB2_RECOVERY_RO_MANUAL:
-		return "recovery button pressed";
-	case VB2_RECOVERY_RO_INVALID_RW:
-		return "RW firmware failed signature check";
-	case VB2_RECOVERY_RO_SHARED_DATA:
-		return "Shared data error in read-only firmware";
-	case VB2_RECOVERY_FW_KEYBLOCK:
-		return "RW firmware unable to verify keyblock";
-	case VB2_RECOVERY_FW_KEY_ROLLBACK:
-		return "RW firmware key version rollback detected";
-	case VB2_RECOVERY_FW_PREAMBLE:
-		return "RW firmware unable to verify preamble";
-	case VB2_RECOVERY_FW_ROLLBACK:
-		return "RW firmware version rollback detected";
-	case VB2_RECOVERY_FW_BODY:
-		return "RW firmware unable to verify firmware body";
-	case VB2_RECOVERY_RO_FIRMWARE:
-		return "Firmware problem outside of verified boot";
-	case VB2_RECOVERY_RO_TPM_REBOOT:
-		return "TPM requires a system reboot (should be transient)";
-	case VB2_RECOVERY_EC_SOFTWARE_SYNC:
-		return "EC software sync error";
-	case VB2_RECOVERY_EC_UNKNOWN_IMAGE:
-		return "EC software sync unable to determine active EC image";
-	case VB2_RECOVERY_EC_UPDATE:
-		return "EC software sync error updating EC";
-	case VB2_RECOVERY_EC_JUMP_RW:
-		return "EC software sync unable to jump to EC-RW";
-	case VB2_RECOVERY_EC_PROTECT:
-		return "EC software sync protection error";
-	case VB2_RECOVERY_EC_EXPECTED_HASH:
-		return "EC software sync error "
-			"obtaining expected EC hash from BIOS";
-	case VB2_RECOVERY_SECDATA_FIRMWARE_INIT:
-		return "Firmware secure NVRAM (TPM) initialization error";
-	case VB2_RECOVERY_GBB_HEADER:
-		return "Error parsing GBB header";
-	case VB2_RECOVERY_TPM_CLEAR_OWNER:
-		return "Error trying to clear TPM owner";
-	case VB2_RECOVERY_DEV_SWITCH:
-		return "Error reading or updating developer switch";
-	case VB2_RECOVERY_FW_SLOT:
-		return "Error selecting RW firmware slot";
-	case VB2_RECOVERY_AUX_FW_UPDATE:
-		return "Error updating AUX firmware";
-	case VB2_RECOVERY_RO_UNSPECIFIED:
-		return "Unspecified/unknown error in RO firmware";
-	case VB2_RECOVERY_RW_INVALID_OS:
-		return "OS kernel or rootfs failed signature check";
-	case VB2_RECOVERY_RW_SHARED_DATA:
-		return "Shared data error in rewritable firmware";
-	case VB2_RECOVERY_TPM_E_FAIL:
-		return "TPM error that was not fixed by reboot";
-	case VB2_RECOVERY_RO_TPM_S_ERROR:
-		return "TPM setup error in read-only firmware";
-	case VB2_RECOVERY_RO_TPM_W_ERROR:
-		return "TPM write error in read-only firmware";
-	case VB2_RECOVERY_RO_TPM_L_ERROR:
-		return "TPM lock error in read-only firmware";
-	case VB2_RECOVERY_RO_TPM_U_ERROR:
-		return "TPM update error in read-only firmware";
-	case VB2_RECOVERY_RW_TPM_R_ERROR:
-		return "TPM read error in rewritable firmware";
-	case VB2_RECOVERY_RW_TPM_W_ERROR:
-		return "TPM write error in rewritable firmware";
-	case VB2_RECOVERY_RW_TPM_L_ERROR:
-		return "TPM lock error in rewritable firmware";
-	case VB2_RECOVERY_EC_HASH_FAILED:
-		return "EC software sync unable to get EC image hash";
-	case VB2_RECOVERY_EC_HASH_SIZE:
-		return "EC software sync invalid image hash size";
-	case VB2_RECOVERY_LK_UNSPECIFIED:
-		return "Unspecified error while trying to load kernel";
-	case VB2_RECOVERY_RW_NO_DISK:
-		return "No bootable storage device in system";
-	case VB2_RECOVERY_RW_NO_KERNEL:
-		return "No bootable kernel found on disk";
-	case VB2_RECOVERY_SECDATA_KERNEL_INIT:
-		return "Kernel secure NVRAM (TPM) initialization error";
-	case VB2_RECOVERY_RO_TPM_REC_HASH_L_ERROR:
-		return "Recovery hash space lock error in RO firmware";
-	case VB2_RECOVERY_TPM_DISABLE_FAILED:
-		return "Failed to disable TPM before running untrusted code";
-	case VB2_RECOVERY_ALTFW_HASH_FAILED:
-		return "Verification of alternative firmware payload failed";
-	case VB2_RECOVERY_CR50_BOOT_MODE:
-		return "Failed to get boot mode from Cr50";
-	case VB2_RECOVERY_ESCAPE_NO_BOOT:
-		return "Attempt to escape from NO_BOOT mode was detected";
-	case VB2_RECOVERY_RW_UNSPECIFIED:
-		return "Unspecified/unknown error in RW firmware";
-	case VB2_RECOVERY_US_TEST:
-		return "Recovery mode test from user-mode";
-	case VB2_RECOVERY_TRAIN_AND_REBOOT:
-		return "User-mode requested DRAM train and reboot";
-	case VB2_RECOVERY_US_UNSPECIFIED:
-		return "Unspecified/unknown error in user-mode";
-	}
-	return "Unknown or deprecated error code";
-}
-
 #define DEBUG_INFO_SIZE 1024
 #define DEBUG_INFO_APPEND(format, args...) do { \
 	if (used < DEBUG_INFO_SIZE) \
@@ -249,7 +142,7 @@
 	i = vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE);
 	DEBUG_INFO_APPEND("\nrecovery_reason: %#.2x / %#.2x  %s",
 			  sd->recovery_reason, i,
-			  RecoveryReasonString(sd->recovery_reason));
+			  vb2_get_recovery_reason_string(sd->recovery_reason));
 
 	/* Add vb2_context and vb2_shared_data flags */
 	DEBUG_INFO_APPEND("\ncontext.flags: %#.16" PRIx64, ctx->flags);
diff --git a/tests/vb2_recovery_reasons_tests.c b/tests/vb2_recovery_reasons_tests.c
new file mode 100644
index 0000000..c1cb95b
--- /dev/null
+++ b/tests/vb2_recovery_reasons_tests.c
@@ -0,0 +1,31 @@
+/* Copyright 2020 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.
+ *
+ * Tests for recovery reasons.
+ */
+
+#include "2recovery_reasons.h"
+#include "test_common.h"
+
+static void get_recovery_reason_string_tests(void)
+{
+	int i;
+
+	/* Recovery string should be non-null for any code */
+	for (i = 0; i < 0x100; i++)
+		TEST_PTR_NEQ(vb2_get_recovery_reason_string(i), NULL,
+			     "Non-null reason");
+
+	/* Sanity check on one of the strings */
+	TEST_EQ(strcmp(vb2_get_recovery_reason_string(VB2_RECOVERY_GBB_HEADER),
+		       "Error parsing GBB header"), 0,
+		"Recovery reason sanity check");
+}
+
+int main(void)
+{
+	get_recovery_reason_string_tests();
+
+	return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_display_tests.c b/tests/vboot_display_tests.c
index a640556..b57915f 100644
--- a/tests/vboot_display_tests.c
+++ b/tests/vboot_display_tests.c
@@ -73,12 +73,6 @@
 /* Test displaying debug info */
 static void DebugInfoTest(void)
 {
-	int i;
-
-	/* Recovery string should be non-null for any code */
-	for (i = 0; i < 0x100; i++)
-		TEST_PTR_NEQ(RecoveryReasonString(i), NULL, "Non-null reason");
-
 	/* Display debug info */
 	ResetMocks();
 	TEST_SUCC(VbDisplayDebugInfo(ctx),