89 lines
3.7 KiB
C
89 lines
3.7 KiB
C
/* Flash geometry and jump sequence derived from climate's F407 bootloader.
|
|
* Sector 3 is a durable commit record; sectors 4..7 hold the application.
|
|
* Reset checks vectors like climate; USB END always verifies Flash. */
|
|
#include "boot_port.h"
|
|
#include "boot_image.h"
|
|
#include "stm32f4xx_hal.h"
|
|
#include <string.h>
|
|
#define META 0x0800C000UL
|
|
#define COMMIT 0x53455442UL
|
|
#define ERRORS (FLASH_SR_PGSERR|FLASH_SR_PGPERR|FLASH_SR_PGAERR|FLASH_SR_WRPERR|FLASH_SR_SOP)
|
|
static void unlock(void) {
|
|
if(FLASH->CR & FLASH_CR_LOCK) { FLASH->KEYR=0x45670123; FLASH->KEYR=0xCDEF89AB; }
|
|
FLASH->SR=ERRORS;
|
|
}
|
|
static bool finish(void) {
|
|
while(FLASH->SR & FLASH_SR_BSY) {}
|
|
return !(FLASH->SR & ERRORS);
|
|
}
|
|
static void cache_reset(void) {
|
|
FLASH->ACR &= ~(FLASH_ACR_ICEN|FLASH_ACR_DCEN);
|
|
FLASH->ACR |= FLASH_ACR_ICRST|FLASH_ACR_DCRST;
|
|
FLASH->ACR &= ~(FLASH_ACR_ICRST|FLASH_ACR_DCRST);
|
|
FLASH->ACR |= FLASH_ACR_ICEN|FLASH_ACR_DCEN;
|
|
__DSB(); __ISB();
|
|
}
|
|
static bool erase_sector(unsigned sector) {
|
|
bool ok; unlock();
|
|
FLASH->CR=(FLASH->CR & ~(FLASH_CR_SNB|FLASH_CR_PSIZE)) |
|
|
FLASH_CR_SER | (2UL<<FLASH_CR_PSIZE_Pos) | (sector<<FLASH_CR_SNB_Pos);
|
|
FLASH->CR|=FLASH_CR_STRT; ok=finish();
|
|
FLASH->CR &= ~FLASH_CR_SER; FLASH->CR |= FLASH_CR_LOCK;
|
|
cache_reset(); return ok;
|
|
}
|
|
static bool program(uint32_t address, const uint8_t *p, uint32_t n) {
|
|
bool ok=true; unlock();
|
|
/* Byte programming supports arbitrary SET block boundaries and final tails. */
|
|
FLASH->CR=(FLASH->CR & ~FLASH_CR_PSIZE)|FLASH_CR_PG;
|
|
while(n--) {
|
|
*(volatile uint8_t *)address=*p;
|
|
if(!finish()) { ok=false; break; }
|
|
++address; ++p;
|
|
}
|
|
FLASH->CR &= ~FLASH_CR_PG; FLASH->CR |= FLASH_CR_LOCK;
|
|
cache_reset(); return ok;
|
|
}
|
|
static bool invalidate(void *u) { (void)u; return erase_sector(3); }
|
|
static bool erase(void *u, uint32_t size) {
|
|
unsigned s; (void)u;
|
|
if(size<8 || size>F407_APP_SIZE) return false;
|
|
for(s=4;s<=7;++s) {
|
|
uint32_t start=s==4 ? F407_APP_BASE : 0x08020000UL+(s-5)*0x20000UL;
|
|
if(start>=F407_APP_BASE+size) break;
|
|
if(!erase_sector(s)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
static bool write(void *u,uint32_t off,const uint8_t *p,uint16_t n) {
|
|
(void)u;
|
|
if(!n || off>F407_APP_SIZE || n>F407_APP_SIZE-off) return false;
|
|
return program(F407_APP_BASE+off,p,n) && !memcmp((const void *)(F407_APP_BASE+off),p,n);
|
|
}
|
|
static bool verify(void *u,uint32_t size,uint32_t crc) {
|
|
(void)u;
|
|
return f407_vectors_valid((const uint8_t *)F407_APP_BASE,size) &&
|
|
setp_crc32((const uint8_t *)F407_APP_BASE,size)==crc;
|
|
}
|
|
static bool commit(void *u,uint32_t size,uint32_t crc) {
|
|
uint32_t record[4]={size,crc,~size,COMMIT}; (void)u;
|
|
return program(META,(const uint8_t *)record,sizeof(record)) &&
|
|
!memcmp((const void *)META,record,sizeof(record));
|
|
}
|
|
bool f407_app_valid(void) {
|
|
/* Like climate: direct Keil/SWD writes need no USB completion record. */
|
|
return f407_vectors_valid((const uint8_t *)F407_APP_BASE,F407_APP_SIZE);
|
|
}
|
|
static void activate(void *u) { (void)u; /* main waits for USB response before reset */ }
|
|
const setp_boot_ops f407_boot_ops={invalidate,erase,write,verify,commit,activate};
|
|
__attribute__((naked,noreturn)) static void enter(uint32_t sp,uint32_t pc) {
|
|
__asm volatile("msr msp, r0\nmovs r2, #0\nmsr control, r2\ndsb\nisb\ncpsie i\nbx r1\n");
|
|
}
|
|
void f407_jump_app(void) {
|
|
unsigned i; uint32_t sp=*(const uint32_t *)F407_APP_BASE;
|
|
uint32_t pc=*(const uint32_t *)(F407_APP_BASE+4);
|
|
__disable_irq(); SysTick->CTRL=0;
|
|
for(i=0;i<8;++i) { NVIC->ICER[i]=0xffffffff; NVIC->ICPR[i]=0xffffffff; }
|
|
SCB->ICSR=SCB_ICSR_PENDSTCLR_Msk|SCB_ICSR_PENDSVCLR_Msk;
|
|
SCB->VTOR=F407_APP_BASE; enter(sp,pc);
|
|
}
|