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