/* * Recovered C-like source from STM32_FlashLoader.axf. * * Source hints came from DWARF symbols in the AXF: * C:\Documents and Settings\junseok\...\STM32\A1000_Flash_loader\main.c * RVCT3.0 [Build 441], Cortex-M3 Thumb code, loaded at 0x20000000. * * This is not the original source. It is a readable reconstruction of the * business logic and the flash routines visible in the disassembly. */ #include typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef volatile uint32_t vu32; typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG = 2, FLASH_ERROR_WRP = 3, FLASH_COMPLETE = 4, FLASH_TIMEOUT = 5 } FLASH_Status; typedef enum { FAILED = 0, PASSED = 1 } TestStatus; typedef enum { ERROR = 0, SUCCESS = 1 } ErrorStatus; typedef enum { RESET = 0, SET = 1 } FlagStatus; typedef enum { DISABLE = 0, ENABLE = 1 } FunctionalState; typedef struct { u32 Command; /* +0x00 */ u32 Result; /* +0x04 */ u32 Reserved1[4]; /* +0x08 */ u32 Reserved2; /* +0x18 */ u32 TargetAddr; /* +0x1c */ u32 Length; /* +0x20 */ u32 Reserved3; /* +0x24 */ u32 Reserved4; /* +0x28 */ u32 Reserved5; /* +0x2c */ u32 Reserved6; /* +0x30 */ u32 Reserved7; /* +0x34 */ u32 Reserved8; /* +0x38 */ u8 Buf[8192]; /* +0x3c */ } FLASH_INFO; #define ERASE_COUNTER_ADDR 0x20000cd8u #define NBR_OF_PAGE_ADDR 0x20000cdcu #define FLASH_STATUS_ADDR 0x20000ce0u #define MEM_STATUS_ADDR 0x20000ce1u #define HSE_STATUS_ADDR 0x20000ce2u #define FLASH_INFO_ADDR 0x20000ce4u #define FLASH_BASE 0x08000000u #define FLASH_PAGE_SIZE 0x400u #define FLASH_PAGE_COUNT 0x80u #define FLASH_TIMEOUT_LONG 0x0fffu #define FLASH_TIMEOUT_PROG 0x000fu #define FLASH_ACR (*(volatile u32 *)0x40022000u) #define FLASH_KEYR (*(volatile u32 *)0x40022004u) #define FLASH_SR (*(volatile u32 *)0x4002200cu) #define FLASH_CR (*(volatile u32 *)0x40022010u) #define FLASH_AR (*(volatile u32 *)0x40022014u) #define FLASH_OBR (*(volatile u32 *)0x4002201cu) #define FLASH_KEY1 0x45670123u #define FLASH_KEY2 0xcdef89abu #define EraseCounter (*(volatile u32 *)ERASE_COUNTER_ADDR) #define NbrOfPage (*(volatile u32 *)NBR_OF_PAGE_ADDR) #define FLASHStatus (*(volatile FLASH_Status *)FLASH_STATUS_ADDR) #define MemoryProgramStatus (*(volatile TestStatus *)MEM_STATUS_ADDR) #define HSEStartUpStatus (*(volatile ErrorStatus *)HSE_STATUS_ADDR) #define Flash_Info (*(volatile FLASH_INFO *)FLASH_INFO_ADDR) void RCC_DeInit(void); void RCC_HSEConfig(u32 RCC_HSE); ErrorStatus RCC_WaitForHSEStartUp(void); void RCC_HCLKConfig(u32 RCC_SYSCLK); void RCC_PCLK1Config(u32 RCC_HCLK); void RCC_PCLK2Config(u32 RCC_HCLK); void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul); void RCC_PLLCmd(FunctionalState NewState); FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG); void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource); u8 RCC_GetSYSCLKSource(void); void NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset); void FLASH_SetLatency(u32 FLASH_Latency); void FLASH_PrefetchBufferCmd(u32 FLASH_PrefetchBuffer); void delay(void) { u32 i = 0x0fff; while (i != 0) { i--; } } FLASH_Status FLASH_GetStatus(void) { if ((FLASH_SR & 0x01u) == 0x01u) { return FLASH_BUSY; } if ((FLASH_SR & 0x04u) != 0) { return FLASH_ERROR_PG; } if ((FLASH_SR & 0x10u) != 0) { return FLASH_ERROR_WRP; } return FLASH_COMPLETE; } FLASH_Status FLASH_WaitForLastOperation(u32 timeout) { FLASH_Status status = FLASH_GetStatus(); while (status == FLASH_BUSY && timeout != 0) { delay(); status = FLASH_GetStatus(); timeout--; } if (timeout == 0) { status = FLASH_TIMEOUT; } return status; } void FLASH_Unlock(void) { FLASH_KEYR = FLASH_KEY1; FLASH_KEYR = FLASH_KEY2; } void FLASH_Lock(void) { FLASH_CR |= 0x80u; } void FLASH_ClearFlag(u32 flags) { FLASH_SR = flags; } FLASH_Status FLASH_ErasePage(u32 pageAddress) { FLASH_Status status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_LONG); if (status == FLASH_COMPLETE) { FLASH_CR |= 0x02u; /* PER */ FLASH_AR = pageAddress; FLASH_CR |= 0x40u; /* STRT */ status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_LONG); if (status != FLASH_BUSY) { FLASH_CR &= 0x00001ffdu; /* clear PER */ } } return status; } FLASH_Status FLASH_EraseAllPages(void) { FLASH_Status status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_LONG); if (status == FLASH_COMPLETE) { FLASH_CR |= 0x04u; /* MER */ FLASH_CR |= 0x40u; /* STRT */ status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_LONG); if (status != FLASH_BUSY) { FLASH_CR &= 0x00001ffbu; /* clear MER */ } } return status; } FLASH_Status FLASH_ProgramHalfWord(u32 targetP, u16 *srcP) { FLASH_Status status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_PROG); if (status == FLASH_COMPLETE) { FLASH_CR |= 0x01u; /* PG */ *(volatile u16 *)targetP = *srcP; status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_PROG); if (status != FLASH_BUSY) { FLASH_CR &= 0x00001ffeu; /* clear PG */ } } return status; } FlagStatus FLASH_GetReadOutProtectionStatus(void) { return (FLASH_OBR & 0x02u) ? SET : RESET; } FlagStatus FLASH_GetFlagStatus(u32 flag) { return ((FLASH_SR & flag) == flag) ? SET : RESET; } void ReadChipID(void) { Flash_Info.Result = 1; } void EraseSector(void) { int i; Flash_Info.Result = 0; for (i = 0; i < (int)(NbrOfPage - 1); i++) { u32 nextPage = FLASH_BASE + ((u32)(i + 1) * FLASH_PAGE_SIZE); if (nextPage > Flash_Info.TargetAddr) { break; } } while ((u32)i < (NbrOfPage - 1) && FLASHStatus == FLASH_COMPLETE) { u32 endAddr = Flash_Info.TargetAddr + Flash_Info.Length; u32 pageAddr = FLASH_BASE + ((u32)i * FLASH_PAGE_SIZE); if (endAddr <= pageAddr) { break; } FLASHStatus = FLASH_ErasePage(pageAddr); if (FLASHStatus == 0) { return; } i++; } Flash_Info.Result = 1; } void EraseAll(void) { EraseCounter = 0; while (EraseCounter < NbrOfPage && FLASHStatus == FLASH_COMPLETE) { FLASHStatus = FLASH_ErasePage(FLASH_BASE + (EraseCounter * FLASH_PAGE_SIZE)); EraseCounter++; } Flash_Info.Result = 1; } void Program(void) { u32 targetP = Flash_Info.TargetAddr; u16 *srcP = (u16 *)Flash_Info.Buf; u32 i = 0; while (i < Flash_Info.Length) { FLASHStatus = FLASH_ProgramHalfWord(targetP, srcP); i += 2; targetP += 2; srcP++; } Flash_Info.Result = 1; } void NVIC_Configuration(void) { NVIC_SetVectorTable(FLASH_BASE, 0); } void RCC_Configuration(void) { RCC_DeInit(); RCC_HSEConfig(0x00010000u); HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (HSEStartUpStatus == SUCCESS) { RCC_HCLKConfig(0); RCC_PCLK2Config(0); RCC_PCLK1Config(0x400u); FLASH_SetLatency(2); FLASH_PrefetchBufferCmd(0x10); RCC_PLLConfig(0x00010000u, 0x001c0000u); RCC_PLLCmd(ENABLE); while (RCC_GetFlagStatus(0x39) == RESET) { } RCC_SYSCLKConfig(2); while (RCC_GetSYSCLKSource() != 0x08) { } } } void Flash_Init(void) { FLASHStatus = FLASH_COMPLETE; MemoryProgramStatus = PASSED; RCC_Configuration(); NVIC_Configuration(); FLASH_Unlock(); NbrOfPage = FLASH_PAGE_COUNT; FLASH_ClearFlag(0x35); } void Main(void) { Flash_Init(); switch (Flash_Info.Command) { case 0: Program(); break; case 1: EraseAll(); break; case 2: EraseSector(); break; case 3: ReadChipID(); break; default: Flash_Info.Result = 0; break; } } int BlankCheck(unsigned long targetAddr, unsigned long targetSize) { volatile unsigned long *targetP = (volatile unsigned long *)targetAddr; unsigned long i = 0; while (i < targetSize) { if (*targetP++ != 0xffffffffu) { return 0; } i += 4; } return 1; } int Verification(unsigned long targetAddr, unsigned long limit, unsigned long srcAddr) { volatile unsigned long *targetP = (volatile unsigned long *)targetAddr; volatile unsigned long *sourceP = (volatile unsigned long *)srcAddr; int i = 0; while ((unsigned long)i < limit) { if (*targetP++ != *sourceP++) { return 0; } i += 4; } return 1; }