1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * High-level firmware API for loading and verifying rewritable firmware.
6  * (Firmware portion)
7  */
8 
9 #include "sysincludes.h"
10 
11 #include "bmpblk_header.h"
12 #include "region.h"
13 #include "gbb_access.h"
14 #include "gbb_header.h"
15 #include "load_kernel_fw.h"
16 #include "utility.h"
17 #include "vboot_api.h"
18 #include "vboot_struct.h"
19 
VbRegionReadGbb(VbCommonParams * cparams,uint32_t offset,uint32_t size,void * buf)20 static VbError_t VbRegionReadGbb(VbCommonParams *cparams, uint32_t offset,
21 				  uint32_t size, void *buf)
22 {
23 	return VbRegionReadData(cparams, VB_REGION_GBB, offset, size, buf);
24 }
25 
VbGbbReadBmpHeader(VbCommonParams * cparams,BmpBlockHeader * hdr_ret)26 VbError_t VbGbbReadBmpHeader(VbCommonParams *cparams, BmpBlockHeader *hdr_ret)
27 {
28 	BmpBlockHeader *hdr;
29 	VbError_t ret;
30 
31 	if (!cparams)
32 		return VBERROR_INVALID_GBB;
33 	if (!cparams->bmp) {
34 		GoogleBinaryBlockHeader *gbb = cparams->gbb;
35 
36 		if (0 == gbb->bmpfv_size)
37 			return VBERROR_INVALID_GBB;
38 
39 		hdr = VbExMalloc(sizeof(*hdr));
40 		ret = VbRegionReadGbb(cparams, gbb->bmpfv_offset,
41 				      sizeof(BmpBlockHeader), hdr);
42 		if (ret) {
43 			VbExFree(hdr);
44 			return ret;
45 		}
46 
47 		/* Sanity-check the bitmap block header */
48 		if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
49 				BMPBLOCK_SIGNATURE_SIZE)) ||
50 		(hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
51 		((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
52 		(hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
53 			VBDEBUG(("VbDisplayScreenFromGBB(): "
54 				"invalid/too new bitmap header\n"));
55 			VbExFree(hdr);
56 			return VBERROR_INVALID_BMPFV;
57 		}
58 		cparams->bmp = hdr;
59 	}
60 
61 	*hdr_ret = *cparams->bmp;
62 	return VBERROR_SUCCESS;
63 }
64 
VbRegionReadHWID(VbCommonParams * cparams,char * hwid,uint32_t max_size)65 VbError_t VbRegionReadHWID(VbCommonParams *cparams, char *hwid,
66 			   uint32_t max_size)
67 {
68 	GoogleBinaryBlockHeader *gbb;
69 	VbError_t ret;
70 
71 	if (!max_size)
72 		return VBERROR_INVALID_PARAMETER;
73 	*hwid = '\0';
74 	StrnAppend(hwid, "{INVALID}", max_size);
75 	if (!cparams)
76 		return VBERROR_INVALID_GBB;
77 
78 	gbb = cparams->gbb;
79 
80 	if (0 == gbb->hwid_size) {
81 		VBDEBUG(("VbHWID(): invalid hwid size\n"));
82 		return VBERROR_SUCCESS; /* oddly enough! */
83 	}
84 
85 	if (gbb->hwid_size > max_size) {
86 		VBDEBUG(("VbDisplayDebugInfo(): invalid hwid offset/size\n"));
87 		return VBERROR_INVALID_PARAMETER;
88 	}
89 	ret = VbRegionReadGbb(cparams, gbb->hwid_offset, gbb->hwid_size, hwid);
90 	if (ret)
91 		return ret;
92 
93 	return VBERROR_SUCCESS;
94 }
95 
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)96 VbError_t VbGbbReadImage(VbCommonParams *cparams,
97 			       uint32_t localization, uint32_t screen_index,
98 			       uint32_t image_num, ScreenLayout *layout,
99 			       ImageInfo *image_info, char **image_datap,
100 			       uint32_t *image_data_sizep)
101 {
102 	uint32_t layout_offset, image_offset, data_offset, data_size;
103 	GoogleBinaryBlockHeader *gbb;
104 	BmpBlockHeader hdr;
105 	void *data = NULL;
106 	VbError_t ret;
107 
108 	if (!cparams)
109 		return VBERROR_INVALID_GBB;
110 
111 	ret = VbGbbReadBmpHeader(cparams, &hdr);
112 	if (ret)
113 		return ret;
114 
115 	gbb = cparams->gbb;
116 	layout_offset = gbb->bmpfv_offset + sizeof(BmpBlockHeader) +
117 		localization * hdr.number_of_screenlayouts *
118 			sizeof(ScreenLayout) +
119 		screen_index * sizeof(ScreenLayout);
120 	ret = VbRegionReadGbb(cparams, layout_offset, sizeof(*layout), layout);
121 	if (ret)
122 		return ret;
123 
124 	if (!layout->images[image_num].image_info_offset)
125 		return VBERROR_NO_IMAGE_PRESENT;
126 
127 	image_offset = gbb->bmpfv_offset +
128 			layout->images[image_num].image_info_offset;
129 	ret = VbRegionReadGbb(cparams, image_offset, sizeof(*image_info),
130 			      image_info);
131 	if (ret)
132 		return ret;
133 
134 	data_offset = image_offset + sizeof(*image_info);
135 	data_size = image_info->compressed_size;
136 	if (data_size) {
137 		void *orig_data;
138 
139 		data = VbExMalloc(image_info->compressed_size);
140 		ret = VbRegionReadGbb(cparams, data_offset,
141 				      image_info->compressed_size, data);
142 		if (ret) {
143 			VbExFree(data);
144 			return ret;
145 		}
146 		if (image_info->compression != COMPRESS_NONE) {
147 			uint32_t inoutsize = image_info->original_size;
148 
149 			orig_data = VbExMalloc(image_info->original_size);
150 			ret = VbExDecompress(data,
151 					     image_info->compressed_size,
152 					     image_info->compression,
153 					     orig_data, &inoutsize);
154 			data_size = inoutsize;
155 			VbExFree(data);
156 			data = orig_data;
157 			if (ret) {
158 				VbExFree(data);
159 				return ret;
160 			}
161 		}
162 	}
163 
164 	*image_datap = data;
165 	*image_data_sizep = data_size;
166 
167 	return VBERROR_SUCCESS;
168 }
169 
170 #define OUTBUF_LEN 128
171 
VbRegionCheckVersion(VbCommonParams * cparams)172 void VbRegionCheckVersion(VbCommonParams *cparams)
173 {
174 	GoogleBinaryBlockHeader *gbb;
175 
176 	if (!cparams)
177 		return;
178 
179 	gbb = cparams->gbb;
180 
181 	/*
182 	 * If GBB flags is nonzero, complain because that's something that the
183 	 * factory MUST fix before shipping. We only have to do this here,
184 	 * because it's obvious that something is wrong if we're not displaying
185 	 * screens from the GBB.
186 	 */
187 	if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 &&
188 	    (gbb->flags != 0)) {
189 		uint32_t used = 0;
190 		char outbuf[OUTBUF_LEN];
191 
192 		*outbuf = '\0';
193 		used += StrnAppend(outbuf + used, "gbb.flags is nonzero: 0x",
194 				OUTBUF_LEN - used);
195 		used += Uint64ToString(outbuf + used, OUTBUF_LEN - used,
196 				       gbb->flags, 16, 8);
197 		used += StrnAppend(outbuf + used, "\n", OUTBUF_LEN - used);
198 		(void)VbExDisplayDebugInfo(outbuf);
199 	}
200 }
201