You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.0 KiB
201 lines
5.0 KiB
/* 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.
|
|
*
|
|
* High-level firmware API for loading and verifying rewritable firmware.
|
|
* (Firmware portion)
|
|
*/
|
|
|
|
#include "sysincludes.h"
|
|
|
|
#include "bmpblk_header.h"
|
|
#include "region.h"
|
|
#include "gbb_access.h"
|
|
#include "gbb_header.h"
|
|
#include "load_kernel_fw.h"
|
|
#include "utility.h"
|
|
#include "vboot_api.h"
|
|
#include "vboot_struct.h"
|
|
|
|
static VbError_t VbRegionReadGbb(VbCommonParams *cparams, uint32_t offset,
|
|
uint32_t size, void *buf)
|
|
{
|
|
return VbRegionReadData(cparams, VB_REGION_GBB, offset, size, buf);
|
|
}
|
|
|
|
VbError_t VbGbbReadBmpHeader(VbCommonParams *cparams, BmpBlockHeader *hdr_ret)
|
|
{
|
|
BmpBlockHeader *hdr;
|
|
VbError_t ret;
|
|
|
|
if (!cparams)
|
|
return VBERROR_INVALID_GBB;
|
|
if (!cparams->bmp) {
|
|
GoogleBinaryBlockHeader *gbb = cparams->gbb;
|
|
|
|
if (0 == gbb->bmpfv_size)
|
|
return VBERROR_INVALID_GBB;
|
|
|
|
hdr = VbExMalloc(sizeof(*hdr));
|
|
ret = VbRegionReadGbb(cparams, gbb->bmpfv_offset,
|
|
sizeof(BmpBlockHeader), hdr);
|
|
if (ret) {
|
|
VbExFree(hdr);
|
|
return ret;
|
|
}
|
|
|
|
/* Sanity-check the bitmap block header */
|
|
if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
|
|
BMPBLOCK_SIGNATURE_SIZE)) ||
|
|
(hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
|
|
((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
|
|
(hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
|
|
VBDEBUG(("VbDisplayScreenFromGBB(): "
|
|
"invalid/too new bitmap header\n"));
|
|
VbExFree(hdr);
|
|
return VBERROR_INVALID_BMPFV;
|
|
}
|
|
cparams->bmp = hdr;
|
|
}
|
|
|
|
*hdr_ret = *cparams->bmp;
|
|
return VBERROR_SUCCESS;
|
|
}
|
|
|
|
VbError_t VbRegionReadHWID(VbCommonParams *cparams, char *hwid,
|
|
uint32_t max_size)
|
|
{
|
|
GoogleBinaryBlockHeader *gbb;
|
|
VbError_t ret;
|
|
|
|
if (!max_size)
|
|
return VBERROR_INVALID_PARAMETER;
|
|
*hwid = '\0';
|
|
StrnAppend(hwid, "{INVALID}", max_size);
|
|
if (!cparams)
|
|
return VBERROR_INVALID_GBB;
|
|
|
|
gbb = cparams->gbb;
|
|
|
|
if (0 == gbb->hwid_size) {
|
|
VBDEBUG(("VbHWID(): invalid hwid size\n"));
|
|
return VBERROR_SUCCESS; /* oddly enough! */
|
|
}
|
|
|
|
if (gbb->hwid_size > max_size) {
|
|
VBDEBUG(("VbDisplayDebugInfo(): invalid hwid offset/size\n"));
|
|
return VBERROR_INVALID_PARAMETER;
|
|
}
|
|
ret = VbRegionReadGbb(cparams, gbb->hwid_offset, gbb->hwid_size, hwid);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return VBERROR_SUCCESS;
|
|
}
|
|
|
|
VbError_t VbGbbReadImage(VbCommonParams *cparams,
|
|
uint32_t localization, uint32_t screen_index,
|
|
uint32_t image_num, ScreenLayout *layout,
|
|
ImageInfo *image_info, char **image_datap,
|
|
uint32_t *image_data_sizep)
|
|
{
|
|
uint32_t layout_offset, image_offset, data_offset, data_size;
|
|
GoogleBinaryBlockHeader *gbb;
|
|
BmpBlockHeader hdr;
|
|
void *data = NULL;
|
|
VbError_t ret;
|
|
|
|
if (!cparams)
|
|
return VBERROR_INVALID_GBB;
|
|
|
|
ret = VbGbbReadBmpHeader(cparams, &hdr);
|
|
if (ret)
|
|
return ret;
|
|
|
|
gbb = cparams->gbb;
|
|
layout_offset = gbb->bmpfv_offset + sizeof(BmpBlockHeader) +
|
|
localization * hdr.number_of_screenlayouts *
|
|
sizeof(ScreenLayout) +
|
|
screen_index * sizeof(ScreenLayout);
|
|
ret = VbRegionReadGbb(cparams, layout_offset, sizeof(*layout), layout);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (!layout->images[image_num].image_info_offset)
|
|
return VBERROR_NO_IMAGE_PRESENT;
|
|
|
|
image_offset = gbb->bmpfv_offset +
|
|
layout->images[image_num].image_info_offset;
|
|
ret = VbRegionReadGbb(cparams, image_offset, sizeof(*image_info),
|
|
image_info);
|
|
if (ret)
|
|
return ret;
|
|
|
|
data_offset = image_offset + sizeof(*image_info);
|
|
data_size = image_info->compressed_size;
|
|
if (data_size) {
|
|
void *orig_data;
|
|
|
|
data = VbExMalloc(image_info->compressed_size);
|
|
ret = VbRegionReadGbb(cparams, data_offset,
|
|
image_info->compressed_size, data);
|
|
if (ret) {
|
|
VbExFree(data);
|
|
return ret;
|
|
}
|
|
if (image_info->compression != COMPRESS_NONE) {
|
|
uint32_t inoutsize = image_info->original_size;
|
|
|
|
orig_data = VbExMalloc(image_info->original_size);
|
|
ret = VbExDecompress(data,
|
|
image_info->compressed_size,
|
|
image_info->compression,
|
|
orig_data, &inoutsize);
|
|
data_size = inoutsize;
|
|
VbExFree(data);
|
|
data = orig_data;
|
|
if (ret) {
|
|
VbExFree(data);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
*image_datap = data;
|
|
*image_data_sizep = data_size;
|
|
|
|
return VBERROR_SUCCESS;
|
|
}
|
|
|
|
#define OUTBUF_LEN 128
|
|
|
|
void VbRegionCheckVersion(VbCommonParams *cparams)
|
|
{
|
|
GoogleBinaryBlockHeader *gbb;
|
|
|
|
if (!cparams)
|
|
return;
|
|
|
|
gbb = cparams->gbb;
|
|
|
|
/*
|
|
* If GBB flags is nonzero, complain because that's something that the
|
|
* factory MUST fix before shipping. We only have to do this here,
|
|
* because it's obvious that something is wrong if we're not displaying
|
|
* screens from the GBB.
|
|
*/
|
|
if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 &&
|
|
(gbb->flags != 0)) {
|
|
uint32_t used = 0;
|
|
char outbuf[OUTBUF_LEN];
|
|
|
|
*outbuf = '\0';
|
|
used += StrnAppend(outbuf + used, "gbb.flags is nonzero: 0x",
|
|
OUTBUF_LEN - used);
|
|
used += Uint64ToString(outbuf + used, OUTBUF_LEN - used,
|
|
gbb->flags, 16, 8);
|
|
used += StrnAppend(outbuf + used, "\n", OUTBUF_LEN - used);
|
|
(void)VbExDisplayDebugInfo(outbuf);
|
|
}
|
|
}
|