From 4bc9906f35507cb332456cb69f883fad4cdfcba2 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Thu, 7 Apr 2016 12:21:03 +0800 Subject: Support doing battery cut-off in firmware stage. 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:338288,CL:338399 Original-Change-Id: I73ccae15b337cd65786106646546c67c155b8fa6 Original-Reviewed-on: https://chromium-review.googlesource.com/337602 Commit-Ready: Hung-Te Lin Tested-by: Hung-Te Lin Reviewed-by: Duncan Laurie (cherry picked from commit aee6bd69fefac653cfc4a5679eb387d7c3280d14) Change-Id: I563602ee8437f867720942df7f658a28378579aa Reviewed-on: https://chromium-review.googlesource.com/338178 Reviewed-by: Duncan Laurie Tested-by: Duncan Laurie Commit-Queue: Duncan Laurie --- firmware/2lib/2nvstorage.c | 6 ++++++ firmware/2lib/include/2nvstorage.h | 2 ++ firmware/2lib/include/2nvstorage_fields.h | 3 ++- firmware/include/vboot_api.h | 5 +++++ firmware/include/vboot_nvstorage.h | 5 ++++- firmware/lib/vboot_api_kernel.c | 12 ++++++++++++ firmware/lib/vboot_nvstorage.c | 13 +++++++++++++ firmware/stub/vboot_api_stub.c | 5 +++++ host/lib/crossystem.c | 4 ++++ utility/crossystem.c | 2 ++ 10 files changed, 55 insertions(+), 2 deletions(-) diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c index 3e2a8740..b40bbe78 100644 --- a/firmware/2lib/2nvstorage.c +++ b/firmware/2lib/2nvstorage.c @@ -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; } /* diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h index 5c958c76..66a5fdf1 100644 --- a/firmware/2lib/include/2nvstorage.h +++ b/firmware/2lib/include/2nvstorage.h @@ -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 */ diff --git a/firmware/2lib/include/2nvstorage_fields.h b/firmware/2lib/include/2nvstorage_fields.h index 9ec3d884..018bdeb7 100644 --- a/firmware/2lib/include/2nvstorage_fields.h +++ b/firmware/2lib/include/2nvstorage_fields.h @@ -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_ */ diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index ddc8cc62..5046d2ae 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -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 */ diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h index 91f62cb4..ef78e47a 100644 --- a/firmware/include/vboot_nvstorage.h +++ b/firmware/include/vboot_nvstorage.h @@ -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 */ diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index fff30561..c3362789 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -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) { diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c index d022c5d3..c131f088 100644 --- a/firmware/lib/vboot_nvstorage.c +++ b/firmware/lib/vboot_nvstorage.c @@ -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; } diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c index 2299a033..7bc4cb86 100644 --- a/firmware/stub/vboot_api_stub.c +++ b/firmware/stub/vboot_api_stub.c @@ -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; diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index fd5cd9eb..3d2a908f 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -542,6 +542,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; @@ -678,6 +680,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; diff --git a/utility/crossystem.c b/utility/crossystem.c index 330a3fd5..c88a444d 100644 --- a/utility/crossystem.c +++ b/utility/crossystem.c @@ -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"}, -- cgit v1.2.1