summaryrefslogtreecommitdiff
path: root/common/vboot/efs2.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/vboot/efs2.c')
-rw-r--r--common/vboot/efs2.c352
1 files changed, 0 insertions, 352 deletions
diff --git a/common/vboot/efs2.c b/common/vboot/efs2.c
deleted file mode 100644
index e5c3b64f04..0000000000
--- a/common/vboot/efs2.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/* Copyright 2020 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/*
- * Early Firmware Selection ver.2.
- *
- * Verify and jump to a RW image. Register boot mode to Cr50.
- */
-
-#include "battery.h"
-#include "chipset.h"
-#include "clock.h"
-#include "compile_time_macros.h"
-#include "console.h"
-#include "crc8.h"
-#include "flash.h"
-#include "hooks.h"
-#include "sha256.h"
-#include "system.h"
-#include "task.h"
-#include "usb_pd.h"
-#include "uart.h"
-#include "vboot.h"
-#include "vboot_hash.h"
-
-#define CPRINTS(format, args...) cprints(CC_VBOOT,"VB " format, ## args)
-#define CPRINTF(format, args...) cprintf(CC_VBOOT,"VB " format, ## args)
-
-static const char *boot_mode_to_string(uint8_t mode)
-{
- static const char *boot_mode_str[] = {
- [BOOT_MODE_NORMAL] = "NORMAL",
- [BOOT_MODE_NO_BOOT] = "NO_BOOT",
- };
- if (mode < ARRAY_SIZE(boot_mode_str))
- return boot_mode_str[mode];
- return "UNDEF";
-}
-
-/*
- * Check whether the session has successfully ended or not. ERR_TIMEOUT is
- * excluded because it's an internal error produced by EC itself.
- */
-static bool is_valid_cr50_response(enum cr50_comm_err code)
-{
- return code != CR50_COMM_ERR_TIMEOUT
- && (code >> 8) == CR50_COMM_ERR_PREFIX;
-}
-
-__overridable void board_enable_packet_mode(bool enable)
-{
- /*
- * This can be done by set_flags(INPUT|PULL_UP). We don't need it now
- * because Cr50 never initiates communication.
- */
- gpio_set_level(GPIO_PACKET_MODE_EN, enable ? 1 : 0);
-}
-
-static enum cr50_comm_err send_to_cr50(const uint8_t *data, size_t size)
-{
- timestamp_t until;
- int i, timeout = 0;
- uint32_t lock_key;
- struct cr50_comm_response res = {};
-
- /* This will wake up (if it's sleeping) and interrupt Cr50. */
- board_enable_packet_mode(true);
-
- uart_flush_output();
- uart_clear_input();
-
- if (uart_shell_stop()) {
- /* Failed to stop the shell. */
- board_enable_packet_mode(false);
- return CR50_COMM_ERR_UNKNOWN;
- }
-
- /*
- * Send packet. No traffic control, assuming Cr50 consumes stream much
- * faster. TX buffer shouldn't overflow because it's cleared above and
- * much bigger than the max packet size.
- *
- * Disable interrupts so that the data frame will be stored in the Tx
- * buffer in one piece.
- */
- lock_key = irq_lock();
- uart_put_raw(data, size);
- irq_unlock(lock_key);
-
- uart_flush_output();
-
- until.val = get_time().val + CR50_COMM_TIMEOUT;
-
- /*
- * Make sure console task won't steal the response in case we exchange
- * packets after tasks start.
- */
-#ifndef CONFIG_ZEPHYR
- if (task_start_called())
- task_disable_task(TASK_ID_CONSOLE);
-#endif /* !CONFIG_ZEPHYR */
-
- /* Wait for response from Cr50 */
- for (i = 0; i < sizeof(res); i++) {
- while (!timeout) {
- int c = uart_getc();
- if (c != -1) {
- res.error = res.error | c << (i*8);
- break;
- }
- msleep(1);
- timeout = timestamp_expired(until, NULL);
- }
- }
-
- uart_shell_start();
-#ifndef CONFIG_ZEPHYR
- if (task_start_called())
- task_enable_task(TASK_ID_CONSOLE);
-#endif /* CONFIG_ZEPHYR */
-
- /* Exit packet mode */
- board_enable_packet_mode(false);
-
- CPRINTS("Received 0x%04x", res.error);
-
- if (timeout) {
- CPRINTS("Timeout");
- return CR50_COMM_ERR_TIMEOUT;
- }
-
- return res.error;
-}
-
-static enum cr50_comm_err cmd_to_cr50(enum cr50_comm_cmd cmd,
- const uint8_t *data, size_t size)
-{
- /*
- * This is on the stack instead of .bss because vboot_main currently is
- * called only once (from main). Keeping the space unused in .bss would
- * be wasteful.
- */
- struct {
- uint8_t preamble[CR50_UART_RX_BUFFER_SIZE];
- uint8_t packet[CR50_COMM_MAX_REQUEST_SIZE];
- } __packed s;
- struct cr50_comm_request *p = (struct cr50_comm_request *)s.packet;
- int retry = CR50_COMM_MAX_RETRY;
- enum cr50_comm_err rv;
-
- /* compose a frame = preamble + packet */
- memset(s.preamble, CR50_COMM_PREAMBLE, sizeof(s.preamble));
- p->magic = CR50_PACKET_MAGIC;
- p->struct_version = CR50_COMM_PACKET_VERSION;
- p->type = cmd;
- p->size = size;
- memcpy(p->data, data, size);
- p->crc = cros_crc8((uint8_t *)&p->type,
- sizeof(p->type) + sizeof(p->size) + size);
-
- do {
- rv = send_to_cr50((uint8_t *)&s,
- sizeof(s.preamble) + sizeof(*p) + p->size);
- if (is_valid_cr50_response(rv))
- break;
- msleep(5);
- } while (--retry);
-
- return rv;
-}
-
-static enum cr50_comm_err verify_hash(void)
-{
- const uint8_t *hash;
- int rv;
-
- /* Wake up Cr50 beforehand in case it's asleep. */
- board_enable_packet_mode(true);
- CPRINTS("Ping Cr50");
- msleep(1);
- board_enable_packet_mode(false);
-
- rv = vboot_get_rw_hash(&hash);
- if (rv)
- return rv;
-
- CPRINTS("Verifying hash");
- return cmd_to_cr50(CR50_COMM_CMD_VERIFY_HASH, hash, SHA256_DIGEST_SIZE);
-}
-
-static enum cr50_comm_err set_boot_mode(uint8_t mode)
-{
- enum cr50_comm_err rv;
-
- CPRINTS("Setting boot mode to %s(%d)", boot_mode_to_string(mode), mode);
- rv = cmd_to_cr50(CR50_COMM_CMD_SET_BOOT_MODE,
- &mode, sizeof(enum boot_mode));
- if (rv != CR50_COMM_SUCCESS)
- CPRINTS("Failed to set boot mode");
- return rv;
-}
-
-static bool pd_comm_enabled;
-
-static void enable_pd(void)
-{
- CPRINTS("Enable USB-PD");
- pd_comm_enabled = true;
-}
-
-bool vboot_allow_usb_pd(void)
-{
- return pd_comm_enabled;
-}
-
-__overridable void show_critical_error(void)
-{
- CPRINTS("%s", __func__);
-}
-
-static void verify_and_jump(void)
-{
- enum cr50_comm_err rv = verify_hash();
-
- switch (rv) {
- case CR50_COMM_ERR_BAD_PAYLOAD:
- /* Cr50 should have set NO_BOOT. */
- CPRINTS("Hash mismatch");
- enable_pd();
- break;
- case CR50_COMM_SUCCESS:
- system_set_reset_flags(EC_RESET_FLAG_EFS);
- rv = system_run_image_copy(EC_IMAGE_RW);
- CPRINTS("Failed to jump (0x%x)", rv);
- system_clear_reset_flags(EC_RESET_FLAG_EFS);
- show_critical_error();
- break;
- default:
- CPRINTS("Failed to verify RW (0x%x)", rv);
- show_critical_error();
- }
-}
-
-__overridable void show_power_shortage(void)
-{
- CPRINTS("%s", __func__);
-}
-
-static bool is_battery_ready(void)
-{
- /* TODO: Add battery check (https://crbug.com/1045216) */
- return true;
-}
-
-void vboot_main(void)
-{
- CPRINTS("Main");
-
- if (system_is_in_rw()) {
- /*
- * We come here and immediately return. LED shows power shortage
- * but it will be immediately corrected if the adapter can
- * provide enough power.
- */
- CPRINTS("Already in RW");
- show_power_shortage();
- return;
- }
-
- if (system_is_manual_recovery() ||
- (system_get_reset_flags() & EC_RESET_FLAG_STAY_IN_RO)) {
- if (system_is_manual_recovery())
- CPRINTS("In recovery mode");
- if (!IS_ENABLED(CONFIG_BATTERY)
- && !IS_ENABLED(HAS_TASK_KEYSCAN)) {
- /*
- * For Chromeboxes, we relax security by allowing PD in
- * RO. Attackers don't gain meaningful advantage on
- * built-in-keyboard-less systems.
- *
- * Alternatively, we can use NO_BOOT to show a firmware
- * screen, strictly requiring BJ adapter and keeping PD
- * disabled.
- */
- enable_pd();
- return;
- }
-
- /*
- * If battery is drained or bad, we will boot in NO_BOOT mode to
- * inform the user of the problem.
- */
- if (!is_battery_ready()) {
- CPRINTS("Battery not ready or bad");
- if (set_boot_mode(BOOT_MODE_NO_BOOT) ==
- CR50_COMM_SUCCESS)
- enable_pd();
- }
-
- /* We'll enter recovery mode immediately, later, or never. */
- return;
- }
-
- verify_and_jump();
-
- /*
- * EFS failed. EC-RO may be able to boot AP if:
- *
- * - Battery is charged or
- * - AC adapter supply in RO >= Boot threshold or
- * - BJ adapter is plugged.
- *
- * Once AP boots, software sync will fix the mismatch. If that's the
- * reason of the failure, we won't come back here next time.
- */
- CPRINTS("Exit");
-}
-
-void hook_shutdown(void)
-{
- CPRINTS("%s", __func__);
-
- /*
- * We filter the cases which can be interfered with if we execute
- * system_reset in HOOK_CHIPSET_SHUTDOWN context. Most cases are
- * filtered out by system_is_in_rw (e.g. system_common_shutdown,
- * check_pending_cutoff).
- */
- if (system_is_in_rw())
- return;
-
- /*
- * We can't reset here because it'll completely tear down the power
- * and disturb the PCH's power sequence. We instead sysjump.
- *
- * Note that this does not reduce the security. Even if it's hijacked in
- * NO_BOOT mode, an RO still needs to go through a cold reset to clear
- * NO_BOOT flag since Cr50 rejects to switch from NO_BOOT to NORMAL.
- * If a spoofed matching hash is passed to Cr50, Cr50 would reset EC.
- */
- system_set_reset_flags(EC_RESET_FLAG_AP_IDLE);
- verify_and_jump();
-}
-/*
- * There can be hooks which are needed to set external chips to a certain state
- * in S5. If the initial state (i.e. AP_OFF state) is different from what those
- * hooks realize, they need to be considered. This hook runs last (i.e.
- * HOOK_PRIO_LAST) to make our landing on S5 as mild as possible.
- */
-DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN_COMPLETE, hook_shutdown, HOOK_PRIO_LAST);