diff --git a/firmware/bootloader/openblt_chibios/nvm.c b/firmware/bootloader/openblt_chibios/nvm.c new file mode 100644 index 0000000000..4243170776 --- /dev/null +++ b/firmware/bootloader/openblt_chibios/nvm.c @@ -0,0 +1,257 @@ +/************************************************************************************//** +* \file Source/_template/nvm.c +* \brief Bootloader non-volatile memory driver source file. +* \ingroup Target__template_nvm +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2019 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or +* modify it under the terms of the GNU General Public License as published by the Free +* Software Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You have received a copy of the GNU General Public License along with OpenBLT. It +* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. +* +* \endinternal +****************************************************************************************/ + +/************************************************************************************//** +* \defgroup Target__template_nvm Non-volatile memory driver of a port +* \brief This module implements the non-volatile memory driver of a microcontroller +* port. Note that the default implementation if for a microcontroller that +* has internal flash memory. At the time of this writing pretty much all +* microcontrollers use flash EEPROM as non-volatile memory to store the +* program code. Assuming that this is also the case for the microcontroller +* for which the port is developed, nothing needs to be modified in this +* source file. +* \ingroup Target__template +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include "boot.h" /* bootloader generic header */ +#include "flash.h" + + +/**************************************************************************************** +* Hook functions +****************************************************************************************/ +#if (BOOT_NVM_HOOKS_ENABLE > 0) +extern void NvmInitHook(void); +extern void NvmReinitHook(void); +extern blt_int8u NvmWriteHook(blt_addr addr, blt_int32u len, blt_int8u *data); +extern blt_int8u NvmEraseHook(blt_addr addr, blt_int32u len); +extern blt_bool NvmDoneHook(void); +#endif + +#if (BOOT_NVM_CHECKSUM_HOOKS_ENABLE > 0) +extern blt_bool NvmWriteChecksumHook(void); +extern blt_bool NvmVerifyChecksumHook(void); +#endif + + +/************************************************************************************//** +** \brief Initializes the NVM driver. +** \return none. +** +****************************************************************************************/ +void NvmInit(void) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to initialize a driver for operating on NVM + * that is not by default supported by this driver. + */ + NvmInitHook(); +#endif + + /* init the internal driver */ + FlashInit(); +} /*** end of NvmInit ***/ + + +/************************************************************************************//** +** \brief Reinitializes the NVM driver. This function is called at the start of each +** firmware update as opposed to NvmInit, which is only called once during +** power on. +** \return none. +** +****************************************************************************************/ +void NvmReinit(void) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to re-initialize a driver for operating on NVM + * that is not by default supported by this driver. + */ + NvmReinitHook(); +#endif + + /* reinitialize the internal driver */ + FlashReinit(); +} /*** end of NvmReinit ***/ + + +/************************************************************************************//** +** \brief Programs the non-volatile memory. +** \param addr Start address. +** \param len Length in bytes. +** \param data Pointer to the data buffer. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmWrite(blt_addr addr, blt_int32u len, blt_int8u *data) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + blt_int8u result = BLT_NVM_NOT_IN_RANGE; +#endif + +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to operate on memory that is not by default supported + * by this driver. + */ + result = NvmWriteHook(addr, len, data); + + /* process the return code */ + if (result == BLT_NVM_OKAY) + { + /* data was within range of the additionally supported memory and succesfully + * programmed, so we are all done. + */ + return BLT_TRUE; + } + else if (result == BLT_NVM_ERROR) + { + /* data was within range of the additionally supported memory and attempted to be + * programmed, but an error occurred, so we can't continue. + */ + return BLT_FALSE; + } +#endif + + /* still here so the internal driver should try and perform the program operation */ + return FlashWrite(addr, len, data); +} /*** end of NvmWrite ***/ + + +/************************************************************************************//** +** \brief Erases the non-volatile memory. +** \param addr Start address. +** \param len Length in bytes. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmErase(blt_addr addr, blt_int32u len) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + blt_int8u result = BLT_NVM_NOT_IN_RANGE; +#endif + +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application a chance to operate on memory that is not by default supported + * by this driver. + */ + result = NvmEraseHook(addr, len); + + /* process the return code */ + if (result == BLT_NVM_OKAY) + { + /* address was within range of the additionally supported memory and succesfully + * erased, so we are all done. + */ + return BLT_TRUE; + } + else if (result == BLT_NVM_ERROR) + { + /* address was within range of the additionally supported memory and attempted to be + * erased, but an error occurred, so we can't continue. + */ + return BLT_FALSE; + } +#endif + + /* still here so the internal driver should try and perform the erase operation */ + return FlashErase(addr, len); +} /*** end of NvmErase ***/ + + +/************************************************************************************//** +** \brief Verifies the checksum, which indicates that a valid user program is +** present and can be started. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmVerifyChecksum(void) +{ +#if (BOOT_NVM_CHECKSUM_HOOKS_ENABLE > 0) + /* check checksum using the application specific method. */ + return NvmVerifyChecksumHook(); +#else + /* check checksum using the interally supported method. */ + return FlashVerifyChecksum(); +#endif +} /*** end of NvmVerifyChecksum ***/ + + +/************************************************************************************//** +** \brief Obtains the base address of the non-volatile memory available to the user +** program. This is typically that start of the vector table. +** \return Base address. +** +****************************************************************************************/ +blt_addr NvmGetUserProgBaseAddress(void) +{ + return FlashGetUserProgBaseAddress(); +} /*** end of NvmGetUserProgBaseAddress ***/ + + +/************************************************************************************//** +** \brief Once all erase and programming operations are completed, this +** function is called, so at the end of the programming session and +** right before a software reset is performed. It is used to calculate +** a checksum and program this into flash. This checksum is later used +** to determine if a valid user program is present in flash. +** \return BLT_TRUE if successful, BLT_FALSE otherwise. +** +****************************************************************************************/ +blt_bool NvmDone(void) +{ +#if (BOOT_NVM_HOOKS_ENABLE > 0) + /* give the application's NVM driver a chance to finish up */ + if (NvmDoneHook() == BLT_FALSE) + { + /* error so no need to continue */ + return BLT_FALSE; + } +#endif + +#if (BOOT_NVM_CHECKSUM_HOOKS_ENABLE > 0) + /* compute and write checksum, using the application specific method. */ + if (NvmWriteChecksumHook() == BLT_FALSE) + { + return BLT_FALSE; + } +#else + /* compute and write checksum, which is programmed by the internal driver. */ + if (FlashWriteChecksum() == BLT_FALSE) + { + return BLT_FALSE; + } +#endif + + /* finish up internal driver operations */ + return FlashDone(); +} /*** end of NvmDone ***/ + + +/*********************************** end of nvm.c **************************************/ diff --git a/firmware/bootloader/openblt_chibios/openblt_chibios.cpp b/firmware/bootloader/openblt_chibios/openblt_chibios.cpp new file mode 100644 index 0000000000..b9a39a58c3 --- /dev/null +++ b/firmware/bootloader/openblt_chibios/openblt_chibios.cpp @@ -0,0 +1,96 @@ +#include "pch.h" + +extern "C" { + #include "boot.h" +} + +void CpuInit() { } +void CopInit() { } + +void TimerInit() { } +void TimerReset() { } + +void NvmInit() { } + +void CopService() { } +void TimerUpdate() { } + +blt_addr NvmGetUserProgBaseAddress() { + return 0x08008000; +} + +blt_bool NvmVerifyChecksum() { + return BLT_TRUE; +} + +/** \brief Pointer to the user program's reset vector. */ +#define CPU_USER_PROGRAM_STARTADDR_PTR ((blt_addr)(NvmGetUserProgBaseAddress() + 0x00000004)) +/** \brief Pointer to the user program's vector table. */ +#define CPU_USER_PROGRAM_VECTABLE_OFFSET ((blt_int32u)NvmGetUserProgBaseAddress()) + +void CpuStartUserProgram(void) +{ + void (*pProgResetHandler)(void); + + /* check if a user program is present by verifying the checksum */ + if (NvmVerifyChecksum() == BLT_FALSE) + { +#if (BOOT_COM_DEFERRED_INIT_ENABLE > 0) && (BOOT_COM_ENABLE > 0) + /* bootloader will stay active so perform deferred initialization to make sure + * the communication interface that were not yet initialized are now initialized. + * this is needed to make sure firmware updates via these communication interfaces + * will be possible. + */ + ComDeferredInit(); +#endif + /* not a valid user program so it cannot be started */ + return; + } +#if (BOOT_CPU_USER_PROGRAM_START_HOOK > 0) + /* invoke callback */ + if (CpuUserProgramStartHook() == BLT_FALSE) + { + #if (BOOT_COM_DEFERRED_INIT_ENABLE > 0) && (BOOT_COM_ENABLE > 0) + /* bootloader will stay active so perform deferred initialization to make sure + * the communication interface that were not yet initialized are now initialized. + * this is needed to make sure firmware updates via these communication interfaces + * will be possible. + */ + ComDeferredInit(); + #endif + /* callback requests the user program to not be started */ + return; + } +#endif +#if (BOOT_COM_ENABLE > 0) + /* release the communication interface */ + ComFree(); +#endif + /* reset the HAL */ + chSysDisable(); + /* reset the timer */ + TimerReset(); + /* remap user program's vector table */ + SCB->VTOR = CPU_USER_PROGRAM_VECTABLE_OFFSET & (blt_int32u)0x1FFFFF80; + /* set the address where the bootloader needs to jump to. this is the address of + * the 2nd entry in the user program's vector table. this address points to the + * user program's reset handler. + */ + pProgResetHandler = (void(*)(void))(*((blt_addr *)CPU_USER_PROGRAM_STARTADDR_PTR)); + /* The Cortex-M4 core has interrupts enabled out of reset. the bootloader + * explicitly disables these for security reasons. Enable them here again, so it does + * not have to be done by the user program. + */ + /* start the user program by activating its reset interrupt service routine */ + pProgResetHandler(); +#if (BOOT_COM_DEFERRED_INIT_ENABLE > 0) && (BOOT_COM_ENABLE > 0) + /* theoretically, the code never gets here because the user program should now be + * running and the previous function call should not return. In case it did return + * for whatever reason, make sure all communication interfaces are initialized so that + * firmware updates can be started. + */ + ComDeferredInit(); +#endif +} /*** end of CpuStartUserProgram ***/ + + diff --git a/firmware/bootloader/openblt_chibios/types.h b/firmware/bootloader/openblt_chibios/types.h new file mode 100644 index 0000000000..d49c592c97 --- /dev/null +++ b/firmware/bootloader/openblt_chibios/types.h @@ -0,0 +1,58 @@ +/************************************************************************************//** +* \file Source/ARMCM4_STM32F4/types.h +* \brief Bootloader types header file. +* \ingroup Target_ARMCM4_STM32F4 +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2013 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or +* modify it under the terms of the GNU General Public License as published by the Free +* Software Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You have received a copy of the GNU General Public License along with OpenBLT. It +* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. +* +* \endinternal +****************************************************************************************/ +#ifndef TYPES_H +#define TYPES_H + + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/** \brief Boolean true value. */ +#define BLT_TRUE (1) +/** \brief Boolean false value. */ +#define BLT_FALSE (0) +/** \brief NULL pointer value. */ +#define BLT_NULL ((void *)0) + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +typedef unsigned char blt_bool; /**< boolean type */ +typedef char blt_char; /**< character type */ +typedef unsigned long blt_addr; /**< memory address type */ +typedef unsigned char blt_int8u; /**< 8-bit unsigned integer */ +typedef signed char blt_int8s; /**< 8-bit signed integer */ +typedef unsigned short blt_int16u; /**< 16-bit unsigned integer */ +typedef signed short blt_int16s; /**< 16-bit signed integer */ +typedef unsigned int blt_int32u; /**< 32-bit unsigned integer */ +typedef signed int blt_int32s; /**< 32-bit signed integer */ + + +#endif /* TYPES_H */ +/*********************************** end of types.h ************************************/ diff --git a/firmware/bootloader/src/Makefile b/firmware/bootloader/src/Makefile index 86955f04ad..d59c86c04a 100644 --- a/firmware/bootloader/src/Makefile +++ b/firmware/bootloader/src/Makefile @@ -181,6 +181,10 @@ CSRC = $(ALLCSRC) \ $(HW_LAYER_DRIVERS_CORE) \ $(PROJECT_DIR)/hw_layer/openblt/shared_params.c \ $(PROJECT_DIR)/hw_layer/main_hardfault.c \ + $(PROJECT_DIR)/ext/openblt/Target/Source/boot.c \ + $(PROJECT_DIR)/ext/openblt/Target/Source/backdoor.c \ + $(PROJECT_DIR)/bootloader/openblt_chibios/nvm.c \ + $(PROJECT_DIR)/hw_layer/openblt/hooks.c \ # C++ sources that can be compiled in ARM or THUMB mode depending on the global # todo: reduce code duplication with primary Makefile!!! @@ -191,6 +195,7 @@ CPPSRC = $(ALLCPPSRC) \ $(PROJECT_DIR)/util/efilib.cpp \ $(PROJECT_DIR)/hw_layer/pin_repository.cpp \ $(RUSEFI_LIB_CPP) \ + $(PROJECT_DIR)/bootloader/openblt_chibios/openblt_chibios.cpp \ src/rusefi_stubs.cpp \ src/main.cpp @@ -258,6 +263,8 @@ INCDIR = $(ALLINC) \ $(RUSEFI_LIB_INC) \ $(BOARDS_DIR) \ $(PROJECT_DIR)/hw_layer/openblt \ + $(PROJECT_DIR)/ext/openblt/Target/Source \ + $(PROJECT_DIR)/bootloader/openblt_chibios \ config BUILDDIR=blbuild diff --git a/firmware/bootloader/src/main.cpp b/firmware/bootloader/src/main.cpp index 0d4a524214..28a80ad291 100644 --- a/firmware/bootloader/src/main.cpp +++ b/firmware/bootloader/src/main.cpp @@ -4,6 +4,7 @@ #include "hardware.h" extern "C" { + #include "boot.h" #include "shared_params.h" } @@ -19,8 +20,11 @@ int main(void) { // Init openblt shared params SharedParamsInit(); + // Init openblt itself + BootInit(); + while (true) { - chThdSleepMilliseconds(1); + BootTask(); } }