#include "bootloader.h" #include "card10-version.h" #include "card10.h" #include "led.h" #include "pb.h" #include "pmic.h" #include "board.h" #include "crc.h" #include "crc16-ccitt.h" #include "ff.h" #include "flc.h" #include "i2c.h" #include "icc.h" #include "mxc_config.h" #include "mxc_delay.h" #include "mxc_sys.h" #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <string.h> #include <errno.h> #define GPIO_PORT_IN PORT_1 #define GPIO_PIN_IN PIN_6 #define PARTITION_START (0x10000000 + 64 * 1024) #define PARTITION_END (0x10000000 + 1024 * 1024 - 1) DIR dir; FATFS FatFs; int format(void) { BYTE work[FF_MAX_SS * 16]; /* Create FAT volume */ int res = f_mkfs("", FM_ANY | FM_SFD, 0, work, sizeof work); if (res != FR_OK) { printf("Failed to make new FS %d\n", res); return -1; } f_setlabel("card10"); if (res != FR_OK) { printf("Failed to set volume name %d\n", res); return -1; } return 0; } int mount(void) { FRESULT res; res = f_mount(&FatFs, "/", 0); if (res != FR_OK) { printf("f_mount error %d\n", res); return -1; } res = f_opendir(&dir, "0:"); if (res != FR_OK) { printf("f_opendir error %d\n", res); return -1; } return 0; } int check_integrity(void) { FIL file; UINT readbytes; char *filename = "card10.bin"; uint8_t data[512]; FRESULT res; res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ); if (res != FR_OK) { printf("f_open error %d\n", res); return -ENOENT; } uint16_t crcval = 0; do { res = f_read(&file, data, sizeof(data), &readbytes); if (res != FR_OK) { printf("f_read error %d\n", res); crcval = 1; // Make sure to fail the test break; } crcval = crc16_ccitt(crcval, data, readbytes); } while (readbytes == sizeof(data)); f_close(&file); if (crcval != 0) { printf("CRC check failed. Final CRC: %d\n", crcval); return -EINVAL; } return 0; } bool is_update_needed(void) { FIL file; UINT readbytes; char *filename = "card10.bin"; uint8_t data[512]; FRESULT res; res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ); if (res != FR_OK) { printf("f_open error %d\n", res); return false; } uint8_t *partition = (uint8_t *)(intptr_t)PARTITION_START; bool different = false; do { res = f_read(&file, data, sizeof(data), &readbytes); if (res != FR_OK) { printf("f_read error %d\n", res); break; /* Going to return false, don't want to use this file */ } if (memcmp(partition, data, readbytes)) { different = true; break; } partition += readbytes; } while (readbytes == sizeof(data)); f_close(&file); return different; } void erase_partition(void) { int ret = FLC_MultiPageErase(PARTITION_START, PARTITION_END); if (ret != E_NO_ERROR) { printf("FLC_MultiPageErase failed with %d\n", ret); while (1) ; } } void flash_partition(void) { FIL file; UINT readbytes; char *filename = "card10.bin"; uint8_t data[512]; FRESULT res; res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ); if (res != FR_OK) { printf("f_open error %d\n", res); while (1) ; } uint32_t partition = PARTITION_START; ICC_Disable(); do { res = f_read(&file, data, sizeof(data), &readbytes); if (res != FR_OK) { printf("f_read error %d\n", res); break; /* Going to return false, don't want to use this file */ } int ret = FLC_Write( partition, readbytes, (uint32_t * ) data); /* wild cast. not sure if this works */ if (ret != E_NO_ERROR) { printf("FLC_Write failed with %d\n", ret); while (1) ; } partition += readbytes; } while (readbytes == sizeof(data)); ICC_Enable(); f_close(&file); } static inline void boot(const void *vtable) { SCB->VTOR = (uintptr_t)vtable; // Reset stack pointer & branch to the new reset vector. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated" __asm("mov r0, %0\n" "ldr sp, [r0]\n" "ldr r0, [r0, #4]\n" "bx r0\n" : : "r"(vtable) : "%sp", "r0"); #pragma GCC diagnostic pop }; static void pmic_button(bool falling) { if (falling) { card10_reset(); } } static void msc(void) { bootloader_display_header(); bootloader_display_line(3, "USB activated.", 0xffff); bootloader_display_line(4, "Ready.", 0xffff); run_usbmsc(); // If we return, don't try to boot. Maybe rather trigger a software reset. // Reason: Not sure in which state the USB peripheral is and what kind // of interrupts are active. while (1) ; } /******************************************************************************/ int main(void) { printf("\n\nBootloader " CARD10_VERSION "\n"); card10_init(); /* * Make the power/reset button restart card10. */ pmic_set_button_callback(pmic_button); bootloader_display_init(); // If the button is pressed, we go into MSC mode. if (PB_Get(3)) { msc(); } if (mount() == 0) { int res = check_integrity(); if (res == -ENOENT) { printf("card10.bin not found!\n"); } else if (res == -EINVAL) { printf("card10.bin CRC is invalid!\n"); bootloader_display_header(); bootloader_display_line( 3, "Integrity check failed", 0xffff ); bootloader_display_line(4, "Trying to boot", 0xffff); } else if (res == 0) { printf("Found valid application image\n"); if (is_update_needed()) { printf("Trying to update firmware from external flash\n"); bootloader_display_header(); bootloader_display_line( 4, "Updating ...", 0xffff ); erase_partition(); flash_partition(); f_unlink("card10.bin"); bootloader_display_line( 4, "Trying to boot", 0xffff ); } else { printf("No update needed\n"); } } } else { bootloader_display_header(); bootloader_display_line(3, "Creating new filesystem", 0xffff); printf("Creating new filesystem\n"); if (format() == 0) { /* Drop into MSC after a reboot */ card10_reset(); } else { bootloader_display_line( 3, "Failed to create new filesystem", 0xffff ); printf("Feiled to create new filesystem\n"); /* Prevent bootloops */ while (1) { } } } /* Get the intital SP of the firmware. If it is 0xFFFFFFFF, no image has been * flashed yet. Drop into MSC for initial flashing. */ if (*((uint32_t *)PARTITION_START) == 0xFFFFFFFF) { printf("No valid image in flash\n"); msc(); } printf("Trying to boot\n"); boot((uintptr_t *)PARTITION_START); while (1) { // Should never be reached. } } /******************************************************************************/ void SysTick_Handler(void) { mxc_delay_handler(); }