1*a248dafdSChristopher Ferris /*
2*a248dafdSChristopher Ferris * Copyright (C) 2012 - 2014 Andrew Duggan
3*a248dafdSChristopher Ferris * Copyright (C) 2012 - 2014 Synaptics Inc
4*a248dafdSChristopher Ferris *
5*a248dafdSChristopher Ferris * Licensed under the Apache License, Version 2.0 (the "License");
6*a248dafdSChristopher Ferris * you may not use this file except in compliance with the License.
7*a248dafdSChristopher Ferris * You may obtain a copy of the License at
8*a248dafdSChristopher Ferris *
9*a248dafdSChristopher Ferris * http://www.apache.org/licenses/LICENSE-2.0
10*a248dafdSChristopher Ferris *
11*a248dafdSChristopher Ferris * Unless required by applicable law or agreed to in writing, software
12*a248dafdSChristopher Ferris * distributed under the License is distributed on an "AS IS" BASIS,
13*a248dafdSChristopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*a248dafdSChristopher Ferris * See the License for the specific language governing permissions and
15*a248dafdSChristopher Ferris * limitations under the License.
16*a248dafdSChristopher Ferris */
17*a248dafdSChristopher Ferris
18*a248dafdSChristopher Ferris #include <iostream>
19*a248dafdSChristopher Ferris #include <fstream>
20*a248dafdSChristopher Ferris #include <string.h>
21*a248dafdSChristopher Ferris #include <stdint.h>
22*a248dafdSChristopher Ferris #include <stdlib.h>
23*a248dafdSChristopher Ferris
24*a248dafdSChristopher Ferris #include "rmidevice.h"
25*a248dafdSChristopher Ferris #include "firmware_image.h"
26*a248dafdSChristopher Ferris
27*a248dafdSChristopher Ferris using namespace std;
28*a248dafdSChristopher Ferris
Checksum(unsigned short * data,unsigned long len)29*a248dafdSChristopher Ferris unsigned long FirmwareImage::Checksum(unsigned short * data, unsigned long len)
30*a248dafdSChristopher Ferris {
31*a248dafdSChristopher Ferris unsigned long checksum = 0xFFFFFFFF;
32*a248dafdSChristopher Ferris unsigned long lsw = checksum & 0xFFFF;
33*a248dafdSChristopher Ferris unsigned long msw = checksum >> 16;
34*a248dafdSChristopher Ferris
35*a248dafdSChristopher Ferris while (len--) {
36*a248dafdSChristopher Ferris lsw += *data++;
37*a248dafdSChristopher Ferris msw += lsw;
38*a248dafdSChristopher Ferris lsw = (lsw & 0xffff) + (lsw >> 16);
39*a248dafdSChristopher Ferris msw = (msw & 0xffff) + (msw >> 16);
40*a248dafdSChristopher Ferris }
41*a248dafdSChristopher Ferris
42*a248dafdSChristopher Ferris checksum = msw << 16 | lsw;
43*a248dafdSChristopher Ferris
44*a248dafdSChristopher Ferris return checksum;
45*a248dafdSChristopher Ferris }
46*a248dafdSChristopher Ferris
ParseHierarchicalImg()47*a248dafdSChristopher Ferris void FirmwareImage::ParseHierarchicalImg()
48*a248dafdSChristopher Ferris {
49*a248dafdSChristopher Ferris struct container_descriptor *descriptor;
50*a248dafdSChristopher Ferris int numOfCntrs;
51*a248dafdSChristopher Ferris int ii;
52*a248dafdSChristopher Ferris unsigned int addr;
53*a248dafdSChristopher Ferris unsigned int offset;
54*a248dafdSChristopher Ferris unsigned int length;
55*a248dafdSChristopher Ferris unsigned char *content;
56*a248dafdSChristopher Ferris unsigned short container_id;
57*a248dafdSChristopher Ferris unsigned int sigature_size;
58*a248dafdSChristopher Ferris
59*a248dafdSChristopher Ferris for (ii = 0; ii < BLv7_MAX; ii++) {
60*a248dafdSChristopher Ferris m_signatureInfo[ii].bExisted = false;
61*a248dafdSChristopher Ferris m_signatureInfo[ii].size = 0;
62*a248dafdSChristopher Ferris }
63*a248dafdSChristopher Ferris
64*a248dafdSChristopher Ferris if (m_bootloaderVersion == RMI_IMG_V10_SIGNATURE_VERSION_NUMBER) {
65*a248dafdSChristopher Ferris fprintf (stdout, "has signature\n");
66*a248dafdSChristopher Ferris }
67*a248dafdSChristopher Ferris
68*a248dafdSChristopher Ferris m_cntrAddr = extract_long(&m_memBlock[RMI_IMG_V10_CNTR_ADDR_OFFSET]);
69*a248dafdSChristopher Ferris descriptor = (struct container_descriptor *)(m_memBlock + m_cntrAddr);
70*a248dafdSChristopher Ferris offset = extract_long(descriptor->content_address);
71*a248dafdSChristopher Ferris numOfCntrs = extract_long(descriptor->content_length) / 4;
72*a248dafdSChristopher Ferris
73*a248dafdSChristopher Ferris for (ii = 0; ii < numOfCntrs; ii++) {
74*a248dafdSChristopher Ferris addr = extract_long(m_memBlock + offset);
75*a248dafdSChristopher Ferris offset += 4;
76*a248dafdSChristopher Ferris descriptor = (struct container_descriptor *)(m_memBlock + addr);
77*a248dafdSChristopher Ferris container_id = descriptor->container_id[0] |
78*a248dafdSChristopher Ferris descriptor->container_id[1] << 8;
79*a248dafdSChristopher Ferris content = m_memBlock + extract_long(descriptor->content_address);
80*a248dafdSChristopher Ferris length = extract_long(descriptor->content_length);
81*a248dafdSChristopher Ferris sigature_size = extract_long(descriptor->signature_size);
82*a248dafdSChristopher Ferris switch (container_id) {
83*a248dafdSChristopher Ferris case BL_CONTAINER:
84*a248dafdSChristopher Ferris m_bootloaderVersion = *content;
85*a248dafdSChristopher Ferris break;
86*a248dafdSChristopher Ferris case UI_CONTAINER:
87*a248dafdSChristopher Ferris case CORE_CODE_CONTAINER:
88*a248dafdSChristopher Ferris if (sigature_size != 0) {
89*a248dafdSChristopher Ferris fprintf(stdout, "CORE CODE signature size : 0x%x\n", sigature_size);
90*a248dafdSChristopher Ferris m_signatureInfo[BLv7_CORE_CODE].bExisted = true;
91*a248dafdSChristopher Ferris m_signatureInfo[BLv7_CORE_CODE].size = sigature_size;
92*a248dafdSChristopher Ferris }
93*a248dafdSChristopher Ferris m_firmwareData = content;
94*a248dafdSChristopher Ferris m_firmwareSize = length;
95*a248dafdSChristopher Ferris break;
96*a248dafdSChristopher Ferris case FLASH_CONFIG_CONTAINER:
97*a248dafdSChristopher Ferris if (sigature_size != 0) {
98*a248dafdSChristopher Ferris fprintf(stdout, "FLASH CONFIG signature size : 0x%x\n", sigature_size);
99*a248dafdSChristopher Ferris m_signatureInfo[BLv7_FLASH_CONFIG].bExisted = true;
100*a248dafdSChristopher Ferris m_signatureInfo[BLv7_FLASH_CONFIG].size = sigature_size;
101*a248dafdSChristopher Ferris }
102*a248dafdSChristopher Ferris m_flashConfigData = content;
103*a248dafdSChristopher Ferris m_flashConfigSize = length;
104*a248dafdSChristopher Ferris break;
105*a248dafdSChristopher Ferris case UI_CONFIG_CONTAINER:
106*a248dafdSChristopher Ferris case CORE_CONFIG_CONTAINER:
107*a248dafdSChristopher Ferris if (sigature_size != 0) {
108*a248dafdSChristopher Ferris fprintf(stdout, "CORE CONFIG signature size : 0x%x\n", sigature_size);
109*a248dafdSChristopher Ferris m_signatureInfo[BLv7_CORE_CONFIG].bExisted = true;
110*a248dafdSChristopher Ferris m_signatureInfo[BLv7_CORE_CONFIG].size = sigature_size;
111*a248dafdSChristopher Ferris }
112*a248dafdSChristopher Ferris m_configData = content;
113*a248dafdSChristopher Ferris m_configSize = length;
114*a248dafdSChristopher Ferris break;
115*a248dafdSChristopher Ferris case PERMANENT_CONFIG_CONTAINER:
116*a248dafdSChristopher Ferris case GUEST_SERIALIZATION_CONTAINER:
117*a248dafdSChristopher Ferris m_lockdownData = content;
118*a248dafdSChristopher Ferris m_lockdownSize = length;
119*a248dafdSChristopher Ferris break;
120*a248dafdSChristopher Ferris case GENERAL_INFORMATION_CONTAINER:
121*a248dafdSChristopher Ferris m_io = true;
122*a248dafdSChristopher Ferris m_packageID = extract_long(content);
123*a248dafdSChristopher Ferris m_firmwareBuildID = extract_long(content + 4);
124*a248dafdSChristopher Ferris memcpy(m_productID, (content + 0x18), RMI_PRODUCT_ID_LENGTH);
125*a248dafdSChristopher Ferris m_productID[RMI_PRODUCT_ID_LENGTH] = 0;
126*a248dafdSChristopher Ferris if ((descriptor->major_version == 0) &&
127*a248dafdSChristopher Ferris (descriptor->minor_version > 0)) {
128*a248dafdSChristopher Ferris m_hasFirmwareVersion = true;
129*a248dafdSChristopher Ferris fprintf(stdout, "General Information version : %d.%d\n", descriptor->major_version, descriptor->minor_version);
130*a248dafdSChristopher Ferris m_firmwareVersion = *(content + 0x26) << 8 | *(content + 0x27);
131*a248dafdSChristopher Ferris fprintf(stdout, "Firmware version : 0x%x\n", m_firmwareVersion);
132*a248dafdSChristopher Ferris }
133*a248dafdSChristopher Ferris break;
134*a248dafdSChristopher Ferris case FIXED_LOCATION_DATA_CONTAINER:
135*a248dafdSChristopher Ferris if (sigature_size != 0) {
136*a248dafdSChristopher Ferris fprintf(stdout, "FLD signature size : 0x%x\n", sigature_size);
137*a248dafdSChristopher Ferris m_signatureInfo[BLv7_FLD].bExisted = true;
138*a248dafdSChristopher Ferris m_signatureInfo[BLv7_FLD].size = sigature_size;
139*a248dafdSChristopher Ferris }
140*a248dafdSChristopher Ferris m_fldData = content;
141*a248dafdSChristopher Ferris m_fldSize = length;
142*a248dafdSChristopher Ferris break;
143*a248dafdSChristopher Ferris case GLOBAL_PARAMETERS_CONTAINER:
144*a248dafdSChristopher Ferris m_globalparaData = content;
145*a248dafdSChristopher Ferris m_globalparaSize = length;
146*a248dafdSChristopher Ferris break;
147*a248dafdSChristopher Ferris default:
148*a248dafdSChristopher Ferris break;
149*a248dafdSChristopher Ferris }
150*a248dafdSChristopher Ferris }
151*a248dafdSChristopher Ferris }
152*a248dafdSChristopher Ferris
Initialize(const char * filename)153*a248dafdSChristopher Ferris int FirmwareImage::Initialize(const char * filename)
154*a248dafdSChristopher Ferris {
155*a248dafdSChristopher Ferris if (!filename)
156*a248dafdSChristopher Ferris return UPDATE_FAIL_INVALID_PARAMETER;
157*a248dafdSChristopher Ferris
158*a248dafdSChristopher Ferris ifstream ifsFile(filename, ios::in|ios::binary|ios::ate);
159*a248dafdSChristopher Ferris if (!ifsFile)
160*a248dafdSChristopher Ferris return UPDATE_FAIL_OPEN_FIRMWARE_IMAGE;
161*a248dafdSChristopher Ferris
162*a248dafdSChristopher Ferris ifsFile.seekg(0, ios::end);
163*a248dafdSChristopher Ferris m_imageSize = ifsFile.tellg();
164*a248dafdSChristopher Ferris if (m_imageSize < 0)
165*a248dafdSChristopher Ferris return UPDATE_FAIL_OPEN_FIRMWARE_IMAGE;
166*a248dafdSChristopher Ferris
167*a248dafdSChristopher Ferris m_memBlock = new unsigned char[m_imageSize];
168*a248dafdSChristopher Ferris ifsFile.seekg(0, ios::beg);
169*a248dafdSChristopher Ferris ifsFile.read((char*)m_memBlock, m_imageSize);
170*a248dafdSChristopher Ferris
171*a248dafdSChristopher Ferris if (m_imageSize < 0x100)
172*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_IMAGE;
173*a248dafdSChristopher Ferris
174*a248dafdSChristopher Ferris m_checksum = extract_long(&m_memBlock[RMI_IMG_CHECKSUM_OFFSET]);
175*a248dafdSChristopher Ferris
176*a248dafdSChristopher Ferris unsigned long imageSizeMinusChecksum = m_imageSize - 4;
177*a248dafdSChristopher Ferris if ((imageSizeMinusChecksum % 2) != 0)
178*a248dafdSChristopher Ferris /*
179*a248dafdSChristopher Ferris * Since the header size is fixed and the firmware is
180*a248dafdSChristopher Ferris * in 16 byte blocks a valid image size should always be
181*a248dafdSChristopher Ferris * divisible by 2.
182*a248dafdSChristopher Ferris */
183*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_IMAGE;
184*a248dafdSChristopher Ferris
185*a248dafdSChristopher Ferris unsigned long calculated_checksum = Checksum((uint16_t *)&(m_memBlock[4]),
186*a248dafdSChristopher Ferris imageSizeMinusChecksum >> 1);
187*a248dafdSChristopher Ferris
188*a248dafdSChristopher Ferris if (m_checksum != calculated_checksum) {
189*a248dafdSChristopher Ferris fprintf(stderr, "Firmware image checksum verification failed, saw 0x%08lX, calculated 0x%08lX\n",
190*a248dafdSChristopher Ferris m_checksum, calculated_checksum);
191*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_CHECKSUM;
192*a248dafdSChristopher Ferris }
193*a248dafdSChristopher Ferris
194*a248dafdSChristopher Ferris m_io = m_memBlock[RMI_IMG_IO_OFFSET];
195*a248dafdSChristopher Ferris m_bootloaderVersion = m_memBlock[RMI_IMG_BOOTLOADER_VERSION_OFFSET];
196*a248dafdSChristopher Ferris m_firmwareSize = extract_long(&m_memBlock[RMI_IMG_IMAGE_SIZE_OFFSET]);
197*a248dafdSChristopher Ferris
198*a248dafdSChristopher Ferris if ((unsigned long)m_imageSize - RMI_IMG_FW_OFFSET - 1 < m_firmwareSize) {
199*a248dafdSChristopher Ferris fprintf(stderr, "Supplied firmware image size too large, goes out of image file size bound\n");
200*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_FIRMWARE_SIZE;
201*a248dafdSChristopher Ferris }
202*a248dafdSChristopher Ferris
203*a248dafdSChristopher Ferris m_configSize = extract_long(&m_memBlock[RMI_IMG_CONFIG_SIZE_OFFSET]);
204*a248dafdSChristopher Ferris if (m_io == 1) {
205*a248dafdSChristopher Ferris m_firmwareBuildID = extract_long(&m_memBlock[RMI_IMG_FW_BUILD_ID_OFFSET]);
206*a248dafdSChristopher Ferris m_packageID = extract_long(&m_memBlock[RMI_IMG_PACKAGE_ID_OFFSET]);
207*a248dafdSChristopher Ferris }
208*a248dafdSChristopher Ferris memcpy(m_productID, &m_memBlock[RMI_IMG_PRODUCT_ID_OFFSET], RMI_PRODUCT_ID_LENGTH);
209*a248dafdSChristopher Ferris m_productID[RMI_PRODUCT_ID_LENGTH] = 0;
210*a248dafdSChristopher Ferris m_productInfo = extract_short(&m_memBlock[RMI_IMG_PRODUCT_INFO_OFFSET]);
211*a248dafdSChristopher Ferris
212*a248dafdSChristopher Ferris m_firmwareData = &m_memBlock[RMI_IMG_FW_OFFSET];
213*a248dafdSChristopher Ferris m_configData = &m_memBlock[RMI_IMG_FW_OFFSET + m_firmwareSize];
214*a248dafdSChristopher Ferris
215*a248dafdSChristopher Ferris switch (m_bootloaderVersion) {
216*a248dafdSChristopher Ferris case 2:
217*a248dafdSChristopher Ferris m_lockdownSize = RMI_IMG_LOCKDOWN_V2_SIZE;
218*a248dafdSChristopher Ferris m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V2_OFFSET];
219*a248dafdSChristopher Ferris break;
220*a248dafdSChristopher Ferris case 3:
221*a248dafdSChristopher Ferris case 4:
222*a248dafdSChristopher Ferris m_lockdownSize = RMI_IMG_LOCKDOWN_V3_SIZE;
223*a248dafdSChristopher Ferris m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V3_OFFSET];
224*a248dafdSChristopher Ferris break;
225*a248dafdSChristopher Ferris case 5:
226*a248dafdSChristopher Ferris case 6:
227*a248dafdSChristopher Ferris m_lockdownSize = RMI_IMG_LOCKDOWN_V5_SIZE;
228*a248dafdSChristopher Ferris m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V5_OFFSET];
229*a248dafdSChristopher Ferris break;
230*a248dafdSChristopher Ferris case 16:
231*a248dafdSChristopher Ferris case RMI_IMG_V10_SIGNATURE_VERSION_NUMBER:
232*a248dafdSChristopher Ferris ParseHierarchicalImg();
233*a248dafdSChristopher Ferris break;
234*a248dafdSChristopher Ferris default:
235*a248dafdSChristopher Ferris return UPDATE_FAIL_UNSUPPORTED_IMAGE_VERSION;
236*a248dafdSChristopher Ferris }
237*a248dafdSChristopher Ferris
238*a248dafdSChristopher Ferris fprintf(stdout, "Firmware Header:\n");
239*a248dafdSChristopher Ferris PrintHeaderInfo();
240*a248dafdSChristopher Ferris
241*a248dafdSChristopher Ferris return UPDATE_SUCCESS;
242*a248dafdSChristopher Ferris }
243*a248dafdSChristopher Ferris
PrintHeaderInfo()244*a248dafdSChristopher Ferris void FirmwareImage::PrintHeaderInfo()
245*a248dafdSChristopher Ferris {
246*a248dafdSChristopher Ferris fprintf(stdout, "Checksum:\t\t0x%lx\n", m_checksum);
247*a248dafdSChristopher Ferris fprintf(stdout, "Firmware Size:\t\t%ld\n", m_firmwareSize);
248*a248dafdSChristopher Ferris fprintf(stdout, "Config Size:\t\t%ld\n", m_configSize);
249*a248dafdSChristopher Ferris fprintf(stdout, "Lockdown Size:\t\t%ld\n", m_lockdownSize);
250*a248dafdSChristopher Ferris fprintf(stdout, "Firmware Build ID:\t%ld\n", m_firmwareBuildID);
251*a248dafdSChristopher Ferris fprintf(stdout, "Package ID:\t\t%d\n", m_packageID);
252*a248dafdSChristopher Ferris fprintf(stdout, "Bootloader Version:\t%d\n", m_bootloaderVersion);
253*a248dafdSChristopher Ferris fprintf(stdout, "Product ID:\t\t%s\n", m_productID);
254*a248dafdSChristopher Ferris fprintf(stdout, "Product Info:\t\t%d\n", m_productInfo);
255*a248dafdSChristopher Ferris fprintf(stdout, "\n");
256*a248dafdSChristopher Ferris }
257*a248dafdSChristopher Ferris
VerifyImageMatchesDevice(unsigned long deviceFirmwareSize,unsigned long deviceConfigSize)258*a248dafdSChristopher Ferris int FirmwareImage::VerifyImageMatchesDevice(unsigned long deviceFirmwareSize,
259*a248dafdSChristopher Ferris unsigned long deviceConfigSize)
260*a248dafdSChristopher Ferris {
261*a248dafdSChristopher Ferris if (m_firmwareSize != deviceFirmwareSize) {
262*a248dafdSChristopher Ferris fprintf(stderr, "Firmware image size verfication failed, size in image %ld did "
263*a248dafdSChristopher Ferris "not match device size %ld\n", m_firmwareSize, deviceFirmwareSize);
264*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_FIRMWARE_SIZE;
265*a248dafdSChristopher Ferris }
266*a248dafdSChristopher Ferris
267*a248dafdSChristopher Ferris if (m_configSize != deviceConfigSize) {
268*a248dafdSChristopher Ferris fprintf(stderr, "Firmware image size verfication failed, size in image %ld did "
269*a248dafdSChristopher Ferris "not match device size %ld\n", m_firmwareSize, deviceConfigSize);
270*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_CONFIG_SIZE;
271*a248dafdSChristopher Ferris }
272*a248dafdSChristopher Ferris
273*a248dafdSChristopher Ferris return UPDATE_SUCCESS;
274*a248dafdSChristopher Ferris }
275*a248dafdSChristopher Ferris
VerifyImageProductID(char * deviceProductID)276*a248dafdSChristopher Ferris int FirmwareImage::VerifyImageProductID(char* deviceProductID)
277*a248dafdSChristopher Ferris {
278*a248dafdSChristopher Ferris if (strcmp(m_productID, deviceProductID) == 0) {
279*a248dafdSChristopher Ferris fprintf(stdout, "image matched\n");
280*a248dafdSChristopher Ferris return UPDATE_SUCCESS;
281*a248dafdSChristopher Ferris } else {
282*a248dafdSChristopher Ferris fprintf (stdout, "image not match, terminated\n");
283*a248dafdSChristopher Ferris return UPDATE_FAIL_VERIFY_IMAGE_PRODUCTID_NOT_MATCH;
284*a248dafdSChristopher Ferris }
285*a248dafdSChristopher Ferris }
286*a248dafdSChristopher Ferris
~FirmwareImage()287*a248dafdSChristopher Ferris FirmwareImage::~FirmwareImage()
288*a248dafdSChristopher Ferris {
289*a248dafdSChristopher Ferris delete [] m_memBlock;
290*a248dafdSChristopher Ferris m_memBlock = NULL;
291*a248dafdSChristopher Ferris }
292