| Index: common/cmd_cros_rec.c
|
| diff --git a/common/cmd_cros_rec.c b/common/cmd_cros_rec.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fba8b86243b7b0fa01da297747d0b2f4a8cb5adb
|
| --- /dev/null
|
| +++ b/common/cmd_cros_rec.c
|
| @@ -0,0 +1,264 @@
|
| +/*
|
| + * Copyright (c) 2011 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.
|
| + *
|
| + * Alternatively, this software may be distributed under the terms of the
|
| + * GNU General Public License ("GPL") version 2 as published by the Free
|
| + * Software Foundation.
|
| + */
|
| +
|
| +/* Debug commands for Chrome OS recovery mode firmware */
|
| +
|
| +#include <common.h>
|
| +#include <command.h>
|
| +#include <lcd.h>
|
| +#include <malloc.h>
|
| +#include <mmc.h>
|
| +#include <usb.h>
|
| +
|
| +#include <bmpblk_header.h>
|
| +#include <chromeos/gbb_bmpblk.h>
|
| +#include <chromeos/hardware_interface.h>
|
| +
|
| +#include <gbb_header.h>
|
| +#include <load_firmware_fw.h>
|
| +#include <load_kernel_fw.h>
|
| +#include <chromeos/boot_device_impl.h>
|
| +
|
| +#define PREFIX "cros_rec: "
|
| +
|
| +#ifdef VBOOT_DEBUG
|
| +#define WARN_ON_FAILURE(action) do { \
|
| + int return_code = (action); \
|
| + if (return_code != 0) \
|
| + debug(PREFIX "%s failed, returning %d\n", \
|
| + #action, return_code); \
|
| +} while (0)
|
| +#else
|
| +#define WARN_ON_FAILURE(action) action
|
| +#endif
|
| +
|
| +/* MMC dev number of SD card */
|
| +#define MMC_DEV_NUM_SD 1
|
| +
|
| +#define WAIT_MS_BETWEEN_PROBING 200
|
| +
|
| +uint8_t *g_gbb_base = NULL;
|
| +int g_is_dev = 0;
|
| +
|
| +static void sleep_ms(int msecond)
|
| +{
|
| + const ulong start = get_timer(0);
|
| + const ulong delay = msecond * CONFIG_SYS_HZ / 1000;
|
| +
|
| + while (!ctrlc() && get_timer(start) < delay)
|
| + udelay(100);
|
| +}
|
| +
|
| +static int is_mmc_storage_present(void)
|
| +{
|
| + return mmc_legacy_init(MMC_DEV_NUM_SD) == 0;
|
| +}
|
| +
|
| +static int is_usb_storage_present(void)
|
| +{
|
| + int i;
|
| + /* TODO: Seek a better way to probe USB instead of restart it */
|
| + usb_stop();
|
| + i = usb_init();
|
| +#ifdef CONFIG_USB_STORAGE
|
| + if (i >= 0) {
|
| + /* Scanning bus for storage devices, mode = 1. */
|
| + return usb_stor_scan(1) == 0;
|
| + }
|
| +#else
|
| + return i;
|
| +#endif
|
| +}
|
| +
|
| +static int write_log(void)
|
| +{
|
| + /* TODO: Implement it when Chrome OS firmware logging is ready. */
|
| + return 0;
|
| +}
|
| +
|
| +static int clear_ram_not_in_use(void)
|
| +{
|
| + /* TODO: Implement it when the memory layout is defined. */
|
| + return 0;
|
| +}
|
| +
|
| +static int load_and_boot_kernel(uint8_t *load_addr, size_t load_size)
|
| +{
|
| + LoadKernelParams par;
|
| + block_dev_desc_t *dev_desc;
|
| + VbNvContext vnc;
|
| + int i, status;
|
| + GoogleBinaryBlockHeader *gbbh = (GoogleBinaryBlockHeader *)g_gbb_base;
|
| + char buffer[CONFIG_SYS_CBSIZE];
|
| +
|
| + if ((dev_desc = get_bootdev()) == NULL) {
|
| + printf(PREFIX "No boot device set yet\n");
|
| + return 1;
|
| + }
|
| +
|
| + par.gbb_data = g_gbb_base;
|
| + par.gbb_size = CONFIG_LENGTH_GBB;
|
| + par.shared_data_blob = NULL;
|
| + par.shared_data_size = 0;
|
| + par.bytes_per_lba = (uint64_t) dev_desc->blksz;
|
| + par.ending_lba = (uint64_t) get_limit() - 1;
|
| + par.kernel_buffer = load_addr;
|
| + par.kernel_buffer_size = load_size;
|
| + par.boot_flags = BOOT_FLAG_RECOVERY | BOOT_FLAG_SKIP_ADDR_CHECK;
|
| + /* TODO: load vnc.raw from NV storage */
|
| + par.nv_context = &vnc;
|
| +
|
| + if (g_is_dev) {
|
| + par.boot_flags |= BOOT_FLAG_DEVELOPER;
|
| + }
|
| +
|
| + status = LoadKernel(&par);
|
| +
|
| + if (vnc.raw_changed) {
|
| + /* TODO: save vnc.raw to NV storage */
|
| + }
|
| +
|
| + switch (status) {
|
| + case LOAD_KERNEL_SUCCESS:
|
| + printf(PREFIX "Success; good kernel found on device\n");
|
| + printf(PREFIX "partition_number: %lld\n",
|
| + par.partition_number);
|
| + printf(PREFIX "bootloader_address: 0x%llx\n",
|
| + par.bootloader_address);
|
| + printf(PREFIX "bootloader_size: 0x%llx\n", par.bootloader_size);
|
| + printf(PREFIX "partition_guid: ");
|
| + for (i = 0; i < 16; i++)
|
| + printf("%02x", par.partition_guid[i]);
|
| + putc('\n');
|
| +
|
| + lcd_clear();
|
| +
|
| + strcpy(buffer, "console=ttyS0,115200n8 ");
|
| + strcat(buffer, getenv("platform_extras"));
|
| + setenv("bootargs", buffer);
|
| + sprintf(buffer, "%lld", par.partition_number + 1);
|
| + setenv("rootpart", buffer);
|
| +
|
| + source(CONFIG_LOADADDR + par.bootloader_address -
|
| + 0x100000, NULL);
|
| + run_command("bootm ${loadaddr}", 0);
|
| + break;
|
| + case LOAD_KERNEL_NOT_FOUND:
|
| + printf(PREFIX "No kernel found on device\n");
|
| + break;
|
| + case LOAD_KERNEL_INVALID:
|
| + printf(PREFIX "Only invalid kernels found on device\n");
|
| + break;
|
| + case LOAD_KERNEL_RECOVERY:
|
| + printf(PREFIX "Internal error; reboot to recovery mode\n");
|
| + break;
|
| + case LOAD_KERNEL_REBOOT:
|
| + printf(PREFIX "Internal error; reboot to current mode\n");
|
| + break;
|
| + default:
|
| + printf(PREFIX "Unexpected return status from LoadKernel: %d\n",
|
| + status);
|
| + return 1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +static int load_recovery_image_in_mmc(void)
|
| +{
|
| + char buffer[CONFIG_SYS_CBSIZE];
|
| + sprintf(buffer, "mmcblk%dp", MMC_DEV_NUM_SD);
|
| + setenv("devname", buffer);
|
| + set_bootdev("mmc", MMC_DEV_NUM_SD, 0);
|
| + return load_and_boot_kernel((uint8_t *)CONFIG_LOADADDR, 0x01000000);
|
| +}
|
| +
|
| +static int load_recovery_image_in_usb(void)
|
| +{
|
| + /* TODO: Find the correct dev num of USB storage instead of always 0 */
|
| + setenv("devname", "sda");
|
| + set_bootdev("usb", 0, 0);
|
| + return load_and_boot_kernel((uint8_t *)CONFIG_LOADADDR, 0x01000000);
|
| +}
|
| +
|
| +static int init_gbb_in_ram(void)
|
| +{
|
| + firmware_storage_t file;
|
| + if (init_firmware_storage(&file)) {
|
| + debug(PREFIX "init_firmware_storage failed\n");
|
| + return -1;
|
| + }
|
| + g_gbb_base = malloc(CONFIG_LENGTH_GBB);
|
| + if (!g_gbb_base) {
|
| + debug(PREFIX "Unable to malloc g_gbb_base\n");
|
| + return -1;
|
| + }
|
| + if (read_firmware_device(&file, CONFIG_OFFSET_GBB, g_gbb_base,
|
| + CONFIG_LENGTH_GBB)) {
|
| + debug(PREFIX "Unable to read firmware to g_gbb_base\n");
|
| + return -1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +static int show_screen(ScreenIndex scr)
|
| +{
|
| + static ScreenIndex cur_scr;
|
| + if (cur_scr == scr) {
|
| + return 0;
|
| + } else {
|
| + cur_scr = scr;
|
| + return display_screen_in_bmpblk(g_gbb_base, scr);
|
| + }
|
| +}
|
| +
|
| +int do_cros_rec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
| +{
|
| + WARN_ON_FAILURE(write_log());
|
| + WARN_ON_FAILURE(clear_ram_not_in_use());
|
| + WARN_ON_FAILURE(init_gbb_in_ram());
|
| +
|
| + g_is_dev = is_developer_mode_gpio_asserted();
|
| +
|
| + if (!g_is_dev) {
|
| + /* Wait for user to plug out SD card and USB storage device */
|
| + while (is_mmc_storage_present() || is_usb_storage_present()) {
|
| + show_screen(SCREEN_RECOVERY_MODE);
|
| + sleep_ms(WAIT_MS_BETWEEN_PROBING);
|
| + }
|
| + }
|
| +
|
| + for (;;) {
|
| + /* Wait for user to plug in SD card or USB storage device */
|
| + while (!is_mmc_storage_present() && !is_usb_storage_present()) {
|
| + show_screen(SCREEN_RECOVERY_NO_OS);
|
| + sleep_ms(WAIT_MS_BETWEEN_PROBING);
|
| + }
|
| + if (is_mmc_storage_present()) {
|
| + WARN_ON_FAILURE(load_recovery_image_in_mmc());
|
| + /* Wait for user to plug out SD card */
|
| + while (is_mmc_storage_present()) {
|
| + show_screen(SCREEN_RECOVERY_MISSING_OS);
|
| + sleep_ms(WAIT_MS_BETWEEN_PROBING);
|
| + }
|
| + } else if (is_usb_storage_present()) {
|
| + WARN_ON_FAILURE(load_recovery_image_in_usb());
|
| + /* Wait for user to plug out USB storage device */
|
| + while (is_usb_storage_present()) {
|
| + show_screen(SCREEN_RECOVERY_MISSING_OS);
|
| + sleep_ms(WAIT_MS_BETWEEN_PROBING);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /* This point is never reached */
|
| + return 0;
|
| +}
|
| +
|
| +U_BOOT_CMD(cros_rec, 1, 1, do_cros_rec, "recovery mode firmware", NULL);
|
|
|