/* 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); } }