diff --git a/firmware/bootloader/src/Makefile b/firmware/bootloader/src/Makefile index 645dcca28f..e21f4b3a51 100644 --- a/firmware/bootloader/src/Makefile +++ b/firmware/bootloader/src/Makefile @@ -191,11 +191,11 @@ CPPSRC = $(ALLCPPSRC) \ $(PROJECT_DIR)/controllers/algo/engine_configuration.cpp \ $(PROJECT_DIR)/controllers/persistent_store.cpp \ $(PROJECT_DIR)/hw_layer/io_pins.cpp \ + $(PROJECT_DIR)/hw_layer/serial_over_usb/usbcfg.cpp \ $(PROJECT_DIR)/util/efilib.cpp \ $(PROJECT_DIR)/hw_layer/pin_repository.cpp \ $(RUSEFI_LIB_CPP) \ src/rusefi_stubs.cpp \ - src/dfu.cpp \ src/main.cpp # C sources to be compiled in ARM mode regardless of the global setting. diff --git a/firmware/bootloader/src/dfu.cpp b/firmware/bootloader/src/dfu.cpp deleted file mode 100644 index 66b4b22ac3..0000000000 --- a/firmware/bootloader/src/dfu.cpp +++ /dev/null @@ -1,319 +0,0 @@ -#include "pch.h" - -#include "hardware.h" - -#include "flash_int.h" - -#include "dfu.h" - -// Communication vars -static UartTsChannel blTsChannel(TS_PRIMARY_UxART_PORT); -static uint8_t buffer[DFU_BUFFER_SIZE]; -// Use short timeout for the first data packet, and normal timeout for the rest -static int sr5Timeout = DFU_SR5_TIMEOUT_FIRST; - -// This big buffer is used for temporary storing of the bootloader flash page -static uint8_t bootloaderVirtualPageBuffer[BOOTLOADER_SIZE]; - - -// needed by DFU protocol (DFU_DEVICE_ID_CMD) -static uint32_t getMcuRevision() { - // =0x413 for F407 - // =0x419 for F42xxx and F43xxx - // =0x434 for F469 - return DBGMCU->IDCODE & MCU_REVISION_MASK; -} - -static bool getByte(uint8_t *b) { - return blTsChannel.readTimeout(b, 1, sr5Timeout) == 1; -} - -static void sendByte(uint8_t b) { - blTsChannel.write(&b, 1, true); -} - -static uint8_t dfuCalcChecksum(const uint8_t *buf, uint8_t size) { - uint8_t checksum = buf[0]; - - for (uint8_t i = 1; i < size; i++) { - checksum ^= buf[i]; - } - return checksum; -} - -// Used to detect writing of the current flash sector -static bool isBootloaderAddress(uint32_t addr) { - return addr >= BOOTLOADER_ADDR && addr < (BOOTLOADER_ADDR + BOOTLOADER_SIZE); -} - -static bool isInVirtualPageBuffer(uint32_t addr) { - return addr >= (uint32_t)bootloaderVirtualPageBuffer && addr < (uint32_t)bootloaderVirtualPageBuffer + sizeof(bootloaderVirtualPageBuffer); -} - -// Read 32-bit address and 8-bit checksum. -// Returns true if all 5 bytes are received and checksum is correct, and false otherwise. -static bool readAddress(uint32_t *addr) { - uint8_t buf[5]; // 4 bytes+checksum - if (blTsChannel.readTimeout(buf, 5, sr5Timeout) != 5) - return false; - if (dfuCalcChecksum(buf, 4) != buf[4]) - return false; - *addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - - // for bootloader flash, return a virtual buffer instead - if (isBootloaderAddress(*addr)) { - *addr = (uint32_t)bootloaderVirtualPageBuffer + (*addr - BOOTLOADER_ADDR); - } - - return true; -} - -// needed by DFU protocol to validate received bytes -static uint8_t complementByte(uint8_t c) { - return c ^ 0xff; -} - -static uint16_t bufToInt16(uint8_t *buf) { - return (buf[0] << 8) | buf[1]; -} - -static void prepareInterruptsForJump() { -#ifdef STM32F4 - // interrupt control - SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk; - // set interrupt vectors - for(int i = 0; i < 8; i++) - NVIC->ICER[i] = NVIC->IABR[i]; - __set_CONTROL(0); -#else -// todo: add support for other MCUs -#error "Unsupported MCU configuration!" -#endif -} - -// some weird STM32 magic... -void dfuJumpToApp(uint32_t addr) { - typedef void (*pFunction)(void); - - // goodbye ChibiOS, we're leaving... - chSysDisable(); - - // get jump addr - uint32_t jumpAddress = *((uint32_t *)(addr + 4)); - pFunction jump = (pFunction) jumpAddress; - prepareInterruptsForJump(); - // set stack pointer - __set_MSP(*(uint32_t *)addr); - - // call - jump(); - - // we shouldn't get here - chSysHalt("dfuJumpToApp FAIL"); -} - -static void dfuHandleGetList() { - static const uint8_t cmdsInfo[] = { DFU_VERSION_NUMBER, DFU_GET_LIST_CMD, DFU_DEVICE_ID_CMD, DFU_READ_CMD, DFU_GO_CMD, - DFU_WRITE_CMD, DFU_ERASE_CMD }; - size_t numBytes = sizeof(cmdsInfo); - sendByte(numBytes - 1); // number of commands - for (size_t i = 0; i < numBytes; i++) - sendByte(cmdsInfo[i]); - sendByte(DFU_ACK_BYTE); -} - -static void dfuHandleDeviceId() { - uint32_t mcuRev = getMcuRevision(); - sendByte(0x01); // the number of bytes to be send - 1 - // send 12 bit MCU revision - sendByte((uint8_t)((mcuRev >> 8) & 0xf)); - sendByte((uint8_t)(mcuRev & 0xff)); - sendByte(DFU_ACK_BYTE); -} - -static void dfuHandleGo() { - uint32_t addr; - - if (!readAddress(&addr)) { - sendByte(DFU_NACK_BYTE); - return; - } - // todo: check if the address is valid - sendByte(DFU_ACK_BYTE); - dfuJumpToApp(addr); -} - -static void dfuHandleRead() { - uint32_t addr; - - if (!readAddress(&addr)) { - sendByte(DFU_NACK_BYTE); - return; - } - sendByte(DFU_ACK_BYTE); - uint8_t byte, complement; - if (!getByte(&byte)) - return; - if (!getByte(&complement)) - return; - // check if we have a correct byte received - if (complement != complementByte(byte)) { - sendByte(DFU_NACK_BYTE); - return; - } - int numBytes = (int)byte + 1; - sendByte(DFU_ACK_BYTE); - - // read flash or virtual RAM buffer (don't transmit directly from flash) - if (isInVirtualPageBuffer(addr)) - memcpy(buffer, (uint8_t *)addr, numBytes); - else - intFlashRead(addr, (char *)buffer, numBytes); - - // transmit data - blTsChannel.write(buffer, numBytes, true); -} - -static void dfuHandleWrite() { - uint32_t addr; - - if (!readAddress(&addr)) { - sendByte(DFU_NACK_BYTE); - return; - } - sendByte(DFU_ACK_BYTE); - if (!getByte(buffer)) - return; - - int numBytes = buffer[0] + 1; - int numBytesAndChecksum = numBytes + 1; // +1 byte of checkSum - // receive data - if (blTsChannel.readTimeout(buffer + 1, numBytesAndChecksum, sr5Timeout) != numBytesAndChecksum) - return; - // don't write corrupted data! - if (dfuCalcChecksum(buffer, numBytesAndChecksum) != buffer[numBytesAndChecksum]) { - sendByte(DFU_NACK_BYTE); - return; - } - - // now write to flash (or to the virtual RAM buffer) - if (isInVirtualPageBuffer(addr)) - memcpy((uint8_t *)addr, (buffer + 1), numBytes); - else - intFlashWrite(addr, (const char *)(buffer + 1), numBytes); - - // we're done! - sendByte(DFU_ACK_BYTE); -} - -static void dfuHandleErase() { - int numSectors; - if (!getByte(buffer)) - return; - if (!getByte(buffer + 1)) - return; - numSectors = bufToInt16(buffer); - int numSectorData; - if (numSectors == 0xffff) // erase all chip - numSectorData = 1; - else - numSectorData = (numSectors + 1) * 2 + 1; - uint8_t *sectorList = buffer + 2; - // read sector data & checksum - if (blTsChannel.readTimeout(sectorList, numSectorData, sr5Timeout) != numSectorData) - return; - // verify checksum - if (dfuCalcChecksum(buffer, 2 + numSectorData - 1) != buffer[2 + numSectorData - 1]) { - sendByte(DFU_NACK_BYTE); - return; - } - // Erase the chosen sectors, sector by sector - for (int i = 0; i < numSectorData - 1; i += 2) { - int sectorIdx = bufToInt16(sectorList + i); - if (sectorIdx < BOOTLOADER_NUM_SECTORS) { // skip first sectors where our bootloader is - // imitate flash erase by writing '0xff' - memset(bootloaderVirtualPageBuffer, 0xff, BOOTLOADER_SIZE); - continue; - } - // erase sector - intFlashSectorErase(sectorIdx); - } - - sendByte(DFU_ACK_BYTE); -} - -bool dfuStartLoop(void) { - bool wasCommand = false; - uint8_t command, complement; - - sr5Timeout = DFU_SR5_TIMEOUT_FIRST; - - // We cannot afford waiting for the first handshake byte, so we have to send an answer in advance! - sendByte(DFU_ACK_BYTE); - - // Fill the temporary buffer from the real flash memory - memcpy(bootloaderVirtualPageBuffer, (void *)BOOTLOADER_ADDR, BOOTLOADER_SIZE); - - while (true) { - // read command & complement bytes - if (!getByte(&command)) { - // timeout, but wait more if we're in bootloader mode - if (wasCommand) - continue; - // exit if no data was received - break; - } - if (!getByte(&complement)) { - if (wasCommand) { - // something is wrong, but keep the connection - sendByte(DFU_NACK_BYTE); - continue; - } - break; - } - - // check if we have a correct command received - if (complement != complementByte(command)) { - sendByte(DFU_NACK_BYTE); - continue; - } - - // confirm that we've got the command - sendByte(DFU_ACK_BYTE); - wasCommand = true; - // set normal (longer) timeout, we're not in a hurry anymore - sr5Timeout = DFU_SR5_TIMEOUT_NORMAL; - - // now execute it (see ST appnote "AN3155") - switch (command) { - case DFU_UART_CHECK: - break; - case DFU_GET_LIST_CMD: - dfuHandleGetList(); - break; - case DFU_DEVICE_ID_CMD: - dfuHandleDeviceId(); - break; - case DFU_GO_CMD: - dfuHandleGo(); - break; - case DFU_READ_CMD: - dfuHandleRead(); - break; - case DFU_WRITE_CMD: - dfuHandleWrite(); - break; - case DFU_ERASE_CMD: - dfuHandleErase(); - break; - default: - break; - } /* End switch */ - } - - return wasCommand; -} - -SerialTsChannelBase *getTsChannel() { - return &blTsChannel; -} diff --git a/firmware/bootloader/src/dfu.h b/firmware/bootloader/src/dfu.h deleted file mode 100644 index a87ba93956..0000000000 --- a/firmware/bootloader/src/dfu.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "tunerstudio_io.h" - -// This is where the bootloader starts -#define BOOTLOADER_ADDR 0x08000000 -// Bootloader code max. size, in bytes -#define BOOTLOADER_SIZE 0x8000 -// Number of sectors for the bootloader -#define BOOTLOADER_NUM_SECTORS (BOOTLOADER_SIZE/0x4000) - -// This is where the application starts -#define APPLICATION_ADDR 0x08008000 - -#define DFU_BUFFER_SIZE 258 // Max. 256 bytes at a time plus 2 bytes (numBytes+checksum) - - -// DFU/USART Protocol is described in AN3155 document "Application note. USART protocol used in the STM32 bootloader" -// http://www.st.com/resource/en/application_note/cd00264342.pdf - -#define DFU_UART_CHECK 0x7F // "UART handshake" escape byte - -#define DFU_GET_LIST_CMD 0x00 // "Get supported commands list" command -#define DFU_DEVICE_ID_CMD 0x02 // "Get device ID" command -#define DFU_READ_CMD 0x11 // "Read memory" command -#define DFU_GO_CMD 0x21 // "Go" command -#define DFU_WRITE_CMD 0x31 // "Write memory" command -#define DFU_ERASE_CMD 0x44 // "Erase memory" command - -#define DFU_VERSION_NUMBER 0x31 // The DFU protocol version number -#define DFU_ACK_BYTE 0x79 // Acknowledge byte ID -#define DFU_NACK_BYTE 0x1F // Not-Acknowledge byte ID - -#define DFU_SR5_TIMEOUT_FIRST TIME_MS2I(200) -#define DFU_SR5_TIMEOUT_NORMAL TIME_MS2I(1000) - -#define MCU_REVISION_MASK 0xfff // MCU Revision ID is needed by DFU protocol - -// The address in MCU system memory where the bootloader version number is stored (2 bytes) -#define DFU_BOOTLOADER_VERSION_ADDRESS 0x1FFF76DE - -/** - * @brief This function waits for the command to apply (write, read etc...) - */ -bool dfuStartLoop(void); -/** - * @brief Jump to the application - */ -void dfuJumpToApp(uint32_t addr); - -SerialTsChannelBase* getTsChannel(); diff --git a/firmware/bootloader/src/main.cpp b/firmware/bootloader/src/main.cpp index ff3bfea6b0..486e18680d 100644 --- a/firmware/bootloader/src/main.cpp +++ b/firmware/bootloader/src/main.cpp @@ -3,38 +3,10 @@ #include "hardware.h" -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#include -#include -#include - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#include "dfu.h" - -static bool wasCommand = false; - -static THD_WORKING_AREA(waBootloaderSerial, 128); -static THD_FUNCTION(thBootloaderSerial, arg) { - (void)arg; - chRegSetThreadName("BootloaderSerial"); - - // start our DFU emulator - wasCommand = dfuStartLoop(); - - chThdExit(MSG_OK); -} - int main(void) { - // run ChibiOS halInit(); chSysInit(); + // set base pin configuration based on the board setDefaultBasePins(); /* at the moment SD card is not needed by bootloader @@ -42,23 +14,7 @@ int main(void) { setDefaultSdCardParameters(); */ - // start UART - getTsChannel()->start(38400); // TODO: should bootloader serial speed be configurable? - - // start a serial port reader thread - thread_t *thrSerial = chThdCreateStatic(waBootloaderSerial, sizeof(waBootloaderSerial), NORMALPRIO, thBootloaderSerial, NULL); - - // wait for the thread to finish - chThdWait(thrSerial); - -#if 0 - if (wasCommand) // abnormal termination of the bootloader thread - chSysHalt("Bootloader DFU FAIL"); -#endif - - // Run application - dfuJumpToApp(APPLICATION_ADDR); - - return 0; + while (true) { + chThdSleepMilliseconds(1); + } } -