1527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass * Use of this source code is governed by a BSD-style license that can be
3527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass * found in the LICENSE file.
4527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass *
5527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass * High-level firmware API for loading and verifying rewritable firmware.
6527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass * (Firmware portion)
7527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass */
8527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
9527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "sysincludes.h"
10527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
11527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "bmpblk_header.h"
12527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "region.h"
13527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "gbb_access.h"
14527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "gbb_header.h"
15527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "load_kernel_fw.h"
16527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "utility.h"
17527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "vboot_api.h"
18527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "vboot_struct.h"
19527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
20527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glassstatic VbError_t VbRegionReadGbb(VbCommonParams *cparams, uint32_t offset,
21527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				  uint32_t size, void *buf)
22527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass{
23527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	return VbRegionReadData(cparams, VB_REGION_GBB, offset, size, buf);
24527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass}
25527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
26527ba810eff4006cf69579f6b96cb4350cb1e189Simon GlassVbError_t VbGbbReadBmpHeader(VbCommonParams *cparams, BmpBlockHeader *hdr_ret)
27527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass{
28527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	BmpBlockHeader *hdr;
29527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	VbError_t ret;
30527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
31527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!cparams)
32527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_INVALID_GBB;
33527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!cparams->bmp) {
34527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		GoogleBinaryBlockHeader *gbb = cparams->gbb;
35527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
36527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		if (0 == gbb->bmpfv_size)
37527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			return VBERROR_INVALID_GBB;
38527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
39527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		hdr = VbExMalloc(sizeof(*hdr));
40527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		ret = VbRegionReadGbb(cparams, gbb->bmpfv_offset,
41527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				      sizeof(BmpBlockHeader), hdr);
42527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		if (ret) {
43527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			VbExFree(hdr);
44527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			return ret;
45527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		}
46527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
47527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		/* Sanity-check the bitmap block header */
48527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
49527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				BMPBLOCK_SIGNATURE_SIZE)) ||
50527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		(hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
51527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
52527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		(hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
53527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			VBDEBUG(("VbDisplayScreenFromGBB(): "
54527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				"invalid/too new bitmap header\n"));
55527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			VbExFree(hdr);
56527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			return VBERROR_INVALID_BMPFV;
57527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		}
58527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		cparams->bmp = hdr;
59527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	}
60527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
61527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	*hdr_ret = *cparams->bmp;
62527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	return VBERROR_SUCCESS;
63527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass}
64527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
65527ba810eff4006cf69579f6b96cb4350cb1e189Simon GlassVbError_t VbRegionReadHWID(VbCommonParams *cparams, char *hwid,
66527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			   uint32_t max_size)
67527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass{
68527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	GoogleBinaryBlockHeader *gbb;
69527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	VbError_t ret;
70527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
71527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!max_size)
72527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_INVALID_PARAMETER;
73527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	*hwid = '\0';
74527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	StrnAppend(hwid, "{INVALID}", max_size);
75527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!cparams)
76527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_INVALID_GBB;
77527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
78527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	gbb = cparams->gbb;
79527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
80527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (0 == gbb->hwid_size) {
81527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		VBDEBUG(("VbHWID(): invalid hwid size\n"));
82527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_SUCCESS; /* oddly enough! */
83527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	}
84527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
85527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (gbb->hwid_size > max_size) {
86527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		VBDEBUG(("VbDisplayDebugInfo(): invalid hwid offset/size\n"));
87527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_INVALID_PARAMETER;
88527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	}
89527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	ret = VbRegionReadGbb(cparams, gbb->hwid_offset, gbb->hwid_size, hwid);
90527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (ret)
91527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return ret;
92527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
93527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	return VBERROR_SUCCESS;
94527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass}
95527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
96527ba810eff4006cf69579f6b96cb4350cb1e189Simon GlassVbError_t VbGbbReadImage(VbCommonParams *cparams,
97527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			       uint32_t localization, uint32_t screen_index,
98527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			       uint32_t image_num, ScreenLayout *layout,
99527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			       ImageInfo *image_info, char **image_datap,
100527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			       uint32_t *image_data_sizep)
101527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass{
102527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	uint32_t layout_offset, image_offset, data_offset, data_size;
103527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	GoogleBinaryBlockHeader *gbb;
104527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	BmpBlockHeader hdr;
105527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	void *data = NULL;
106527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	VbError_t ret;
107527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
108527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!cparams)
109527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_INVALID_GBB;
110527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
111527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	ret = VbGbbReadBmpHeader(cparams, &hdr);
112527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (ret)
113527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return ret;
114527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
115527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	gbb = cparams->gbb;
116527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	layout_offset = gbb->bmpfv_offset + sizeof(BmpBlockHeader) +
117527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		localization * hdr.number_of_screenlayouts *
118527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			sizeof(ScreenLayout) +
119527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		screen_index * sizeof(ScreenLayout);
120527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	ret = VbRegionReadGbb(cparams, layout_offset, sizeof(*layout), layout);
121527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (ret)
122527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return ret;
123527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
124527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!layout->images[image_num].image_info_offset)
125527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return VBERROR_NO_IMAGE_PRESENT;
126527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
127527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	image_offset = gbb->bmpfv_offset +
128527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			layout->images[image_num].image_info_offset;
129527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	ret = VbRegionReadGbb(cparams, image_offset, sizeof(*image_info),
130527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			      image_info);
131527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (ret)
132527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return ret;
133527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
134527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	data_offset = image_offset + sizeof(*image_info);
135527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	data_size = image_info->compressed_size;
136527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (data_size) {
137527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		void *orig_data;
138527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
139527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		data = VbExMalloc(image_info->compressed_size);
140527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		ret = VbRegionReadGbb(cparams, data_offset,
141527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				      image_info->compressed_size, data);
142527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		if (ret) {
143527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			VbExFree(data);
144527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			return ret;
145527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		}
146527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		if (image_info->compression != COMPRESS_NONE) {
147527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			uint32_t inoutsize = image_info->original_size;
148527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
149527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			orig_data = VbExMalloc(image_info->original_size);
150527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			ret = VbExDecompress(data,
151527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass					     image_info->compressed_size,
152527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass					     image_info->compression,
153527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass					     orig_data, &inoutsize);
154527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			data_size = inoutsize;
155527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			VbExFree(data);
156527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			data = orig_data;
157527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			if (ret) {
158527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				VbExFree(data);
159527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				return ret;
160527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			}
161527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		}
162527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	}
163527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
164527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	*image_datap = data;
165527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	*image_data_sizep = data_size;
166527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
167527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	return VBERROR_SUCCESS;
168527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass}
169527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
170527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#define OUTBUF_LEN 128
171527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
172527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glassvoid VbRegionCheckVersion(VbCommonParams *cparams)
173527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass{
174527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	GoogleBinaryBlockHeader *gbb;
175527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
176527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (!cparams)
177527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		return;
178527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
179527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	gbb = cparams->gbb;
180527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
181527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	/*
182527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	 * If GBB flags is nonzero, complain because that's something that the
183527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	 * factory MUST fix before shipping. We only have to do this here,
184527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	 * because it's obvious that something is wrong if we're not displaying
185527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	 * screens from the GBB.
186527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	 */
187527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 &&
188527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	    (gbb->flags != 0)) {
189527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		uint32_t used = 0;
190527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		char outbuf[OUTBUF_LEN];
191527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
192527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		*outbuf = '\0';
193527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		used += StrnAppend(outbuf + used, "gbb.flags is nonzero: 0x",
194527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				OUTBUF_LEN - used);
195527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		used += Uint64ToString(outbuf + used, OUTBUF_LEN - used,
196527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass				       gbb->flags, 16, 8);
197527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		used += StrnAppend(outbuf + used, "\n", OUTBUF_LEN - used);
198527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		(void)VbExDisplayDebugInfo(outbuf);
199527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	}
200527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass}
201