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