Home | History | Annotate | Download | only in lib
      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 
     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 
     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 
     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 
     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 
    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