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 "firmware_image.h" 25 26 using namespace std; 27 28 unsigned long FirmwareImage::Checksum(unsigned short * data, unsigned long len) 29 { 30 unsigned long checksum = 0xFFFFFFFF; 31 unsigned long lsw = checksum & 0xFFFF; 32 unsigned long msw = checksum >> 16; 33 34 while (len--) { 35 lsw += *data++; 36 msw += lsw; 37 lsw = (lsw & 0xffff) + (lsw >> 16); 38 msw = (msw & 0xffff) + (msw >> 16); 39 } 40 41 checksum = msw << 16 | lsw; 42 43 return checksum; 44 } 45 46 int FirmwareImage::Initialize(const char * filename) 47 { 48 if (!filename) 49 return UPDATE_FAIL_INVALID_PARAMETER; 50 51 ifstream ifsFile(filename, ios::in|ios::binary|ios::ate); 52 if (!ifsFile) 53 return UPDATE_FAIL_OPEN_FIRMWARE_IMAGE; 54 55 ifsFile.seekg(0, ios::end); 56 m_imageSize = ifsFile.tellg(); 57 if (m_imageSize < 0) 58 return UPDATE_FAIL_OPEN_FIRMWARE_IMAGE; 59 60 m_memBlock = new unsigned char[m_imageSize]; 61 ifsFile.seekg(0, ios::beg); 62 ifsFile.read((char*)m_memBlock, m_imageSize); 63 64 if (m_imageSize < 0x100) 65 return UPDATE_FAIL_VERIFY_IMAGE; 66 67 m_checksum = extract_long(&m_memBlock[RMI_IMG_CHECKSUM_OFFSET]); 68 69 unsigned long imageSizeMinusChecksum = m_imageSize - 4; 70 if ((imageSizeMinusChecksum % 2) != 0) 71 /* 72 * Since the header size is fixed and the firmware is 73 * in 16 byte blocks a valid image size should always be 74 * divisible by 2. 75 */ 76 return UPDATE_FAIL_VERIFY_IMAGE; 77 78 unsigned long calculated_checksum = Checksum((uint16_t *)&(m_memBlock[4]), 79 imageSizeMinusChecksum >> 1); 80 81 if (m_checksum != calculated_checksum) { 82 fprintf(stderr, "Firmware image checksum verification failed, saw 0x%08lX, calculated 0x%08lX\n", 83 m_checksum, calculated_checksum); 84 return UPDATE_FAIL_VERIFY_CHECKSUM; 85 } 86 87 m_io = m_memBlock[RMI_IMG_IO_OFFSET]; 88 m_bootloaderVersion = m_memBlock[RMI_IMG_BOOTLOADER_VERSION_OFFSET]; 89 m_firmwareSize = extract_long(&m_memBlock[RMI_IMG_IMAGE_SIZE_OFFSET]); 90 91 if ((unsigned long)m_imageSize - RMI_IMG_FW_OFFSET - 1 < m_firmwareSize) { 92 fprintf(stderr, "Supplied firmware image size too large, goes out of image file size bound\n"); 93 return UPDATE_FAIL_VERIFY_FIRMWARE_SIZE; 94 } 95 96 m_configSize = extract_long(&m_memBlock[RMI_IMG_CONFIG_SIZE_OFFSET]); 97 if (m_io == 1) { 98 m_firmwareBuildID = extract_long(&m_memBlock[RMI_IMG_FW_BUILD_ID_OFFSET]); 99 m_packageID = extract_long(&m_memBlock[RMI_IMG_PACKAGE_ID_OFFSET]); 100 } 101 memcpy(m_productID, &m_memBlock[RMI_IMG_PRODUCT_ID_OFFSET], RMI_PRODUCT_ID_LENGTH); 102 m_productID[RMI_PRODUCT_ID_LENGTH] = 0; 103 m_productInfo = extract_short(&m_memBlock[RMI_IMG_PRODUCT_INFO_OFFSET]); 104 105 m_firmwareData = &m_memBlock[RMI_IMG_FW_OFFSET]; 106 m_configData = &m_memBlock[RMI_IMG_FW_OFFSET + m_firmwareSize]; 107 108 switch (m_bootloaderVersion) { 109 case 2: 110 m_lockdownSize = RMI_IMG_LOCKDOWN_V2_SIZE; 111 m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V2_OFFSET]; 112 break; 113 case 3: 114 case 4: 115 m_lockdownSize = RMI_IMG_LOCKDOWN_V3_SIZE; 116 m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V3_OFFSET]; 117 break; 118 case 5: 119 case 6: 120 m_lockdownSize = RMI_IMG_LOCKDOWN_V5_SIZE; 121 m_lockdownData = &m_memBlock[RMI_IMG_LOCKDOWN_V5_OFFSET]; 122 break; 123 default: 124 return UPDATE_FAIL_UNSUPPORTED_IMAGE_VERSION; 125 } 126 127 fprintf(stdout, "Firmware Header:\n"); 128 PrintHeaderInfo(); 129 130 return UPDATE_SUCCESS; 131 } 132 133 void FirmwareImage::PrintHeaderInfo() 134 { 135 fprintf(stdout, "Checksum:\t\t0x%lx\n", m_checksum); 136 fprintf(stdout, "Firmware Size:\t\t%ld\n", m_firmwareSize); 137 fprintf(stdout, "Config Size:\t\t%ld\n", m_configSize); 138 fprintf(stdout, "Lockdown Size:\t\t%ld\n", m_lockdownSize); 139 fprintf(stdout, "Firmware Build ID:\t%ld\n", m_firmwareBuildID); 140 fprintf(stdout, "Package ID:\t\t%d\n", m_packageID); 141 fprintf(stdout, "Bootloader Version:\t%d\n", m_bootloaderVersion); 142 fprintf(stdout, "Product ID:\t\t%s\n", m_productID); 143 fprintf(stdout, "Product Info:\t\t%d\n", m_productInfo); 144 fprintf(stdout, "\n"); 145 } 146 147 int FirmwareImage::VerifyImageMatchesDevice(unsigned long deviceFirmwareSize, 148 unsigned long deviceConfigSize) 149 { 150 if (m_firmwareSize != deviceFirmwareSize) { 151 fprintf(stderr, "Firmware image size verfication failed, size in image %ld did " 152 "not match device size %ld\n", m_firmwareSize, deviceFirmwareSize); 153 return UPDATE_FAIL_VERIFY_FIRMWARE_SIZE; 154 } 155 156 if (m_configSize != deviceConfigSize) { 157 fprintf(stderr, "Firmware image size verfication failed, size in image %ld did " 158 "not match device size %ld\n", m_firmwareSize, deviceConfigSize); 159 return UPDATE_FAIL_VERIFY_CONFIG_SIZE; 160 } 161 162 return UPDATE_SUCCESS; 163 } 164 165 FirmwareImage::~FirmwareImage() 166 { 167 delete [] m_memBlock; 168 m_memBlock = NULL; 169 } 170