mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-02 21:25:03 +00:00
Add support for update related vendor commands in mn50 by relocating relevant code from board/cr50 to chip/g. BUG=b:36910757 BRANCH=None TEST=./extra/usb_updater/usb_updater -d 18d1:502a build/mn50/ec.bin Change-Id: Iec0fe5585b5b6eb099f9254dfb0e5b02d5106abc Reviewed-on: https://chromium-review.googlesource.com/537999 Commit-Ready: Nick Sanders <nsanders@chromium.org> Tested-by: Nick Sanders <nsanders@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
151 lines
4.1 KiB
C
151 lines
4.1 KiB
C
/* Copyright 2016 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.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "console.h"
|
|
#include "endian.h"
|
|
#include "extension.h"
|
|
#include "flash.h"
|
|
#include "flash_info.h"
|
|
#include "hooks.h"
|
|
#include "signed_header.h"
|
|
#include "system.h"
|
|
#include "upgrade_fw.h"
|
|
#include "util.h"
|
|
|
|
#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args)
|
|
|
|
static void deferred_reboot(void)
|
|
{
|
|
system_reset(SYSTEM_RESET_MANUALLY_TRIGGERED | SYSTEM_RESET_HARD);
|
|
}
|
|
DECLARE_DEFERRED(deferred_reboot);
|
|
|
|
#define MAX_REBOOT_TIMEOUT_MS 1000
|
|
|
|
/*
|
|
* Verify if the header at the passed in flash offset needs to be restored,
|
|
* and restore it if so. If this is an RO header - enable writing into that RO
|
|
* section (the currently active RO writes can not be enabled).
|
|
*
|
|
* Return true if a corruption was detected and restored.
|
|
*/
|
|
static int header_restored(uint32_t offset)
|
|
{
|
|
struct SignedHeader *header;
|
|
uint32_t new_size;
|
|
|
|
header = (struct SignedHeader *)(CONFIG_PROGRAM_MEMORY_BASE + offset);
|
|
|
|
new_size = header->image_size;
|
|
if (!(new_size & TOP_IMAGE_SIZE_BIT))
|
|
return 0;
|
|
|
|
new_size &= ~TOP_IMAGE_SIZE_BIT;
|
|
/*
|
|
* Clear only in case the size is sensible (i.e. not set to all
|
|
* ones).
|
|
*/
|
|
if (new_size > CONFIG_RW_SIZE)
|
|
return 0;
|
|
|
|
if ((offset == CONFIG_RO_MEM_OFF) || (offset == CHIP_RO_B_MEM_OFF))
|
|
flash_open_ro_window(offset, sizeof(struct SignedHeader));
|
|
|
|
return flash_physical_write(offset + offsetof(struct SignedHeader,
|
|
image_size),
|
|
sizeof(header->image_size),
|
|
(char *)&new_size) == EC_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Try restoring inactive RO and RW headers, Return the number of restored
|
|
* headers.
|
|
*/
|
|
static uint8_t headers_restored(void)
|
|
{
|
|
uint8_t total_restored;
|
|
|
|
/* Examine the RO first. */
|
|
if (system_get_ro_image_copy() == SYSTEM_IMAGE_RO)
|
|
total_restored = header_restored(CHIP_RO_B_MEM_OFF);
|
|
else
|
|
total_restored = header_restored(CONFIG_RO_MEM_OFF);
|
|
|
|
/* Now the RW */
|
|
if (system_get_image_copy() == SYSTEM_IMAGE_RW)
|
|
total_restored += header_restored(CONFIG_RW_B_MEM_OFF);
|
|
else
|
|
total_restored += header_restored(CONFIG_RW_MEM_OFF);
|
|
|
|
return total_restored;
|
|
}
|
|
|
|
/*
|
|
* The TURN_UPDATE_ON command comes with a single parameter, which is a 16 bit
|
|
* integer value of the number of milliseconds to wait before reboot in case
|
|
* there has been an update waiting.
|
|
*
|
|
* Maximum wait time is 1000 ms.
|
|
*
|
|
* If the requested timeout exceeds the allowed maximum, or the command is
|
|
* malformed, a protocol error is returned.
|
|
*
|
|
* If there was no errors, the number of restored headers is returned to the
|
|
* host in a single byte.
|
|
*
|
|
* If at least one header was restored AND the host supplied a nonzero timeout
|
|
* value, the H1 will be reset after this many milliseconds.
|
|
*
|
|
* Sending this command with the zero timeout value results in reporting to
|
|
* the host how many headers were restored, the reset is not triggered.
|
|
*/
|
|
static enum vendor_cmd_rc turn_update_on(enum vendor_cmd_cc code,
|
|
void *buf,
|
|
size_t input_size,
|
|
size_t *response_size)
|
|
{
|
|
uint16_t timeout;
|
|
uint8_t *response;
|
|
|
|
/* Just in case. */
|
|
*response_size = 0;
|
|
|
|
if (input_size < sizeof(uint16_t)) {
|
|
CPRINTF("%s: incorrect request size %d\n",
|
|
__func__, input_size);
|
|
return VENDOR_RC_BOGUS_ARGS;
|
|
}
|
|
|
|
/* Retrieve the requested timeout. */
|
|
memcpy(&timeout, buf, sizeof(timeout));
|
|
timeout = be16toh(timeout);
|
|
|
|
if (timeout > MAX_REBOOT_TIMEOUT_MS) {
|
|
CPRINTF("%s: incorrect timeout value %d\n",
|
|
__func__, timeout);
|
|
return VENDOR_RC_BOGUS_ARGS;
|
|
}
|
|
|
|
*response_size = 1;
|
|
response = buf;
|
|
|
|
*response = headers_restored();
|
|
if (*response && timeout) {
|
|
/*
|
|
* At least one header was restored, and timeout is not zero,
|
|
* set up the reboot.
|
|
*/
|
|
CPRINTF("%s: rebooting in %d ms\n", __func__, timeout);
|
|
hook_call_deferred(&deferred_reboot_data, timeout * MSEC);
|
|
}
|
|
|
|
return VENDOR_RC_SUCCESS;
|
|
}
|
|
DECLARE_VENDOR_COMMAND(VENDOR_CC_TURN_UPDATE_ON, turn_update_on);
|
|
|
|
/* This command's implementation is shared with USB updater. */
|
|
DECLARE_EXTENSION_COMMAND(EXTENSION_FW_UPGRADE, fw_upgrade_command_handler);
|