iap.c 6.8 KB

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