blob: 2575faedc0dd11c5a871c9690de1bd2a6c1401de [file] [log] [blame]
/*
* Copyright (c) 2013 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.
*/
#include <common.h>
#include <errno.h>
#include <cros/stages.h>
#include <cros/power_management.h>
#include <cros/vboot.h>
struct vboot_stage {
const char *name;
int (*run)(struct vboot_info *vboot);
};
struct vboot_stage stages[] = {
{ "ro_init", vboot_ro_init, },
{ "ro_vbinit", vboot_ro_vbinit, },
{ "ro_flags", vboot_ro_flags, },
{ "ro_selectfirmware", vboot_ro_select_firmware, },
{ "ro_prepare", vboot_ro_prepare, },
{ "ro_jump", vboot_ro_jump, },
#ifdef CONFIG_CROS_RO
{ "invalid", NULL },
{ "invalid", NULL },
{ "invalid", NULL },
#else
{ "rw_init", vboot_rw_init, },
{ "rw_selectkernel", vboot_rw_select_kernel, },
{ "rw_boot", vboot_rw_boot, },
#endif
};
const char *vboot_get_stage_name(enum vboot_stage_t stagenum)
{
if (stagenum >= VBOOT_STAGE_FIRST && stagenum < VBOOT_STAGE_COUNT)
return stages[stagenum].name;
return NULL;
}
enum vboot_stage_t vboot_find_stage(const char *name)
{
enum vboot_stage_t stagenum;
for (stagenum = VBOOT_STAGE_FIRST; stagenum < VBOOT_STAGE_COUNT;
stagenum++) {
struct vboot_stage *stage = &stages[stagenum];
if (!strcmp(name, stage->name))
return stagenum;
}
return VBOOT_STAGE_NONE;
}
int vboot_run_stage(struct vboot_info *vboot, enum vboot_stage_t stagenum)
{
struct vboot_stage *stage = &stages[stagenum];
int ret;
vboot_set_legacy(false);
VBDEBUG("Running stage '%s'\n", stage->name);
if (!stage->run) {
VBDEBUG(" - Stage '%s' not available\n", stage->name);
return -EPERM;
}
bootstage_mark_name(BOOTSTAGE_VBOOT_FIRST + stagenum, stage->name);
ret = (*stage->run)(vboot);
if (ret)
VBDEBUG("Error: stage '%s' returned %d\n", stage->name, ret);
return ret;
}
int vboot_run_stages(struct vboot_info *vboot, bool do_ro, uint flags)
{
enum vboot_stage_t start, stagenum;
int ret;
start = do_ro ? VBOOT_STAGE_RO_INIT : VBOOT_STAGE_RW_INIT;
for (stagenum = start; stagenum < VBOOT_STAGE_COUNT; stagenum++) {
ret = vboot_run_stage(vboot, stagenum);
if (ret)
break;
}
/* Allow dropping to the command line here for debugging */
if (flags & VBOOT_FLAG_CMDLINE)
return -1;
switch (vboot->vb_error) {
case VBERROR_BIOS_SHELL_REQUESTED:
return -1;
case VBERROR_EC_REBOOT_TO_RO_REQUIRED:
case VBERROR_SHUTDOWN_REQUESTED:
power_off();
break;
default:
cold_reboot();
break;
}
return 0;
}
int vboot_run_auto(struct vboot_info *vboot, uint flags)
{
return vboot_run_stages(vboot, is_processor_reset(), flags);
}