mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-02 21:25:03 +00:00
Keyboard scan module now owns the recovery key state on all platforms. And clean up a few comments to linux kernel style BUG=chrome-os-partner:10890 TEST=manual - Power on system. Should boot normally. - Power+Refresh+D. Should turn dev switch on. - Power+Refresh+F. Should turn dev switch off. - Power+Esc. Should reboot system. Power button should power on normally. - Power+Refresh+Esc. Should power on into recovery mode. - Then press power to shut system down. - Power button should power on normally (not back into recovery mode). Change-Id: I4d16e1e8b039efeacbd41e8acec115844bc8457d Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/26147 Reviewed-by: Simon Glass <sjg@chromium.org>
193 lines
4.8 KiB
C
193 lines
4.8 KiB
C
/* Copyright (c) 2012 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.
|
|
*/
|
|
|
|
/* Verified boot module for Chrome EC */
|
|
|
|
#include "board.h"
|
|
#include "config.h"
|
|
#include "console.h"
|
|
#include "cryptolib.h"
|
|
#include "gpio.h"
|
|
#include "system.h"
|
|
#include "timer.h"
|
|
#include "util.h"
|
|
#include "vboot.h"
|
|
#include "vboot_api.h"
|
|
#include "vboot_common.h"
|
|
#include "vboot_struct.h"
|
|
#include "watchdog.h"
|
|
|
|
/* Console output macros */
|
|
#define CPUTS(outstr) cputs(CC_VBOOT, outstr)
|
|
#define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args)
|
|
|
|
enum howgood {
|
|
IMAGE_IS_BAD,
|
|
IMAGE_IS_GOOD,
|
|
IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY,
|
|
};
|
|
|
|
static enum howgood good_image(uint8_t *key_data,
|
|
uint8_t *vblock_data, uint32_t vblock_size,
|
|
uint8_t *fv_data, uint32_t fv_size) {
|
|
VbPublicKey *sign_key;
|
|
VbKeyBlockHeader *key_block;
|
|
VbECPreambleHeader *preamble;
|
|
uint32_t now = 0;
|
|
RSAPublicKey *rsa;
|
|
|
|
key_block = (VbKeyBlockHeader *)vblock_data;
|
|
sign_key = (VbPublicKey *)key_data;
|
|
|
|
watchdog_reload();
|
|
if (0 != KeyBlockVerify(key_block, vblock_size, sign_key, 0)) {
|
|
CPRINTF("[Error verifying key block]\n");
|
|
return IMAGE_IS_BAD;
|
|
}
|
|
|
|
now += key_block->key_block_size;
|
|
rsa = PublicKeyToRSA(&key_block->data_key);
|
|
if (!rsa) {
|
|
CPRINTF("[Error parsing data key]\n");
|
|
return IMAGE_IS_BAD;
|
|
}
|
|
|
|
watchdog_reload();
|
|
preamble = (VbECPreambleHeader *)(vblock_data + now);
|
|
if (0 != VerifyECPreamble(preamble, vblock_size - now, rsa)) {
|
|
CPRINTF("[Error verifying preamble]\n");
|
|
RSAPublicKeyFree(rsa);
|
|
return IMAGE_IS_BAD;
|
|
}
|
|
|
|
if (preamble->flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
|
|
CPRINTF("[Flags says USE_RO_NORMAL]\n");
|
|
RSAPublicKeyFree(rsa);
|
|
return IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY;
|
|
}
|
|
|
|
watchdog_reload();
|
|
if (0 != EqualData(fv_data, fv_size, &preamble->body_digest, rsa)) {
|
|
CPRINTF("Error verifying firmware body]\n");
|
|
RSAPublicKeyFree(rsa);
|
|
return IMAGE_IS_BAD;
|
|
}
|
|
|
|
RSAPublicKeyFree(rsa);
|
|
|
|
watchdog_reload();
|
|
CPRINTF("[Verified!]\n");
|
|
return IMAGE_IS_GOOD;
|
|
}
|
|
|
|
/* Might I want to jump to one of the RW images? */
|
|
static int maybe_jump_to_other_image(void)
|
|
{
|
|
/* We'll only jump to another image if we're currently in RO */
|
|
if (system_get_image_copy() != SYSTEM_IMAGE_RO)
|
|
return 0;
|
|
|
|
#ifdef CONFIG_TASK_KEYSCAN
|
|
/* Don't jump if recovery requested */
|
|
if (keyboard_scan_recovery_pressed()) {
|
|
CPUTS("[Vboot staying in RO because recovery key pressed]\n");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Don't jump if we're in RO becuase we jumped there (this keeps us
|
|
* from jumping to RO only to jump right back).
|
|
*/
|
|
if (system_jumped_to_this_image())
|
|
return 0;
|
|
|
|
#if !defined(CHIP_stm32)
|
|
/*
|
|
* TODO: (crosbug.com/p/8572) Daisy and Snow don't define a GPIO for
|
|
* the recovery signal from servo, so we can't check it. BDS uses the
|
|
* DOWN button.
|
|
*/
|
|
if (gpio_get_level(GPIO_RECOVERYn) == 0) {
|
|
CPUTS("[Vboot staying in RO due to recovery signal]\n");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Okay, we might want to jump to a RW image. */
|
|
return 1;
|
|
}
|
|
|
|
int vboot_check_signature(void)
|
|
{
|
|
enum howgood r;
|
|
timestamp_t ts1, ts2;
|
|
|
|
CPRINTF("[%T Vboot init]\n");
|
|
|
|
if (!maybe_jump_to_other_image())
|
|
return EC_SUCCESS;
|
|
|
|
CPRINTF("[%T Vboot check image A...]\n");
|
|
|
|
ts1 = get_time();
|
|
r = good_image((uint8_t *)CONFIG_VBOOT_ROOTKEY_OFF,
|
|
(uint8_t *)CONFIG_VBLOCK_A_OFF, CONFIG_VBLOCK_SIZE,
|
|
(uint8_t *)CONFIG_FW_A_OFF, CONFIG_FW_A_SIZE);
|
|
ts2 = get_time();
|
|
|
|
CPRINTF("[%T Vboot result=%d, elapsed time=%ld us]\n",
|
|
r, ts2.val - ts1.val);
|
|
|
|
switch (r) {
|
|
case IMAGE_IS_GOOD:
|
|
CPRINTF("[Image A verified]\n");
|
|
system_run_image_copy(SYSTEM_IMAGE_RW_A);
|
|
CPRINTF("[ERROR: Unable to jump to image A]\n");
|
|
goto bad;
|
|
case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY:
|
|
CPRINTF("[Image A verified]\n");
|
|
CPRINTF("[Staying in RO mode]\n");
|
|
return EC_SUCCESS;
|
|
default:
|
|
CPRINTF("[Image A is invalid]\n");
|
|
}
|
|
|
|
#ifdef CONFIG_RW_B
|
|
CPRINTF("[%T Vboot check image B...]\n");
|
|
|
|
ts1 = get_time();
|
|
r = good_image((uint8_t *)CONFIG_VBOOT_ROOTKEY_OFF,
|
|
(uint8_t *)CONFIG_VBLOCK_B_OFF, CONFIG_VBLOCK_SIZE,
|
|
(uint8_t *)CONFIG_FW_B_OFF, CONFIG_FW_B_SIZE);
|
|
ts2 = get_time();
|
|
|
|
CPRINTF("[%T Vboot result=%d, elapsed time=%ld us]\n",
|
|
r, ts2.val - ts1.val);
|
|
|
|
switch (r) {
|
|
case IMAGE_IS_GOOD:
|
|
CPRINTF("[Image B verified]\n");
|
|
system_run_image_copy(SYSTEM_IMAGE_RW_B);
|
|
CPRINTF("[ERROR: Unable to jump to image B]\n");
|
|
goto bad;
|
|
case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY:
|
|
CPRINTF("[Image B verified]\n");
|
|
CPRINTF("[Staying in RO mode]\n");
|
|
return EC_SUCCESS;
|
|
default:
|
|
CPRINTF("[Image B is invalid]\n");
|
|
}
|
|
#else /* CONFIG_RW_B */
|
|
CPRINTF("[Vboot no image B to check]\n");
|
|
#endif /* CONFIG_RW_B */
|
|
|
|
bad:
|
|
CPRINTF("[Staying in RO mode]\n");
|
|
CPRINTF("[FIXME: How to trigger recovery mode?]\n");
|
|
return EC_ERROR_UNKNOWN;
|
|
}
|
|
|