Files
0xFFFF/src/cold-flash.c
T

388 lines
8.5 KiB
C
Raw Normal View History

/*
cold-flash.c - Cold flashing
Copyright (C) 2011-2012 Pali Rohár <pali.rohar@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <usb.h>
#define READ_DEV 0x81
#define WRITE_DEV 0x01
#define READ_TIMEOUT 500
#define WRITE_TIMEOUT 3000
static uint32_t tab[256];
static void crc32_gentab(void) {
int i, j;
uint32_t crc;
uint32_t poly = 0xEDB88320L;
for ( i = 0; i < 256; i++) {
crc = i;
for ( j = 8; j > 0; j-- ) {
if (crc & 1)
crc = (crc >> 1) ^ poly;
else
crc >>= 1;
}
tab[i] = crc;
}
}
static uint32_t crc32(unsigned char * bytes, size_t size, uint32_t crc) {
static int gen = 0;
uint32_t i;
if ( ! gen ) {
crc32_gentab();
gen = 1;
}
for ( i = 0; i < size; ++i )
crc = (crc >> 8) ^ tab[(crc ^ bytes[i]) & 0xff];
return crc;
}
/* Omap download message */
static const uint8_t omap_download_msg[4] = { 0x02, 0x00, 0x03, 0xF0 };
/* Structure of X-Loader message */
struct xloader_msg {
uint8_t type[4]; /* 4 bytes - type of message */
uint8_t size[4]; /* 4 bytes - size of file */
uint8_t crc1[4]; /* 4 bytes - crc32 of file */
uint8_t crc2[4]; /* 4 bytes - crc32 of first 12 bytes of message */
};
#define XLOADER_MSG_TYPE_PING 0x6301326E
#define XLOADER_MSG_TYPE_SEND 0x6302326E
struct xloader_msg xloader_msg_create(uint32_t type, FILE * file, size_t offset, uint32_t size) {
struct xloader_msg msg;
uint8_t buffer[1024];
size_t need, readed;
uint32_t crc = 0;
int ret;
memcpy(msg.type, &type, 4);
memcpy(msg.size, &size, 4);
if ( file ) {
fseek(file, offset, SEEK_SET);
readed = 0;
while ( readed < size ) {
need = size - readed;
if ( need > sizeof(buffer) )
need = sizeof(buffer);
ret = fread(buffer, 1, need, file);
if ( ret < 0 )
break;
crc = crc32(buffer, ret, crc);
readed += ret;
}
}
memcpy(msg.crc1, &crc, 4);
crc = crc32((unsigned char *)&msg, 12, 0);
memcpy(msg.crc2, &crc, 4);
return msg;
}
static int read_asic(usb_dev_handle * udev) {
uint8_t asic_buffer[127];
int asic_size = 69;
int i, ret;
printf("Waiting for ASIC ID...\n");
ret = usb_bulk_read(udev, READ_DEV, (char *)asic_buffer, sizeof(asic_buffer), READ_TIMEOUT);
if ( ret != asic_size ) {
fprintf(stderr, "Invalid size of ASIC ID\n");
return 0;
}
printf("Got ASIC ID:");
for ( i = 0; i < asic_size; ++i )
printf(" 0x%.2X", (unsigned int)asic_buffer[i]);
printf("\n");
return 1;
}
static int send_2nd(usb_dev_handle * udev, FILE * file, size_t offset, size_t size) {
uint8_t buffer[1024];
uint32_t size32;
size_t need, readed;
int ret;
size32 = size;
fseek(file, offset, SEEK_SET);
if ( size == 0 ) {
fprintf(stderr, "2nd X-Loader image has zero size\n");
return 0;
}
if ( size > UINT32_MAX ) {
fprintf(stderr, "2nd X-Loader image is too big\n");
return 0;
}
printf("Sending OMAP download message...\n");
ret = usb_bulk_write(udev, WRITE_DEV, (char *)omap_download_msg, sizeof(omap_download_msg), WRITE_TIMEOUT);
usleep(5000);
if ( ret != sizeof(omap_download_msg) ) {
fprintf(stderr, "Error while sending OMAP download message\n");
return 0;
}
printf("Sending 2nd X-Loader image size...\n");
ret = usb_bulk_write(udev, WRITE_DEV, (char *)&size32, sizeof(size32), WRITE_TIMEOUT);
usleep(5000);
if ( ret != sizeof(size32) ) {
fprintf(stderr, "Error while sending 2nd X-Loader image size\n");
return 0;
}
printf("Sending 2nd X-Loader image...\n");
readed = 0;
while ( readed < size ) {
need = size - readed;
if ( need > sizeof(buffer) )
need = sizeof(buffer);
ret = fread(buffer, 1, need, file);
if ( ret < 0 )
break;
if ( usb_bulk_write(udev, WRITE_DEV, (char *)buffer, ret, WRITE_TIMEOUT) != ret ) {
fprintf(stderr, "Error while sending 2nd X-Loader image\n");
return 0;
}
readed += ret;
}
usleep(50000);
return 1;
}
static int send_secondary(usb_dev_handle * udev, FILE * file, size_t offset, size_t size) {
struct xloader_msg init_msg;
uint8_t buffer[1024];
uint32_t size32;
size_t need, readed;
int ret;
size32 = size;
fseek(file, offset, SEEK_SET);
if ( size == 0 ) {
fprintf(stderr, "2nd Secondary image has zero size\n");
return 0;
}
if ( size > UINT32_MAX ) {
fprintf(stderr, "2nd Secondary image is too big\n");
return 0;
}
init_msg = xloader_msg_create(XLOADER_MSG_TYPE_SEND, file, offset, size32);
printf("Sending X-Loader init message...\n");
ret = usb_bulk_write(udev, WRITE_DEV, (char *)&init_msg, sizeof(init_msg), WRITE_TIMEOUT);
usleep(5000);
if ( ret != sizeof(init_msg) ) {
fprintf(stderr, "Error while sending X-Loader init message\n");
return 0;
}
printf("Waiting for X-Loader response...\n");
ret = usb_bulk_read(udev, READ_DEV, (char *)&size32, sizeof(size32), READ_TIMEOUT); /* size32 - dummy value */
if ( ret != sizeof(size32) ) {
fprintf(stderr, "Error no response\n");
return 0;
}
printf("Sending Secondary image...\n");
readed = 0;
while ( readed < size ) {
need = size - readed;
if ( need > sizeof(buffer) )
need = sizeof(buffer);
ret = fread(buffer, 1, need, file);
if ( ret < 0 )
break;
if ( usb_bulk_write(udev, WRITE_DEV, (char *)buffer, ret, WRITE_TIMEOUT) != ret ) {
fprintf(stderr, "Error while sending Secondary image\n");
return 0;
}
readed += ret;
}
usleep(5000);
printf("Waiting for X-Loader response...\n");
ret = usb_bulk_read(udev, READ_DEV, (char *)&size32, sizeof(size32), READ_TIMEOUT); /* size32 - dummy value */
if ( ret != sizeof(size32) ) {
fprintf(stderr, "Error no response\n");
return 0;
}
return 1;
}
static int ping_timeout(usb_dev_handle * udev) {
int ret;
int pong = 0;
int try_ping = 10;
while ( try_ping > 0 ) {
struct xloader_msg ping_msg = xloader_msg_create(XLOADER_MSG_TYPE_PING, NULL, 0, 0);
int try_read = 4;
printf("Sending X-Loader ping message\n");
ret = usb_bulk_write(udev, WRITE_DEV, (char *)&ping_msg, sizeof(ping_msg), WRITE_TIMEOUT);
if ( ret != sizeof(ping_msg) ) {
fprintf(stderr, "Error while sending X-Loader ping message\n");
return 0;
}
printf("Waiting for X-Loader pong response...\n");
while ( try_read > 0 ) {
uint32_t ping_read;
ret = usb_bulk_read(udev, READ_DEV, (char *)&ping_read, sizeof(ping_read), READ_TIMEOUT);
if ( ret == sizeof(ping_read) ) {
printf("Got it\n");
pong = 1;
break;
}
usleep(5000);
--try_read;
}
if ( pong )
break;
printf("Responce timeout\n");
--try_ping;
}
if (pong)
return 1;
else
return 0;
}
int cold_flash(usb_dev_handle * udev, const char * x2nd, const char * secondary) {
size_t size1, size2;
FILE * file1 = NULL;
FILE * file2 = NULL;
int ret = 1;
file1 = fopen(x2nd, "r");
if ( ! file1 ) {
fprintf(stderr, "Cannot open 2nd X-Loader file '%s': %s\n", x2nd, strerror(errno));
goto cleanup;
}
file2 = fopen(secondary, "r");
if ( ! file2 ) {
fprintf(stderr, "Cannot open Secondary file '%s': %s\n", secondary, strerror(errno));
goto cleanup;
}
fseek(file1, 0, SEEK_END);
size1 = ftell(file1);
fseek(file2, 0, SEEK_END);
size2 = ftell(file2);
if ( usb_set_configuration(udev, 1) < 0 ) {
fprintf(stderr, "usb_set_configuration failed: %s\n", strerror(errno));
goto cleanup;
}
if ( usb_claim_interface(udev, 1) < 0 ) {
fprintf(stderr, "usb_claim_interface failed: %s\n", strerror(errno));
goto cleanup;
}
if ( ! read_asic(udev) ) {
fprintf(stderr, "Reading ASIC ID failed\n");
goto cleanup;
}
if ( ! send_2nd(udev, file1, size1, 0) ) {
fprintf(stderr, "Sending 2nd X-Loader image failed\n");
goto cleanup;
}
if ( ! ping_timeout(udev) ) {
fprintf(stderr, "Sending X-Loader ping failed\n");
goto cleanup;
}
if ( ! send_secondary(udev, file2, size2, 0) ) {
fprintf(stderr, "Sending Secondary image failed\n");
goto cleanup;
}
printf("Done\n");
ret = 0;
cleanup:
if (file1)
fclose(file1);
if (file2)
fclose(file2);
return ret;
}
/*int fiasco_cold_flash(usb_dev_handle * udev, const char * device, const char * hw_rev, const char * fiasco) {
}*/