Support doing battery cut-off in firmware stage.
authorHung-Te Lin <hungte@chromium.org>
Thu, 7 Apr 2016 04:21:03 +0000 (12:21 +0800)
committerchrome-bot <chrome-bot@chromium.org>
Tue, 12 Apr 2016 12:49:26 +0000 (05:49 -0700)
Add a new crossystem value "battery_cutoff_request" to indicate that
next reboot should cut-off battery and shutdown during firmware stage.

This request is primarily for factories to ship devices in an safe
state. Previously we have done same thing by running "ectool battery-cutoff"
but that creates a problem which "ectool" (and the one to request for
cut-off) must live in developer mode while  the device must be shipped
in normal mode. The mode transition was solved by setting
"disable_dev_request=1", but that flag is may get lost on x86 systems
(having NV storage in CMOS) when the battery is cut-off .

From the experience from Ryu, such settings (dev mode transition and
battery cut-off) should be done together inside firmware execution so we
can create a new flag, battery_cutoff_request, to finalize device
properly.

BRANCH=none
BUG=chromium:601705
TEST=emerge-chell depthcharge vboot_reference chromeos-bootimage
     crossystem battery_cutoff_request=1
     # Unplug AC adapter
     reboot
     # See device rebooted and then shutdown immediately.
     # Press power button and system won't boot.
     # Attach AC adapter and now system boots.
CQ-DEPEND=CL:337596,CL:338193

Change-Id: I73ccae15b337cd65786106646546c67c155b8fa6
Reviewed-on: https://chromium-review.googlesource.com/337602
Commit-Ready: Hung-Te Lin <hungte@chromium.org>
Tested-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
firmware/2lib/2nvstorage.c
firmware/2lib/include/2nvstorage.h
firmware/2lib/include/2nvstorage_fields.h
firmware/include/vboot_api.h
firmware/include/vboot_nvstorage.h
firmware/lib/vboot_api_kernel.c
firmware/lib/vboot_nvstorage.c
firmware/stub/vboot_api_stub.c
host/lib/crossystem.c
utility/crossystem.c

index 3e2a874..b40bbe7 100644 (file)
@@ -172,6 +172,9 @@ uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param)
 
        case VB2_NV_TRY_RO_SYNC:
                return GETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_TRY_RO_SYNC);
+
+       case VB2_NV_BATTERY_CUTOFF_REQUEST:
+               return GETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_BATTERY_CUTOFF);
        }
 
        /*
@@ -350,6 +353,9 @@ void vb2_nv_set(struct vb2_context *ctx,
                SETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_TRY_RO_SYNC);
                break;
 
+       case VB2_NV_BATTERY_CUTOFF_REQUEST:
+               SETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_BATTERY_CUTOFF);
+               break;
        }
 
        /*
index 5c958c7..66a5fdf 100644 (file)
@@ -96,6 +96,8 @@ enum vb2_nv_param {
        VB2_NV_BOOT_ON_AC_DETECT,
        /* Try to update the EC-RO image after updating the EC-RW image(0=no, 1=yes). */
        VB2_NV_TRY_RO_SYNC,
+        /* Cut off battery and shutdown on next boot. */
+        VB2_NV_BATTERY_CUTOFF_REQUEST,
 };
 
 /* Set default boot in developer mode */
index 9ec3d88..018bdeb 100644 (file)
@@ -70,9 +70,10 @@ enum vb2_nv_offset {
 #define VB2_NV_TPM_CLEAR_OWNER_DONE            0x02
 #define VB2_NV_TPM_REBOOTED                    0x04
 
-/* Fields in VB2_NV_OFFS_MISC (unused = 0xf8) */
+/* Fields in VB2_NV_OFFS_MISC (unused = 0xf0) */
 #define VB2_NV_MISC_UNLOCK_FASTBOOT            0x01
 #define VB2_NV_MISC_BOOT_ON_AC_DETECT          0x02
 #define VB2_NV_MISC_TRY_RO_SYNC                       0x04
+#define VB2_NV_MISC_BATTERY_CUTOFF             0x08
 
 #endif  /* VBOOT_REFERENCE_VBOOT_2NVSTORAGE_FIELDS_H_ */
index ddc8cc6..5046d2a 100644 (file)
@@ -945,6 +945,11 @@ VbError_t VbExEcEnteringMode(int devidx, enum VbEcBootMode_t mode);
  */
 VbError_t VbExEcVbootDone(int in_recovery);
 
+/**
+ * Request EC to stop discharging and cut-off battery.
+ */
+VbError_t VbExEcBatteryCutOff(void);
+
 /*****************************************************************************/
 /* Misc */
 
index 91f62cb..ef78e47 100644 (file)
@@ -120,7 +120,10 @@ typedef enum VbNvParam {
        VBNV_BOOT_ON_AC_DETECT,
        /* Try to update the EC-RO image (0=no, 1=yes). */
        VBNV_TRY_RO_SYNC,
-
+       /*
+        * Finish mode transition (if requested), perform battery cut-off and
+        * shutdown in next boot. */
+       VBNV_BATTERY_CUTOFF_REQUEST,
 } VbNvParam;
 
 /* Set default boot in developer mode */
index fff3056..c336278 100644 (file)
@@ -1082,6 +1082,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
        VbError_t retval = VBERROR_SUCCESS;
        LoadKernelParams p;
        uint32_t tpm_status = 0;
+       uint32_t battery_cutoff = 0;
 
        /* Start timer */
        shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
@@ -1138,6 +1139,17 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
        if (retval != VBERROR_SUCCESS)
                goto VbSelectAndLoadKernel_exit;
 
+       /* Check if we need to cut-off battery. This must be done after EC
+         * firmware updating and before kernel started. */
+       VbNvGet(&vnc, VBNV_BATTERY_CUTOFF_REQUEST, &battery_cutoff);
+       if (battery_cutoff) {
+               VBDEBUG(("Request to cut-off battery\n"));
+               VbNvSet(&vnc, VBNV_BATTERY_CUTOFF_REQUEST, 0);
+               VbExEcBatteryCutOff();
+               retval = VBERROR_SHUTDOWN_REQUESTED;
+               goto VbSelectAndLoadKernel_exit;
+       }
+
        /* Read kernel version from the TPM.  Ignore errors in recovery mode. */
        tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
        if (0 != tpm_status) {
index d022c5d..c131f08 100644 (file)
@@ -64,6 +64,7 @@
 #define MISC_UNLOCK_FASTBOOT            0x01
 #define MISC_BOOT_ON_AC_DETECT          0x02
 #define MISC_TRY_RO_SYNC               0x04
+#define MISC_BATTERY_CUTOFF_REQUEST    0x08
 
 #define KERNEL_FIELD_OFFSET         11
 #define CRC_OFFSET                  15
@@ -231,6 +232,11 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest)
                *dest = (raw[MISC_OFFSET] & MISC_TRY_RO_SYNC) ? 1 : 0;
                return 0;
 
+       case VBNV_BATTERY_CUTOFF_REQUEST:
+               *dest = (raw[MISC_OFFSET] & MISC_BATTERY_CUTOFF_REQUEST)
+                        ?  1 : 0;
+               return 0;
+
        default:
                return 1;
        }
@@ -456,6 +462,13 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
                        raw[MISC_OFFSET] &= ~MISC_TRY_RO_SYNC;
                break;
 
+       case VBNV_BATTERY_CUTOFF_REQUEST:
+               if (value)
+                       raw[MISC_OFFSET] |= MISC_BATTERY_CUTOFF_REQUEST;
+               else
+                       raw[MISC_OFFSET] &= ~MISC_BATTERY_CUTOFF_REQUEST;
+               break;
+
        default:
                return 1;
        }
index 2299a03..7bc4cb8 100644 (file)
@@ -166,6 +166,11 @@ VbError_t VbExEcVbootDone(int in_recovery)
        return VBERROR_SUCCESS;
 }
 
+VbError_t VbExEcBatteryCutOff(void)
+{
+       return VBERROR_SUCCESS;
+}
+
 enum VbEcBootMode_t VbGetMode(void)
 {
        return vboot_mode;
index bcbf4dd..7c51927 100644 (file)
@@ -551,6 +551,8 @@ int VbGetSystemPropertyInt(const char* name) {
          value = VbGetNvStorage(VBNV_BOOT_ON_AC_DETECT);
   } else if (!strcasecmp(name, "try_ro_sync")) {
          value = VbGetNvStorage(VBNV_TRY_RO_SYNC);
+  } else if (!strcasecmp(name, "battery_cutoff_request")) {
+    value = VbGetNvStorage(VBNV_BATTERY_CUTOFF_REQUEST);
   }
 
   return value;
@@ -687,6 +689,8 @@ int VbSetSystemPropertyInt(const char* name, int value) {
     return VbSetNvStorage_WithBackup(VBNV_BOOT_ON_AC_DETECT, value);
   } else if (!strcasecmp(name, "try_ro_sync")) {
     return VbSetNvStorage_WithBackup(VBNV_TRY_RO_SYNC, value);
+  } else if (!strcasecmp(name, "battery_cutoff_request")) {
+    return VbSetNvStorage(VBNV_BATTERY_CUTOFF_REQUEST, value);
   }
 
   return -1;
index 330a3fd..c88a444 100644 (file)
@@ -34,6 +34,8 @@ const Param sys_param_list[] = {
   {"arch", IS_STRING, "Platform architecture"},
   {"backup_nvram_request", CAN_WRITE,
    "Backup the nvram somewhere at the next boot. Cleared on success."},
+  {"battery_cutoff_request", CAN_WRITE,
+   "Cut off battery and shutdown on next boot."},
   {"block_devmode", CAN_WRITE, "Block all use of developer mode"},
   {"clear_tpm_owner_request", CAN_WRITE, "Clear TPM owner on next boot"},
   {"clear_tpm_owner_done", CAN_WRITE, "Clear TPM owner done"},