summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorRob Barnes <robbarnes@google.com>2022-11-15 01:46:49 +0000
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-05-01 21:29:22 +0000
commitf2e7fd5a61404ff60652fe6dfc9a4e0d1cdad5a9 (patch)
treee1790e86d150b2234e5ec4bbc2f72f84c87d6f34 /common
parent3567580eb767809e3c0791fb0aba9346752b55ae (diff)
downloadchrome-ec-f2e7fd5a61404ff60652fe6dfc9a4e0d1cdad5a9.tar.gz
system: Implement system safe mode
Basic implementation of system safe mode recovery. System safe mode is a recovery mode that may be started after a fault/panic. It allows the AP to collect info about the fault and system state before the system resets This CL only includes support for legacy CrOS EC BUG=b:249128225 BRANCH=None TEST=Manually tested on octopus Orig-Change-Id: I15139bb082011485b54e4ca7813839940bf5401a Orig-Signed-off-by: Rob Barnes <robbarnes@google.com> Orig-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4029604 Orig-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Change-Id: I8abd563b82b611dafbc9fe1fda05ac6ade2b7c91 Signed-off-by: Rob Barnes <robbarnes@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4320966 Reviewed-by: Boris Mittelberg <bmbm@google.com>
Diffstat (limited to 'common')
-rw-r--r--common/build.mk1
-rw-r--r--common/host_command.c6
-rw-r--r--common/system_safe_mode.c127
3 files changed, 134 insertions, 0 deletions
diff --git a/common/build.mk b/common/build.mk
index 32e61123cb..f91d020f54 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -151,6 +151,7 @@ common-$(HAS_TASK_KEYSCAN)+=keyboard_scan.o
common-$(HAS_TASK_LIGHTBAR)+=lb_common.o lightbar.o
common-$(HAS_TASK_MOTIONSENSE)+=motion_sense.o
common-$(HAS_TASK_TPM)+=tpm_registers.o
+common-$(CONFIG_SYSTEM_SAFE_MODE)+=system_safe_mode.o
ifneq ($(CONFIG_COMMON_RUNTIME),)
common-$(CONFIG_MALLOC)+=shmalloc.o
diff --git a/common/host_command.c b/common/host_command.c
index cad9fd94a9..38113f021e 100644
--- a/common/host_command.c
+++ b/common/host_command.c
@@ -14,6 +14,7 @@
#include "lpc.h"
#include "shared_mem.h"
#include "system.h"
+#include "system_safe_mode.h"
#include "task.h"
#include "timer.h"
#include "util.h"
@@ -403,6 +404,11 @@ static const struct host_command *find_host_command(int command)
#else
const struct host_command *cmd;
+ if (IS_ENABLED(CONFIG_SYSTEM_SAFE_MODE) && system_is_in_safe_mode()) {
+ if (!command_is_allowed_in_safe_mode(command))
+ return NULL;
+ }
+
for (cmd = __hcmds; cmd < __hcmds_end; cmd++) {
if (command == cmd->command)
return cmd;
diff --git a/common/system_safe_mode.c b/common/system_safe_mode.c
new file mode 100644
index 0000000000..dbad287463
--- /dev/null
+++ b/common/system_safe_mode.c
@@ -0,0 +1,127 @@
+/* Copyright 2022 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "ec_commands.h"
+#include "hooks.h"
+#include "panic.h"
+#include "stdbool.h"
+#include "stddef.h"
+#include "system.h"
+#include "system_safe_mode.h"
+#include "task.h"
+#include "timer.h"
+#include "watchdog.h"
+
+static bool in_safe_mode;
+
+static const int safe_mode_allowed_hostcmds[] = {
+ EC_CMD_GET_PROTOCOL_INFO,
+ EC_CMD_GET_VERSION, EC_CMD_CONSOLE_SNAPSHOT,
+ EC_CMD_CONSOLE_READ, EC_CMD_GET_NEXT_EVENT,
+ EC_CMD_GET_UPTIME_INFO
+};
+
+#ifndef CONFIG_ZEPHYR
+
+/* TODO: This function can be generalized for zephyr and legacy EC by
+ * improving ec_tasks support in zephyr.
+ */
+static bool task_is_safe_mode_critical(task_id_t task_id)
+{
+ const task_id_t safe_mode_critical_tasks[] = {
+ TASK_ID_HOOKS,
+ TASK_ID_IDLE,
+ TASK_ID_HOSTCMD,
+ };
+ for (int i = 0; i < ARRAY_SIZE(safe_mode_critical_tasks); i++)
+ if (safe_mode_critical_tasks[i] == task_id)
+ return true;
+ return false;
+}
+
+bool current_task_is_safe_mode_critical(void)
+{
+ return task_is_safe_mode_critical(task_get_current());
+}
+
+int disable_non_safe_mode_critical_tasks(void)
+{
+ for (task_id_t task_id = 0; task_id < TASK_ID_COUNT; task_id++) {
+ if (!task_is_safe_mode_critical(task_id)) {
+ task_disable_task(task_id);
+ }
+ }
+ return EC_SUCCESS;
+}
+
+#endif /* CONFIG_ZEPHYR */
+
+void handle_system_safe_mode_timeout(void)
+{
+ panic_printf("Safe mode timeout after %d msec\n",
+ CONFIG_SYSTEM_SAFE_MODE_TIMEOUT_MSEC);
+ panic_reboot();
+}
+DECLARE_DEFERRED(handle_system_safe_mode_timeout);
+
+__overridable int schedule_system_safe_mode_timeout(void)
+{
+ hook_call_deferred(&handle_system_safe_mode_timeout_data,
+ CONFIG_SYSTEM_SAFE_MODE_TIMEOUT_MSEC * MSEC);
+ return EC_SUCCESS;
+}
+
+bool system_is_in_safe_mode(void)
+{
+ return !!in_safe_mode;
+}
+
+bool command_is_allowed_in_safe_mode(int command)
+{
+ for (int i = 0; i < ARRAY_SIZE(safe_mode_allowed_hostcmds); i++)
+ if (command == safe_mode_allowed_hostcmds[i])
+ return true;
+ return false;
+}
+
+int start_system_safe_mode(void)
+{
+ if (!system_is_in_rw()) {
+ panic_printf("Can only enter safe mode from RW image\n");
+ return EC_ERROR_INVAL;
+ }
+
+ if (system_is_in_safe_mode()) {
+ panic_printf("Already in system safe mode");
+ return EC_ERROR_INVAL;
+ }
+
+ if (current_task_is_safe_mode_critical()) {
+ /* TODO: Restart critical tasks */
+ panic_printf(
+ "Fault in critical task, cannot enter system safe mode\n");
+ return EC_ERROR_INVAL;
+ }
+
+ disable_non_safe_mode_critical_tasks();
+
+ schedule_system_safe_mode_timeout();
+
+ in_safe_mode = true;
+
+ panic_printf("\nStarting system safe mode\n");
+
+ return EC_SUCCESS;
+}
+
+#ifdef TEST_BUILD
+void set_system_safe_mode(bool mode)
+{
+ in_safe_mode = mode;
+}
+#endif