/* cold-flash.c - Cold flashing Copyright (C) 2011-2012 Pali Rohár 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 . */ #include #include #include #include #include #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) { }*/