vboot: adjust VB2_SECDATA_KERNEL_FLAGS in non-recovery path

Currently, VB2_SECDATA_KERNEL_FLAGS controls experimental features
like phone recovery (and its UI), diagnostics entry. All of those
are under recovery screen. In order to allow later update pushes to
enable specific features in write-protected RO, we should not set
those flags in recovery path. Otherwise, it will always toggle back
and forth when booting RO recovery path vs. normal boot path.

BRANCH=puff
BUG=b:165181118
TEST=MENU_UI=0 DIAGNOSTIC_UI=0 make runtests
TEST=MENU_UI=0 DIAGNOSTIC_UI=1 make runtests
TEST=MENU_UI=1 DIAGNOSTIC_UI=0 make runtests
TEST=MENU_UI=1 DIAGNOSTIC_UI=1 make runtests
TEST=Cherry-pick locally to ToT of firmware-puff-13324.B with
     chromium:2360066 to manually check flags on Kaisa device.

Change-Id: I7ec45b4ecfa6d50781cec2690dbc88894c734073
Signed-off-by: Chun-Ta Lin <itspeter@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2361983
Tested-by: Chun-ta Lin <itspeter@chromium.org>
Reviewed-by: Joel Kitching <kitching@chromium.org>
Commit-Queue: Chun-ta Lin <itspeter@chromium.org>
diff --git a/firmware/2lib/2kernel.c b/firmware/2lib/2kernel.c
index 02ea544..4b6badb 100644
--- a/firmware/2lib/2kernel.c
+++ b/firmware/2lib/2kernel.c
@@ -126,7 +126,7 @@
 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
 	struct vb2_workbuf wb;
 	struct vb2_packed_key *packed_key;
-	uint32_t secdata_flags;
+	uint32_t flags;
 	vb2_error_t rv;
 
 	vb2_workbuf_from_ctx(ctx, &wb);
@@ -143,12 +143,14 @@
 		return rv;
 	}
 
-	/* Enable phone recovery while disabling the UI; disable diagnostics. */
-	secdata_flags = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS);
-	secdata_flags &= ~VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_DISABLED;
-	secdata_flags |= VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_UI_DISABLED;
-	secdata_flags |= VB2_SECDATA_KERNEL_FLAG_DIAGNOSTIC_UI_DISABLED;
-	vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, secdata_flags);
+	/* Initialize experimental feature flags while in normal RW path. */
+        if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
+		flags = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS);
+		flags &= ~VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_DISABLED;
+		flags |= VB2_SECDATA_KERNEL_FLAG_PHONE_RECOVERY_UI_DISABLED;
+		flags |= VB2_SECDATA_KERNEL_FLAG_DIAGNOSTIC_UI_DISABLED;
+		vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, flags);
+	}
 
 	/* Read kernel version from secdata. */
 	sd->kernel_version_secdata =
diff --git a/tests/vb2_kernel_tests.c b/tests/vb2_kernel_tests.c
index c2741b4..67b6b48 100644
--- a/tests/vb2_kernel_tests.c
+++ b/tests/vb2_kernel_tests.c
@@ -213,6 +213,11 @@
 		"  key data");
 	TEST_EQ(sd->kernel_version_secdata, 0x20002,
 		"  secdata_kernel version");
+
+	/* Test flags for experimental features in non-recovery path */
+	reset_common_data(FOR_PHASE1);
+	ctx->flags &= ~VB2_CONTEXT_RECOVERY_MODE;
+	TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 non-rec good");
 	/* Make sure phone recovery functionality is enabled, but UI disabled */
 	TEST_EQ(vb2api_phone_recovery_enabled(ctx), 1,
 		"  phone recovery enabled");
@@ -222,6 +227,27 @@
 	TEST_EQ(vb2api_diagnostic_ui_enabled(ctx), 0,
 		"  diagnostic ui disabled");
 
+	/*
+	 * Test flags are unchanged for experimental features in recovery path
+	 */
+
+	/* Set 8 bits to 0 */
+	reset_common_data(FOR_PHASE1);
+	ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+	vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, 0);
+	TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 rec good");
+	TEST_EQ(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS), 0,
+		"VB2_SECDATA_KERNEL_FLAGS remains unchanged in recovery path");
+
+	/* Set 8 bits to 1 */
+	reset_common_data(FOR_PHASE1);
+	ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+	vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS, UINT8_MAX);
+	TEST_SUCC(vb2api_kernel_phase1(ctx), "phase1 rec good");
+	TEST_EQ(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_FLAGS),
+	        UINT8_MAX,
+		"VB2_SECDATA_KERNEL_FLAGS remains unchanged in recovery path");
+
 	/* Bad secdata_fwmp causes failure in normal mode only */
 	reset_common_data(FOR_PHASE1);
 	mock_secdata_fwmp_check_retval = VB2_ERROR_SECDATA_FWMP_CRC;