Add a production-ready, educational bootloader extension for STM32 MCUs. Core features: - Custom binary protocol with CRC16/CRC32 verification - AES-256 encryption for firmware security - Dual-bank firmware management with rollback support - Version management and firmware validation - Modular architecture with BSP abstraction layer Project structure: - include/: Header files (bootloader.h, bsp_flash.h, bsp_uart.h) - src/: Core implementation (bootloader, protocol, crypto, firmware manager) - port/: MCU-specific adaptation layer (STM32F4xx) - docs/: Documentation (integration guide, porting guide) Supported platforms: - STM32F4xx (primary) - STM32F1xx (via porting) Quick start: 1. Copy extension module to project 2. Configure bootloader_config.h 3. Modify linker script for APP_BASE_ADDR 4. Build and flash bootloader to 0x08000000 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
2.9 KiB
C
91 lines
2.9 KiB
C
#include "stm32f407xx.h"
|
|
#include "stm32f4xx_hal_flash.h"
|
|
#include "stm32f4xx_hal_flash_ex.h"
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
static uint32_t flash_get_sector(uint32_t address) {
|
|
address -= FLASH_BASE;
|
|
if (address < 0x4000) return FLASH_SECTOR_0;
|
|
else if (address < 0x8000) return FLASH_SECTOR_1;
|
|
else if (address < 0xC000) return FLASH_SECTOR_2;
|
|
else if (address < 0x10000) return FLASH_SECTOR_3;
|
|
else if (address < 0x20000) return FLASH_SECTOR_4;
|
|
else if (address < 0x40000) return FLASH_SECTOR_5;
|
|
else if (address < 0x60000) return FLASH_SECTOR_6;
|
|
else if (address < 0x80000) return FLASH_SECTOR_7;
|
|
else if (address < 0xA0000) return FLASH_SECTOR_8;
|
|
else if (address < 0xC0000) return FLASH_SECTOR_9;
|
|
else if (address < 0xE0000) return FLASH_SECTOR_10;
|
|
else return FLASH_SECTOR_11;
|
|
}
|
|
|
|
int flash_port_erase(uint32_t address, uint32_t length) {
|
|
HAL_FLASH_Unlock();
|
|
uint32_t start_sector = flash_get_sector(address);
|
|
uint32_t end_sector = flash_get_sector(address + length - 1);
|
|
|
|
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
|
|
FLASH_EraseInitTypeDef erase;
|
|
erase.TypeErase = FLASH_TYPEERASE_SECTORS;
|
|
erase.Sector = start_sector;
|
|
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
|
|
erase.NbSectors = end_sector - start_sector + 1;
|
|
uint32_t sector_error = 0;
|
|
if (HAL_FLASHEx_Erase(&erase, §or_error) != HAL_OK) {
|
|
HAL_FLASH_Lock();
|
|
return -1;
|
|
}
|
|
HAL_FLASH_Lock();
|
|
return 0;
|
|
}
|
|
|
|
int flash_port_write(uint32_t address, const uint8_t *data, uint32_t length) {
|
|
HAL_FLASH_Unlock();
|
|
uint32_t written = 0;
|
|
while (written < length) {
|
|
|
|
uint32_t chunk_data;
|
|
if (length - written >= 4) {
|
|
chunk_data = *(uint32_t *)(data + written);
|
|
} else {
|
|
word_data = 0xFFFFFFFF;
|
|
for (uint32_t i = 0; i < length - written; i++) {
|
|
((uint8_t *)&chunk_data)[i] = data[written + i];
|
|
}
|
|
}
|
|
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address + written, chunk_data) != HAL_OK) {
|
|
HAL_FLASH_Lock();
|
|
return -1;
|
|
}
|
|
written += 4;
|
|
}
|
|
HAL_FLASH_Lock();
|
|
return 0;
|
|
}
|
|
|
|
int flash_port_read(uint32_t address, uint8_t *buffer, uint32_t length) {
|
|
memcpy(buffer, (const void *)address, length);
|
|
return 0;
|
|
}
|
|
|
|
bool flash_port_verify(uint32_t address, const uint8_t *data, uint32_t length) {
|
|
uint8_t read_data[length];
|
|
flash_port_read(address, read_data, length);
|
|
return memcmp(read_data, data, length) == 0;
|
|
}
|
|
|
|
int flash_port_init(void) {
|
|
return 0;
|
|
}
|
|
|
|
static const bsp_flash_ops_t flash_ops = {
|
|
.init = flash_port_init,
|
|
.erase = flash_port_erase,
|
|
.write = flash_port_write,
|
|
.read = flash_port_read,
|
|
.verify = flash_port_verify,
|
|
};
|
|
|
|
void flash_port_register(void) {
|
|
bsp_flash_register(&flash_ops);
|
|
} |