blob: b5966b46b793a467f05ecdcfb3f46e76f9b05446 [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 <bootstage.h>
#include <malloc.h>
#include <tss_constants.h>
#include <asm/io.h>
#include <cros/boot_kernel.h>
#include <cros/cros_init.h>
#include <cros/nvstorage.h>
#include <cros/vboot.h>
DECLARE_GLOBAL_DATA_PTR;
int vboot_rw_init(struct vboot_info *vboot)
{
const void *blob = gd->fdt_blob;
fdt_addr_t base;
const void *cdata_fdt;
fdt_size_t size;
memset(vboot, '\0', sizeof(*vboot));
vboot->valid = true;
#ifdef CONFIG_BOOTSTAGE_STASH
bootstage_unstash((void *)CONFIG_BOOTSTAGE_STASH,
CONFIG_BOOTSTAGE_STASH_SIZE);
#endif
bootstage_mark_name(BOOTSTAGE_ID_ALLOC, "vboot_readwrite");
VBDEBUG("Starting read-write firmware\n");
if (cros_init()) {
VBDEBUG("fail to init cros library\n");
return -1;
}
if (vboot_load_config(blob, vboot)) {
VBDEBUG("failed to read /chromeos-config\n");
return -1;
}
/* Since we made it to U-Boot RW we can clear the persist info */
vboot_persist_clear(vboot);
if (cros_fdtdec_flashmap(blob, &vboot->fmap)) {
VBDEBUG("failed to decode fmap\n");
return -1;
}
if (cros_fdtdec_decode_region(blob, "cros-system-data",
vboot->use_efs ? ",efs" : NULL,
&base, &size)) {
VBDEBUG("Cannot find cdata FDT\n");
return -1;
}
VBDEBUG("Reading cdata from FDT at %08lx\n", (ulong)base);
cdata_fdt = map_sysmem(base, size);
if (vboot_read_from_fdt(vboot, cdata_fdt)) {
VBDEBUG("Cannot read cdata FDT\n");
return -1;
}
VBDEBUG("RO firmware requests '%s'\n", vboot->firmware_type);
if (!vboot->nvcontext_method) {
VBDEBUG("No selected nvcontext method\n");
vboot_dump(vboot);
return -1;
}
/* TODO(sjg@chromium.org): We should not need this - remove? */
if (firmware_storage_open(&vboot->file)) {
VBDEBUG("failed to open firmware storage\n");
return -1;
}
/*
* VbSelectAndLoadKernel() assumes the TPM interface has already been
* initialized by VbSelectFirmware(). Since we haven't called
* VbSelectFirmware() in the readwrite firmware, we need to explicitly
* initialize the TPM interface. Note that this only re-initializes the
* interface, not the TPM itself.
*/
if (VbExTpmInit() != TPM_SUCCESS) {
VBDEBUG("failed to init tpm interface\n");
return -1;
}
return 0;
}
int vboot_rw_select_kernel(struct vboot_info *vboot)
{
VbSelectAndLoadKernelParams *kparams = &vboot->kparams;
VbError_t err;
fdt_addr_t base;
fdt_size_t size;
vboot_init_cparams(vboot, &vboot->cparams);
if (cros_fdtdec_decode_region(gd->fdt_blob, "kernel", NULL,
&base, &size)) {
VBDEBUG("No kernel load address specified\n");
return -1;
}
kparams->kernel_buffer = map_sysmem(base, size);
kparams->kernel_buffer_size = size;
VBDEBUG("kparams:\n");
VBDEBUG("- kernel_buffer: : %08x\n",
(unsigned)map_to_sysmem(kparams->kernel_buffer));
VBDEBUG("- kernel_buffer_size: : %08x\n",
kparams->kernel_buffer_size);
err = VbSelectAndLoadKernel(&vboot->cparams, kparams);
if (err) {
VBDEBUG("VbSelectAndLoadKernel: %d\n", err);
vboot_set_error(vboot, "VbSelectAndLoadKernel", err);
if (err == VBERROR_EC_REBOOT_TO_RO_REQUIRED)
vboot_request_ec_reboot_to_ro();
return -1;
}
VBDEBUG("kparams:\n");
VBDEBUG("- kernel_buffer: : %08x\n",
(unsigned)map_to_sysmem(kparams->kernel_buffer));
VBDEBUG("- kernel_buffer_size: : %08x\n", kparams->kernel_buffer_size);
VBDEBUG("- disk_handle: : %p\n", kparams->disk_handle);
VBDEBUG("- partition_number: : %08x\n", kparams->partition_number);
VBDEBUG("- bootloader_address: : %08llx\n",
(unsigned long long)kparams->bootloader_address);
VBDEBUG("- bootloader_size: : %08x\n", kparams->bootloader_size);
VBDEBUG("- partition_guid: :");
#ifdef VBOOT_DEBUG
int i;
for (i = 0; i < 16; i++)
VbExDebug(" %02x", kparams->partition_guid[i]);
VbExDebug("\n");
#endif /* VBOOT_DEBUG */
/*
* EC might jump between RO and RW during software sync. We need to
* update active EC copy
*/
int in_rw = 0;
int rv;
/* If software sync is disabled, just leave this as original value. */
vboot->active_ec_firmware = ACTIVE_EC_FIRMWARE_UNCHANGE;
if (cros_fdtdec_config_has_prop(gd->fdt_blob, "ec-software-sync")) {
rv = VbExEcRunningRW(0, &in_rw);
if (rv == VBERROR_SUCCESS) {
vboot->active_ec_firmware = in_rw ?
ACTIVE_EC_FIRMWARE_RW :
ACTIVE_EC_FIRMWARE_RO;
}
}
vboot_dump(vboot);
return 0;
}
int vboot_rw_boot(struct vboot_info *vboot)
{
boot_kernel(vboot, &vboot->kparams, NULL);
/* Should not get here */
return -1;
}