vboot: Notify EC of current boot mode

Notify EC of boot mode, i.e. normal, developer or recovery.
This is necessary for battery firmware updates.

BUG=chrome-os-partner:24741
BRANCH=ToT
TEST=Verified on glimmer.

Change-Id: I1613ede34b4a929d1e8114fb519861f349377e94
Signed-off-by: Sheng-Liang Song <ssl@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/214273
Reviewed-by: Randall Spangler <rspangler@chromium.org>
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 0ae6c76..c12c3d2 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -787,6 +787,13 @@
  */
 VbError_t VbExEcProtectRW(void);
 
+/**
+ * Info the EC of the boot mode selected by the AP.
+ * mode: Normal, Developer, or Recovery
+ */
+enum VbEcBootMode_t {VB_EC_NORMAL, VB_EC_DEVELOPER, VB_EC_RECOVERY };
+VbError_t VbExEcEnteringMode(enum VbEcBootMode_t mode);
+
 /* Args to VbExProtectFlash() */
 enum VbProtectFlash_t { VBPROTECT_RW_A, VBPROTECT_RW_B, VBPROTECT_RW_DEVKEY };
 
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 18d00ae..220ae6f 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -954,15 +954,18 @@
 		/* Recovery boot */
 		p.boot_flags |= BOOT_FLAG_RECOVERY;
 		retval = VbBootRecovery(cparams, &p);
+		VbExEcEnteringMode(VB_EC_RECOVERY);
 		VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
 
 	} else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
 		/* Developer boot */
 		retval = VbBootDeveloper(cparams, &p);
+		VbExEcEnteringMode(VB_EC_DEVELOPER);
 		VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
 
 	} else {
 		/* Normal boot */
+		VbExEcEnteringMode(VB_EC_NORMAL);
 		retval = VbBootNormal(cparams, &p);
 
 		if ((1 == shared->firmware_index) &&
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c
index e82be5b..6807834 100644
--- a/firmware/stub/vboot_api_stub.c
+++ b/firmware/stub/vboot_api_stub.c
@@ -17,6 +17,8 @@
 
 #include "vboot_api.h"
 
+static enum VbEcBootMode_t vboot_mode;
+
 void VbExSleepMs(uint32_t msec)
 {
 }
@@ -136,6 +138,17 @@
 	return VBERROR_SUCCESS;
 }
 
+VbError_t VbExEcEnteringMode(enum VbEcBootMode_t mode)
+{
+	vboot_mode = mode;
+	return VBERROR_SUCCESS;
+}
+
+enum VbEcBootMode_t VbGetMode(void)
+{
+	return vboot_mode;
+}
+
 int VbExLegacy(void)
 {
 	return 1;
diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c
index 21ea306..7eab0d5 100644
--- a/tests/vboot_api_kernel2_tests.c
+++ b/tests/vboot_api_kernel2_tests.c
@@ -42,6 +42,8 @@
 static uint32_t mock_num_disks[8];
 static uint32_t mock_num_disks_count;
 
+extern enum VbEcBootMode_t VbGetMode(void);
+
 /* Reset mock data (for use before each test) */
 static void ResetMocks(void)
 {
@@ -203,7 +205,9 @@
 static void VbBootTest(void)
 {
 	ResetMocks();
+	VbExEcEnteringMode(VB_EC_NORMAL);
 	TEST_EQ(VbBootNormal(&cparams, &lkp), 1002, "VbBootNormal()");
+	TEST_EQ(VbGetMode(), VB_EC_NORMAL, "vboot_mode normal");
 }
 
 static void VbBootDevTest(void)
@@ -214,7 +218,9 @@
 
 	/* Proceed after timeout */
 	ResetMocks();
+	VbExEcEnteringMode(VB_EC_DEVELOPER);
 	TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Timeout");
+	TEST_EQ(VbGetMode(), VB_EC_DEVELOPER, "vboot_mode developer");
 	TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
 		"  warning screen");
 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
@@ -389,8 +395,11 @@
 	/* Shutdown requested in loop */
 	ResetMocks();
 	shutdown_request_calls_left = 10;
+	VbExEcEnteringMode(VB_EC_RECOVERY);
 	TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
 		"Shutdown requested");
+	TEST_EQ(VbGetMode(), VB_EC_RECOVERY, "vboot_mode recovery");
+
 	VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
 	TEST_EQ(u, 0, "  recovery reason");
 	TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,