iap.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #include <arm/NXP/LPC17xx/LPC17xx.h>
  2. #include <string.h>
  3. #include "bits.h"
  4. #include "iap.h"
  5. #include "config.h"
  6. #include "uart.h"
  7. #include "fileops.h"
  8. #include "crc32.h"
  9. #include "led.h"
  10. uint32_t iap_cmd[5];
  11. uint32_t iap_res[5];
  12. uint32_t flash_sig[4];
  13. IAP iap_entry = ( IAP ) IAP_LOCATION;
  14. uint32_t calc_flash_crc( uint32_t start, uint32_t len )
  15. {
  16. DBG_BL printf( "calc_flash_crc(%08lx, %08lx) {\n", start, len );
  17. uint32_t end = start + len;
  18. if ( end > 0x20000 )
  19. {
  20. len = 0x1ffff - start;
  21. end = 0x20000;
  22. }
  23. uint32_t crc = 0xffffffff;
  24. uint32_t s = start;
  25. while ( s < end )
  26. {
  27. crc = crc32_update( crc, *( const unsigned char * )( s ) );
  28. s++;
  29. }
  30. crc = crc_finalize( crc );
  31. DBG_BL printf( " crc generated. result=%08lx\n", crc );
  32. DBG_BL printf( "} //calc_flash_crc\n" );
  33. return crc;
  34. }
  35. void test_iap()
  36. {
  37. iap_cmd[0] = 54;
  38. iap_entry( iap_cmd, iap_res );
  39. DBG_BL printf( "Part ID=%08lx\n", iap_res[1] );
  40. }
  41. void print_header( sd2snes_fw_header *header )
  42. {
  43. DBG_BL printf( " magic = %08lx\n version = %08lx\n size = %08lx\n crc = %08lx\n ~crc = %08lx\n",
  44. header->magic, header->version, header->size,
  45. header->crc, header->crcc );
  46. }
  47. int check_header( sd2snes_fw_header *header, uint32_t crc )
  48. {
  49. if ( ( header->magic != FW_MAGIC )
  50. || ( header->size < 0x200 )
  51. || ( header->size > ( 0x1ffff - FW_START ) )
  52. || ( ( header->crc ^ header->crcc ) != 0xffffffff ) )
  53. {
  54. return ERR_FLASHHD;
  55. }
  56. if ( header->crc != crc )
  57. {
  58. return ERR_FLASHCRC;
  59. }
  60. return ERR_OK;
  61. }
  62. FLASH_RES check_flash()
  63. {
  64. sd2snes_fw_header *fw_header = ( sd2snes_fw_header * ) FW_START;
  65. uint32_t flash_addr = FW_START;
  66. if ( flash_addr != FW_START )
  67. {
  68. 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",
  69. FW_START, flash_addr );
  70. return ERR_HW;
  71. }
  72. DBG_BL printf( "Current flash contents:\n" );
  73. DBG_BL print_header( fw_header );
  74. uint32_t crc = calc_flash_crc( flash_addr + 0x100, ( fw_header->size & 0x1ffff ) );
  75. return check_header( fw_header, crc );
  76. }
  77. IAP_RES iap_wrap( uint32_t *iap_cmd, uint32_t *iap_res )
  78. {
  79. // NVIC_DisableIRQ(RIT_IRQn);
  80. // NVIC_DisableIRQ(UART_IRQ);
  81. for ( volatile int i = 0; i < 2048; i++ );
  82. iap_entry( iap_cmd, iap_res );
  83. for ( volatile int i = 0; i < 2048; i++ );
  84. // NVIC_EnableIRQ(UART_IRQ);
  85. return iap_res[0];
  86. }
  87. IAP_RES iap_prepare_for_write( uint32_t start, uint32_t end )
  88. {
  89. if ( start < ( FW_START / 0x1000 ) )
  90. {
  91. return INVALID_SECTOR;
  92. }
  93. iap_cmd[0] = 50;
  94. iap_cmd[1] = start;
  95. iap_cmd[2] = end;
  96. iap_wrap( iap_cmd, iap_res );
  97. return iap_res[0];
  98. }
  99. IAP_RES iap_erase( uint32_t start, uint32_t end )
  100. {
  101. if ( start < ( FW_START / 0x1000 ) )
  102. {
  103. return INVALID_SECTOR;
  104. }
  105. iap_cmd[0] = 52;
  106. iap_cmd[1] = start;
  107. iap_cmd[2] = end;
  108. iap_cmd[3] = CONFIG_CPU_FREQUENCY / 1000L;
  109. iap_wrap( iap_cmd, iap_res );
  110. return iap_res[0];
  111. }
  112. IAP_RES iap_ram2flash( uint32_t tgt, uint8_t *src, int num )
  113. {
  114. iap_cmd[0] = 51;
  115. iap_cmd[1] = tgt;
  116. iap_cmd[2] = ( uint32_t )src;
  117. iap_cmd[3] = num;
  118. iap_cmd[4] = CONFIG_CPU_FREQUENCY / 1000L;
  119. iap_wrap( iap_cmd, iap_res );
  120. return iap_res[0];
  121. }
  122. FLASH_RES flash_file( uint8_t *filename )
  123. {
  124. sd2snes_fw_header *fw_header = ( sd2snes_fw_header * ) FW_START;
  125. uint32_t flash_addr = FW_START;
  126. uint32_t file_crc = 0xffffffff;
  127. uint16_t count;
  128. sd2snes_fw_header file_header;
  129. UINT bytes_read;
  130. if ( flash_addr != FW_START )
  131. {
  132. 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",
  133. FW_START, flash_addr );
  134. return ERR_HW;
  135. }
  136. file_open( filename, FA_READ );
  137. if ( file_res )
  138. {
  139. DBG_BL printf( "file_open: error %d\n", file_res );
  140. return ERR_FS;
  141. }
  142. DBG_BL printf( "firmware image found. file size: %ld\n", file_handle.fsize );
  143. DBG_BL printf( "reading header...\n" );
  144. f_read( &file_handle, &file_header, 32, &bytes_read );
  145. DBG_BL print_header( &file_header );
  146. if ( check_flash() || file_header.version != fw_header->version || file_header.version == FW_MAGIC
  147. || fw_header->version == FW_MAGIC )
  148. {
  149. DBG_UART uart_putc( 'F' );
  150. f_read( &file_handle, file_buf, 0xe0, &bytes_read );
  151. for ( ;; )
  152. {
  153. bytes_read = file_read();
  154. if ( file_res || !bytes_read )
  155. {
  156. break;
  157. }
  158. for ( count = 0; count < bytes_read; count++ )
  159. {
  160. file_crc = crc32_update( file_crc, file_buf[count] );
  161. }
  162. }
  163. file_crc = crc_finalize( file_crc );
  164. DBG_BL printf( "file crc=%08lx\n", file_crc );
  165. if ( check_header( &file_header, file_header.crc ) != ERR_OK )
  166. {
  167. DBG_BL printf( "Invalid firmware file (header corrupted).\n" );
  168. return ERR_FILEHD;
  169. }
  170. if ( file_header.crc != file_crc )
  171. {
  172. DBG_BL printf( "Firmware file checksum error.\n" );
  173. return ERR_FILECHK;
  174. }
  175. uint32_t res;
  176. writeled( 1 );
  177. DBG_BL printf( "erasing flash...\n" );
  178. DBG_UART uart_putc( 'P' );
  179. if ( ( res = iap_prepare_for_write( FW_START / 0x1000, FLASH_SECTORS ) ) != CMD_SUCCESS )
  180. {
  181. DBG_BL printf( "error %ld while preparing for erase\n", res );
  182. DBG_UART uart_putc( 'X' );
  183. return ERR_FLASHPREP;
  184. };
  185. DBG_UART uart_putc( 'E' );
  186. if ( ( res = iap_erase( FW_START / 0x1000, FLASH_SECTORS ) ) != CMD_SUCCESS )
  187. {
  188. DBG_BL printf( "error %ld while erasing\n", res );
  189. DBG_UART uart_putc( 'X' );
  190. return ERR_FLASHERASE;
  191. }
  192. DBG_BL printf( "writing... @%08lx\n", flash_addr );
  193. file_close();
  194. file_open( filename, FA_READ );
  195. uint8_t current_sec;
  196. uint32_t total_read = 0;
  197. for ( flash_addr = FW_START; flash_addr < 0x00020000; flash_addr += 0x200 )
  198. {
  199. total_read += ( bytes_read = file_read() );
  200. if ( file_res || !bytes_read )
  201. {
  202. break;
  203. }
  204. current_sec = flash_addr & 0x10000 ? ( 16 + ( ( flash_addr >> 15 ) & 1 ) )
  205. : ( flash_addr >> 12 );
  206. DBG_BL printf( "current_sec=%d flash_addr=%08lx\n", current_sec, flash_addr );
  207. DBG_UART uart_putc( '.' );
  208. if ( current_sec < ( FW_START / 0x1000 ) )
  209. {
  210. return ERR_FLASH;
  211. }
  212. DBG_UART uart_putc( current_sec["0123456789ABCDEFGH"] );
  213. DBG_UART uart_putc( 'p' );
  214. if ( ( res = iap_prepare_for_write( current_sec, current_sec ) ) != CMD_SUCCESS )
  215. {
  216. DBG_BL printf( "error %ld while preparing sector %d for write\n", res, current_sec );
  217. DBG_UART uart_putc( 'X' );
  218. return ERR_FLASH;
  219. }
  220. DBG_UART uart_putc( 'w' );
  221. if ( ( res = iap_ram2flash( flash_addr, file_buf, 512 ) ) != CMD_SUCCESS )
  222. {
  223. //printf("error %ld while writing to address %08lx (sector %d)\n", res, flash_addr, current_sec);
  224. DBG_UART uart_putc( 'X' );
  225. return ERR_FLASH;
  226. }
  227. }
  228. if ( total_read != ( file_header.size + 0x100 ) )
  229. {
  230. DBG_BL printf( "wrote less data than expected! (%08lx vs. %08lx)\n", total_read, file_header.size );
  231. // DBG_UART uart_putc('X');
  232. return ERR_FILECHK;
  233. }
  234. writeled( 0 );
  235. }
  236. else
  237. {
  238. DBG_UART uart_putc( 'n' );
  239. DBG_BL printf( "flash content is ok, no version mismatch, no forced upgrade. No need to flash\n" );
  240. }
  241. return ERR_OK;
  242. }