summaryrefslogtreecommitdiff
path: root/firmware/lib/region-kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/lib/region-kernel.c')
-rw-r--r--firmware/lib/region-kernel.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/firmware/lib/region-kernel.c b/firmware/lib/region-kernel.c
new file mode 100644
index 00000000..84d474da
--- /dev/null
+++ b/firmware/lib/region-kernel.c
@@ -0,0 +1,200 @@
+/* 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);
+ }
+}