vboot: allow firmware to signal a wipeout request

It has become necessary to be able to "factory reset" certain devices
on firmware request. The best mechanism for this is NVRAM, as the
request needs to be detected very early in the boot process, before
other means of communications with the upper layers are available.

A previously unused NVRAM bit (bit 0x08 at offset zero) is taken for
this purpose.

A new flag is introduced to allow the firmware to signal the need to
assert this bit.

A new variable name/parameter ('wipeout_request') added to crossystem
to provide user space access to the setting of the dedicated NVRAM
bit.

BRANCH=storm
BUG=chrome-os-partner:37219
TEST=with all the patches applied, on storm, holding the recovery
     button at startup for 10 seconds, causes 'crossystem
     wipeout_request' to report '1'.

Change-Id: If1f6f061ce5b3f357b92aaa74cb129671dc30446
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/259857
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
(cherry picked from commit 7b50512ccf17f1a0f138c2ef2bb5d3984e0e89de)
Reviewed-on: https://chromium-review.googlesource.com/270004
Reviewed-by: Patrick Sosinski <sosinski@google.com>
Commit-Queue: Patrick Sosinski <sosinski@google.com>
Tested-by: Patrick Sosinski <sosinski@google.com>
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index 5fc7604..53f713b 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -257,6 +257,9 @@
 		vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 0);
 	}
 
+	if (ctx->flags & VB2_CONTEXT_FORCE_WIPEOUT_MODE)
+		vb2_nv_set(ctx, VB2_NV_REQ_WIPEOUT, 1);
+
 	if (flags != old_flags) {
 		/*
 		 * Just changed dev mode state.  Clear TPM owner.  This must be
diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c
index 68a4dad..9e702ab 100644
--- a/firmware/2lib/2nvstorage.c
+++ b/firmware/2lib/2nvstorage.c
@@ -149,6 +149,9 @@
 
 	case VB2_NV_CLEAR_TPM_OWNER_DONE:
 		return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
+
+	case VB2_NV_REQ_WIPEOUT:
+		return GETBIT(VB2_NV_OFFS_HEADER , VB2_NV_HEADER_WIPEOUT);
 	}
 
 	/*
@@ -291,6 +294,10 @@
 	case VB2_NV_CLEAR_TPM_OWNER_DONE:
 		SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
 		break;
+
+	case VB2_NV_REQ_WIPEOUT:
+		SETBIT(VB2_NV_OFFS_HEADER , VB2_NV_HEADER_WIPEOUT);
+		break;
 	}
 
 	/*
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 69f4dde..b3ee6d1 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -87,6 +87,9 @@
 
 	/* RAM should be cleared by caller this boot */
 	VB2_CONTEXT_CLEAR_RAM = (1 << 7),
+
+	/* Wipeout by the app should be requested. */
+	VB2_CONTEXT_FORCE_WIPEOUT_MODE = (1 << 8),
 };
 
 /*
diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h
index 3bda9d7..3b3f34c 100644
--- a/firmware/2lib/include/2nvstorage.h
+++ b/firmware/2lib/include/2nvstorage.h
@@ -78,6 +78,8 @@
 	VB2_NV_FW_PREV_TRIED,
 	/* Result of trying that firmware (see vb2_fw_result) */
 	VB2_NV_FW_PREV_RESULT,
+	/* Request wipeout of the device by the app. */
+	VB2_NV_REQ_WIPEOUT,
 };
 
 /* Firmware result codes for VB2_NV_FW_RESULT and VB2_NV_FW_PREV_RESULT */
diff --git a/firmware/2lib/include/2nvstorage_fields.h b/firmware/2lib/include/2nvstorage_fields.h
index a794f38..1c4fdf4 100644
--- a/firmware/2lib/include/2nvstorage_fields.h
+++ b/firmware/2lib/include/2nvstorage_fields.h
@@ -34,7 +34,8 @@
 	VB2_NV_OFFS_CRC = 15
 };
 
-/* Fields in VB2_NV_OFFS_HEADER (unused = 0x0f) */
+/* Fields in VB2_NV_OFFS_HEADER (unused = 0x07) */
+#define VB2_NV_HEADER_WIPEOUT		       0x08
 #define VB2_NV_HEADER_KERNEL_SETTINGS_RESET    0x10
 #define VB2_NV_HEADER_FW_SETTINGS_RESET        0x20
 #define VB2_NV_HEADER_SIGNATURE                0x40
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h
index 4401777..65cd2e5 100644
--- a/firmware/include/vboot_nvstorage.h
+++ b/firmware/include/vboot_nvstorage.h
@@ -102,6 +102,8 @@
 	VBNV_FW_PREV_TRIED,
 	/* Result of trying that firmware (see vb2_fw_result) */
 	VBNV_FW_PREV_RESULT,
+	/* Wipeout request from firmware present. */
+	VBNV_FW_REQ_WIPEOUT,
 
 } VbNvParam;
 
diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c
index a0721d7..9d99b1c 100644
--- a/firmware/lib/vboot_nvstorage.c
+++ b/firmware/lib/vboot_nvstorage.c
@@ -25,6 +25,7 @@
 #define HEADER_SIGNATURE                0x40
 #define HEADER_FIRMWARE_SETTINGS_RESET  0x20
 #define HEADER_KERNEL_SETTINGS_RESET    0x10
+#define HEADER_WIPEOUT			0x08
 
 #define BOOT_OFFSET                  1
 #define BOOT_DEBUG_RESET_MODE           0x80
@@ -191,6 +192,10 @@
 			>> BOOT2_PREV_RESULT_SHIFT;
 		return 0;
 
+	case VBNV_FW_REQ_WIPEOUT:
+		*dest = (raw[HEADER_OFFSET] & HEADER_WIPEOUT) ? 1 : 0;
+		return 0;
+
 	default:
 		return 1;
 	}
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index 43dcc2a..1eef737 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -496,6 +496,8 @@
     value = VbGetNvStorage(VBNV_OPROM_NEEDED);
   } else if (!strcasecmp(name,"recovery_subcode")) {
     value = VbGetNvStorage(VBNV_RECOVERY_SUBCODE);
+  } else if (!strcasecmp(name,"wipeout_request")) {
+    value = VbGetNvStorage(VBNV_FW_REQ_WIPEOUT);
   }
   /* Other parameters */
   else if (!strcasecmp(name,"cros_debug")) {
diff --git a/utility/crossystem.c b/utility/crossystem.c
index 41ed849..adc828d 100644
--- a/utility/crossystem.c
+++ b/utility/crossystem.c
@@ -94,6 +94,7 @@
   {"vdat_lkdebug", IS_STRING|NO_PRINT_ALL,
    "LoadKernel() debug data (not in print-all)"},
   {"vdat_timers", IS_STRING, "Timer values from VbSharedData"},
+  {"wipeout_request", 0, "Firmware requested factory reset (wipeout)"},
   {"wpsw_boot", 0, "Firmware write protect hardware switch position at boot"},
   {"wpsw_cur", 0, "Firmware write protect hardware switch current position"},
   /* Terminate with null name */