nvstorage: Add new flag VBNV_DEV_BOOT_FASTBOOT_FULL_CAP

Add a new flag to nvstorage for controlling fastboot capabilities
offered in firmware in dev-mode. By default, value of this flag would
be ignored in normal mode. Thus, when fastboot-based recovery is
entered from normal mode, only limited capability would be available
in firmware.

After switching to dev-mode, this flag can be set automatically by
user script after performing the wipe or it can be set manually using
crossystem. When fastboot-based recovery is entered from dev mode and
this flag is set, it will provide full fastboot capability in the
firmware.

BUG=chrome-os-partner:40196
BRANCH=None
TEST=Compiles successfully for smaug. make runalltests successful.

Change-Id: I761a9ab304dd90f0b73081acc9ce1f8d9052325f
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://chromium-review.googlesource.com/271369
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Furquan Shaikh <furquan@chromium.org>
Trybot-Ready: Furquan Shaikh <furquan@chromium.org>
Tested-by: Furquan Shaikh <furquan@chromium.org>
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h
index 65cd2e5..7f01735 100644
--- a/firmware/include/vboot_nvstorage.h
+++ b/firmware/include/vboot_nvstorage.h
@@ -72,6 +72,11 @@
 	/* Only boot Google-signed images in developer mode.  0=no, 1=yes. */
 	VBNV_DEV_BOOT_SIGNED_ONLY,
 	/*
+	 * Allow full fastboot capability in firmware in developer mode.
+	 * 0=no, 1=yes.
+	 */
+	VBNV_DEV_BOOT_FASTBOOT_FULL_CAP,
+	/*
 	 * Set by userspace to request that RO firmware disable dev-mode on the
 	 * next boot. This is likely only possible if the dev-switch is
 	 * virtual.
diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c
index ce89715..4371042 100644
--- a/firmware/lib/vboot_api_init.c
+++ b/firmware/lib/vboot_api_init.c
@@ -320,6 +320,7 @@
 		VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
 		VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0);
 		VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0);
+		VbNvSet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, 0);
 		/*
 		 * Back up any changes now, so these values can't be forgotten
 		 * by draining the battery. We really only care about these
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index 26fa8bd..311a1c9 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -564,6 +564,12 @@
 			DEBUG_INFO_SIZE - used);
 	used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
 
+	/* Add dev_boot_fastboot_full_cap flag */
+	VbNvGet(vncptr, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, &i);
+	used += StrnAppend(buf + used, "\ndev_boot_fastboot_full_cap: ",
+			DEBUG_INFO_SIZE - used);
+	used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
+
 	/* Add TPM versions */
 	used += StrnAppend(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used);
 	used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c
index af24fac..ebf796e 100644
--- a/firmware/lib/vboot_nvstorage.c
+++ b/firmware/lib/vboot_nvstorage.c
@@ -41,6 +41,7 @@
 #define DEV_BOOT_USB_MASK               0x01
 #define DEV_BOOT_SIGNED_ONLY_MASK       0x02
 #define DEV_BOOT_LEGACY_MASK            0x04
+#define DEV_BOOT_FASTBOOT_FULL_CAP_MASK 0x08
 
 #define TPM_FLAGS_OFFSET             5
 #define TPM_CLEAR_OWNER_REQUEST         0x01
@@ -150,6 +151,11 @@
 			 1 : 0);
 		return 0;
 
+	case VBNV_DEV_BOOT_FASTBOOT_FULL_CAP:
+		*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_FASTBOOT_FULL_CAP_MASK
+			 ? 1 : 0);
+		return 0;
+
 	case VBNV_DISABLE_DEV_REQUEST:
 		*dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0);
 		return 0;
@@ -292,6 +298,15 @@
 			raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK;
 		break;
 
+	case VBNV_DEV_BOOT_FASTBOOT_FULL_CAP:
+		if (value)
+			raw[DEV_FLAGS_OFFSET] |=
+				DEV_BOOT_FASTBOOT_FULL_CAP_MASK;
+		else
+			raw[DEV_FLAGS_OFFSET] &=
+				~DEV_BOOT_FASTBOOT_FULL_CAP_MASK;
+		break;
+
 	case VBNV_DISABLE_DEV_REQUEST:
 		if (value)
 			raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST;
diff --git a/firmware/lib/vboot_nvstorage_rollback.c b/firmware/lib/vboot_nvstorage_rollback.c
index 8e67812..85c245a 100644
--- a/firmware/lib/vboot_nvstorage_rollback.c
+++ b/firmware/lib/vboot_nvstorage_rollback.c
@@ -20,6 +20,7 @@
 	VBNV_DEV_BOOT_USB,
 	VBNV_DEV_BOOT_LEGACY,
 	VBNV_DEV_BOOT_SIGNED_ONLY,
+	VBNV_DEV_BOOT_FASTBOOT_FULL_CAP,
 };
 
 /* We can't back things up if there isn't enough storage. */
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index af0acc4..cb6b960 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -499,6 +499,8 @@
     value = VbGetNvStorage(VBNV_DEV_BOOT_LEGACY);
   } else if (!strcasecmp(name,"dev_boot_signed_only")) {
     value = VbGetNvStorage(VBNV_DEV_BOOT_SIGNED_ONLY);
+  } else if (!strcasecmp(name,"dev_boot_fastboot_full_cap")) {
+    value = VbGetNvStorage(VBNV_DEV_BOOT_FASTBOOT_FULL_CAP);
   } else if (!strcasecmp(name,"oprom_needed")) {
     value = VbGetNvStorage(VBNV_OPROM_NEEDED);
   } else if (!strcasecmp(name,"recovery_subcode")) {
@@ -653,6 +655,8 @@
     return VbSetNvStorage_WithBackup(VBNV_DEV_BOOT_LEGACY, value);
   } else if (!strcasecmp(name,"dev_boot_signed_only")) {
     return VbSetNvStorage_WithBackup(VBNV_DEV_BOOT_SIGNED_ONLY, value);
+  } else if (!strcasecmp(name,"dev_boot_fastboot_full_cap")) {
+    return VbSetNvStorage_WithBackup(VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, value);
   }
 
   return -1;
diff --git a/tests/vboot_api_init_tests.c b/tests/vboot_api_init_tests.c
index 331ba72..a74c541 100644
--- a/tests/vboot_api_init_tests.c
+++ b/tests/vboot_api_init_tests.c
@@ -555,6 +555,7 @@
 	VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 1);
 	VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 1);
 	VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
+	VbNvSet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, 1);
 	/* and some that don't */
 	VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
 	VbNvSet(&vnc, VBNV_TRY_B_COUNT, 3);
@@ -582,6 +583,8 @@
 	TEST_EQ(u, 0, "  NV dev_boot_legacy");
 	VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &u);
 	TEST_EQ(u, 0, "  NV dev_boot_signed_only");
+	VbNvGet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, &u);
+	TEST_EQ(u, 0, "  NV dev_boot_fastboot_full_cap");
 	/* So we should have written the backup */
 	TEST_EQ(backup_write_called, 1, "  Backup written once");
 	/* And the backup should reflect the persisent flags. */
@@ -597,6 +600,8 @@
 	TEST_EQ(u, 0, "  BU dev_boot_legacy");
 	VbNvGet(&tmp_vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &u);
 	TEST_EQ(u, 0, "  BU dev_boot_signed_only");
+	VbNvGet(&tmp_vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, &u);
+	TEST_EQ(u, 0, "  BU dev_boot_fastboot_full_cap");
 	/* but not the others */
 	VbNvGet(&tmp_vnc, VBNV_OPROM_NEEDED, &u);
 	TEST_EQ(u, 0, "  BU oprom_needed");
@@ -636,6 +641,7 @@
 	VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 1);
 	VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 1);
 	VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
+	VbNvSet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, 1);
 	/* and some that don't */
 	VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
 	VbNvSet(&vnc, VBNV_TRY_B_COUNT, 4);
@@ -683,6 +689,8 @@
 	TEST_EQ(u, 1, "  BU dev_boot_legacy");
 	VbNvGet(&tmp_vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &u);
 	TEST_EQ(u, 1, "  BU dev_boot_signed_only");
+	VbNvGet(&tmp_vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, &u);
+	TEST_EQ(u, 1, "  BU dev_boot_fastboot_full_cap");
 	/* but not the others */
 	VbNvGet(&tmp_vnc, VBNV_OPROM_NEEDED, &u);
 	TEST_EQ(u, 0, "  BU oprom_needed");
@@ -720,6 +728,8 @@
 	TEST_EQ(u, 1, "  BU dev_boot_legacy");
 	VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &u);
 	TEST_EQ(u, 1, "  BU dev_boot_signed_only");
+	VbNvGet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, &u);
+	TEST_EQ(u, 1, "  BU dev_boot_fastboot_full_cap");
 
 	/*
 	 * But if we lose the NV storage and go back to normal mode at the same
@@ -754,6 +764,8 @@
 	TEST_EQ(u, 0, "  BU dev_boot_legacy");
 	VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &u);
 	TEST_EQ(u, 0, "  BU dev_boot_signed_only");
+	VbNvGet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, &u);
+	TEST_EQ(u, 0, "  BU dev_boot_fastboot_full_cap");
 }
 
 
diff --git a/tests/vboot_nvstorage_test.c b/tests/vboot_nvstorage_test.c
index ec85738..9548a80 100644
--- a/tests/vboot_nvstorage_test.c
+++ b/tests/vboot_nvstorage_test.c
@@ -33,6 +33,7 @@
   {VBNV_DEV_BOOT_USB, 0, 1, 0, "dev boot usb"},
   {VBNV_DEV_BOOT_LEGACY, 0, 1, 0, "dev boot legacy"},
   {VBNV_DEV_BOOT_SIGNED_ONLY, 0, 1, 0, "dev boot custom"},
+  {VBNV_DEV_BOOT_FASTBOOT_FULL_CAP, 0, 1, 0, "dev boot fastboot full cap"},
   {VBNV_DISABLE_DEV_REQUEST, 0, 1, 0, "disable dev request"},
   {VBNV_CLEAR_TPM_OWNER_REQUEST, 0, 1, 0, "clear tpm owner request"},
   {VBNV_CLEAR_TPM_OWNER_DONE, 0, 1, 0, "clear tpm owner done"},