123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- #include <arm/NXP/LPC17xx/LPC17xx.h>
- #include <string.h>
- #include "bits.h"
- #include "iap.h"
- #include "config.h"
- #include "uart.h"
- #include "fileops.h"
- #include "crc32.h"
- #include "led.h"
- uint32_t iap_cmd[5];
- uint32_t iap_res[5];
- uint32_t flash_sig[4];
- IAP iap_entry = ( IAP ) IAP_LOCATION;
- uint32_t calc_flash_crc( uint32_t start, uint32_t len )
- {
- DBG_BL printf( "calc_flash_crc(%08lx, %08lx) {\n", start, len );
- uint32_t end = start + len;
- if ( end > 0x20000 )
- {
- len = 0x1ffff - start;
- end = 0x20000;
- }
- uint32_t crc = 0xffffffff;
- uint32_t s = start;
- while ( s < end )
- {
- crc = crc32_update( crc, *( const unsigned char * )( s ) );
- s++;
- }
- crc = crc_finalize( crc );
- DBG_BL printf( " crc generated. result=%08lx\n", crc );
- DBG_BL printf( "} //calc_flash_crc\n" );
- return crc;
- }
- void test_iap()
- {
- iap_cmd[0] = 54;
- iap_entry( iap_cmd, iap_res );
- DBG_BL printf( "Part ID=%08lx\n", iap_res[1] );
- }
- void print_header( sd2snes_fw_header *header )
- {
- DBG_BL printf( " magic = %08lx\n version = %08lx\n size = %08lx\n crc = %08lx\n ~crc = %08lx\n",
- header->magic, header->version, header->size,
- header->crc, header->crcc );
- }
- int check_header( sd2snes_fw_header *header, uint32_t crc )
- {
- if ( ( header->magic != FW_MAGIC )
- || ( header->size < 0x200 )
- || ( header->size > ( 0x1ffff - FW_START ) )
- || ( ( header->crc ^ header->crcc ) != 0xffffffff ) )
- {
- return ERR_FLASHHD;
- }
- if ( header->crc != crc )
- {
- return ERR_FLASHCRC;
- }
- return ERR_OK;
- }
- FLASH_RES check_flash()
- {
- sd2snes_fw_header *fw_header = ( sd2snes_fw_header * ) FW_START;
- uint32_t flash_addr = FW_START;
- if ( flash_addr != FW_START )
- {
- DBG_BL printf( "address sanity check failed. expected 0x%08lx, got 0x%08lx.\nSomething is terribly wrong.\nBailing out to avoid bootldr self-corruption.\n",
- FW_START, flash_addr );
- return ERR_HW;
- }
- DBG_BL printf( "Current flash contents:\n" );
- DBG_BL print_header( fw_header );
- uint32_t crc = calc_flash_crc( flash_addr + 0x100, ( fw_header->size & 0x1ffff ) );
- return check_header( fw_header, crc );
- }
- IAP_RES iap_wrap( uint32_t *iap_cmd, uint32_t *iap_res )
- {
- // NVIC_DisableIRQ(RIT_IRQn);
- // NVIC_DisableIRQ(UART_IRQ);
- for ( volatile int i = 0; i < 2048; i++ );
- iap_entry( iap_cmd, iap_res );
- for ( volatile int i = 0; i < 2048; i++ );
- // NVIC_EnableIRQ(UART_IRQ);
- return iap_res[0];
- }
- IAP_RES iap_prepare_for_write( uint32_t start, uint32_t end )
- {
- if ( start < ( FW_START / 0x1000 ) )
- {
- return INVALID_SECTOR;
- }
- iap_cmd[0] = 50;
- iap_cmd[1] = start;
- iap_cmd[2] = end;
- iap_wrap( iap_cmd, iap_res );
- return iap_res[0];
- }
- IAP_RES iap_erase( uint32_t start, uint32_t end )
- {
- if ( start < ( FW_START / 0x1000 ) )
- {
- return INVALID_SECTOR;
- }
- iap_cmd[0] = 52;
- iap_cmd[1] = start;
- iap_cmd[2] = end;
- iap_cmd[3] = CONFIG_CPU_FREQUENCY / 1000L;
- iap_wrap( iap_cmd, iap_res );
- return iap_res[0];
- }
- IAP_RES iap_ram2flash( uint32_t tgt, uint8_t *src, int num )
- {
- iap_cmd[0] = 51;
- iap_cmd[1] = tgt;
- iap_cmd[2] = ( uint32_t )src;
- iap_cmd[3] = num;
- iap_cmd[4] = CONFIG_CPU_FREQUENCY / 1000L;
- iap_wrap( iap_cmd, iap_res );
- return iap_res[0];
- }
- FLASH_RES flash_file( uint8_t *filename )
- {
- sd2snes_fw_header *fw_header = ( sd2snes_fw_header * ) FW_START;
- uint32_t flash_addr = FW_START;
- uint32_t file_crc = 0xffffffff;
- uint16_t count;
- sd2snes_fw_header file_header;
- UINT bytes_read;
- if ( flash_addr != FW_START )
- {
- DBG_BL printf( "address sanity check failed. expected 0x%08lx, got 0x%08lx.\nSomething is terribly wrong.\nBailing out to avoid bootldr self-corruption.\n",
- FW_START, flash_addr );
- return ERR_HW;
- }
- file_open( filename, FA_READ );
- if ( file_res )
- {
- DBG_BL printf( "file_open: error %d\n", file_res );
- return ERR_FS;
- }
- DBG_BL printf( "firmware image found. file size: %ld\n", file_handle.fsize );
- DBG_BL printf( "reading header...\n" );
- f_read( &file_handle, &file_header, 32, &bytes_read );
- DBG_BL print_header( &file_header );
- if ( check_flash() || file_header.version != fw_header->version || file_header.version == FW_MAGIC
- || fw_header->version == FW_MAGIC )
- {
- DBG_UART uart_putc( 'F' );
- f_read( &file_handle, file_buf, 0xe0, &bytes_read );
- for ( ;; )
- {
- bytes_read = file_read();
- if ( file_res || !bytes_read )
- {
- break;
- }
- for ( count = 0; count < bytes_read; count++ )
- {
- file_crc = crc32_update( file_crc, file_buf[count] );
- }
- }
- file_crc = crc_finalize( file_crc );
- DBG_BL printf( "file crc=%08lx\n", file_crc );
- if ( check_header( &file_header, file_header.crc ) != ERR_OK )
- {
- DBG_BL printf( "Invalid firmware file (header corrupted).\n" );
- return ERR_FILEHD;
- }
- if ( file_header.crc != file_crc )
- {
- DBG_BL printf( "Firmware file checksum error.\n" );
- return ERR_FILECHK;
- }
- uint32_t res;
- writeled( 1 );
- DBG_BL printf( "erasing flash...\n" );
- DBG_UART uart_putc( 'P' );
- if ( ( res = iap_prepare_for_write( FW_START / 0x1000, FLASH_SECTORS ) ) != CMD_SUCCESS )
- {
- DBG_BL printf( "error %ld while preparing for erase\n", res );
- DBG_UART uart_putc( 'X' );
- return ERR_FLASHPREP;
- };
- DBG_UART uart_putc( 'E' );
- if ( ( res = iap_erase( FW_START / 0x1000, FLASH_SECTORS ) ) != CMD_SUCCESS )
- {
- DBG_BL printf( "error %ld while erasing\n", res );
- DBG_UART uart_putc( 'X' );
- return ERR_FLASHERASE;
- }
- DBG_BL printf( "writing... @%08lx\n", flash_addr );
- file_close();
- file_open( filename, FA_READ );
- uint8_t current_sec;
- uint32_t total_read = 0;
- for ( flash_addr = FW_START; flash_addr < 0x00020000; flash_addr += 0x200 )
- {
- total_read += ( bytes_read = file_read() );
- if ( file_res || !bytes_read )
- {
- break;
- }
- current_sec = flash_addr & 0x10000 ? ( 16 + ( ( flash_addr >> 15 ) & 1 ) )
- : ( flash_addr >> 12 );
- DBG_BL printf( "current_sec=%d flash_addr=%08lx\n", current_sec, flash_addr );
- DBG_UART uart_putc( '.' );
- if ( current_sec < ( FW_START / 0x1000 ) )
- {
- return ERR_FLASH;
- }
- DBG_UART uart_putc( current_sec["0123456789ABCDEFGH"] );
- DBG_UART uart_putc( 'p' );
- if ( ( res = iap_prepare_for_write( current_sec, current_sec ) ) != CMD_SUCCESS )
- {
- DBG_BL printf( "error %ld while preparing sector %d for write\n", res, current_sec );
- DBG_UART uart_putc( 'X' );
- return ERR_FLASH;
- }
- DBG_UART uart_putc( 'w' );
- if ( ( res = iap_ram2flash( flash_addr, file_buf, 512 ) ) != CMD_SUCCESS )
- {
- //printf("error %ld while writing to address %08lx (sector %d)\n", res, flash_addr, current_sec);
- DBG_UART uart_putc( 'X' );
- return ERR_FLASH;
- }
- }
- if ( total_read != ( file_header.size + 0x100 ) )
- {
- DBG_BL printf( "wrote less data than expected! (%08lx vs. %08lx)\n", total_read, file_header.size );
- // DBG_UART uart_putc('X');
- return ERR_FILECHK;
- }
- writeled( 0 );
- }
- else
- {
- DBG_UART uart_putc( 'n' );
- DBG_BL printf( "flash content is ok, no version mismatch, no forced upgrade. No need to flash\n" );
- }
- return ERR_OK;
- }
|