玩过自制DAP工具的一定都知道通过MDK目录的FLM文件,通过工具可以获取一段FLASH的操作算法文件,算法文件由一串HEX字符串组成,但这算法的内容相信大多数的人都没有研究过。由于本人尽来因为服务的客户令人十分糟心,也想搞个刷写器的项目,因此本着好奇的心,研究了了该HEX文本的算法内容,并将汇编反译成了C。
以下记录下过程:
FlashAlgo生成C文件
FlashAlgo压缩文件内有两个FLM文件,一个EXE文件
而FLM文件通过搜索MDK的安装目录大约可以找到90多个,因此对于不同的芯片,如果想要制作不同的DAP的话,通过更换FLM文件即可制作算法文件。
flash_algo生成的C代码
以下以STM32F10X的芯片为例,使用flash_algo生成的C代码如下
/* Flash OS Routines (Automagically Generated)
* Copyright (c) 2009-2015 ARM Limited
*/
#include "flash_blob.h"
/******************************************
* stm32F1系列的下载算法
*其作用就是在下载主程序之前,给目标MCU的SRAM下载一段引导代码
*然后调用这段代码里面的flash读取和擦除函数对目标芯片编程
*不同芯片的下载算法不同,其下载算法可以在MDK的FLM文件中提取
*/
static const uint32_t flash_code[] = {
0xE00ABE00, 0x062D780D, 0x24084068, 0xD3000040, 0x1E644058, 0x1C49D1FA, 0x2A001E52, 0x4770D1F2,
0x4603B510, 0x4C442000, 0x48446020, 0x48446060, 0x46206060, 0xF01069C0, 0xD1080F04, 0x5055F245,
0x60204C40, 0x60602006, 0x70FFF640, 0x200060A0, 0x4601BD10, 0x69004838, 0x0080F040, 0x61104A36,
0x47702000, 0x69004834, 0x0004F040, 0x61084932, 0x69004608, 0x0040F040, 0xE0036108, 0x20AAF64A,
0x60084930, 0x68C0482C, 0x0F01F010, 0x482AD1F6, 0xF0206900, 0x49280004, 0x20006108, 0x46014770,
0x69004825, 0x0002F040, 0x61104A23, 0x61414610, 0xF0406900, 0x61100040, 0xF64AE003, 0x4A2120AA,
0x481D6010, 0xF01068C0, 0xD1F60F01, 0x6900481A, 0x0002F020, 0x61104A18, 0x47702000, 0x4603B510,
0xF0201C48, 0xE0220101, 0x69004813, 0x0001F040, 0x61204C11, 0x80188810, 0x480FBF00, 0xF01068C0,
0xD1FA0F01, 0x6900480C, 0x0001F020, 0x61204C0A, 0x68C04620, 0x0F14F010, 0x4620D006, 0xF04068C0,
0x60E00014, 0xBD102001, 0x1C921C9B, 0x29001E89, 0x2000D1DA, 0x0000E7F7, 0x40022000, 0x45670123,
0xCDEF89AB, 0x40003000, 0x00000000
};
const program_target_t flash_algo = {
0x20000021, // Init
0x20000053, // UnInit
0x20000065, // EraseChip
0x2000009F, // EraseSector
0x200000DD, // ProgramPage
// BKPT : start of blob + 1
// RSB : address to access global/static data
// RSP : stack pointer
{
0x20000001,
0x20000C00,
0x20001000
},
0x20000400, // mem buffer location
0x20000000, // location to write prog_blob in target RAM
sizeof(flash_code), // prog_blob size
flash_code, // address of prog_blob
0x00000400, // ram_to_flash_bytes_to_be_written
};
将其中的flash_code写入到一个TXT文件中,并使用自制的工具将其转换为HEX文件
反汇编的ASM文件
;-------------------------------------------------------------------------------
;---- DISASSEMBLE INFORMATION :
;---- File Name: flash_blob.hex
;---- CPU Family:STM32F10x
;---- CPU Factory:STMicroelectronics
;---- CPU Model: STM32F103C8T6
;---- Time Stamp: 621073228816300
;----
;---- Writen by: beacon_light@163.com
;---- Wechat: 18676693732
;---- QQ: 19263826
;-------------------------------------------------------------------------------
PRESERVE8
THUMB
AREA RESET, DATA, READONLY
DCD 0
__Vectors DCD Reset_Handler
;ALIGN 0X200
; Segment type: Pure code
AREA |.text|, CODE, READONLY
;AREA RAMCODE, CODE, READONLY
; =============== S U B R O U T I N E =======================================
Reset_Handler
;BKPT_20000000
BKPT 0
B loc_2000001A
loc_20000004
LDRB R5, [R1]
LSLS R5, R5, #0x18
EORS R0, R5
MOVS R4, #8
loc_2000000C
LSLS R0, R0, #1
BCC loc_20000012
EORS R0, R3
loc_20000012
SUBS R4, R4, #1
BNE loc_2000000C
ADDS R1, R1, #1
SUBS R2, R2, #1
loc_2000001A
CMP R2, #0
BNE loc_20000004
BX LR
; End of function BKPT_20000000
; =============== S U B R O U T I N E =======================================
Init_20000020
PUSH {R4,LR}
MOV R3, R0
MOVS R0, #0
LDR R4, off_20000138 ; 0x40022000
STR R0, [R4]
LDR R0, dword_2000013C ; 0x45670123
STR R0, [R4,#4]
LDR R0, dword_20000140 ; 0xCDEF89AB
STR R0, [R4,#4]
MOV R0, R4
LDR R0, [R0,#0x1C]
TST.W R0, #4
BNE loc_2000004E
MOVW R0, #0x5555
LDR R4, off_20000144 ; 0x40003000
STR R0, [R4]
MOVS R0, #6
STR R0, [R4,#4]
MOVW R0, #0xFFF
STR R0, [R4,#8]
loc_2000004E
MOVS R0, #0
POP {R4,PC}
; End of function Init_20000020
; =============== S U B R O U T I N E =======================================
UnInit_20000052
MOV R1, R0
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
ORR.W R0, R0, #0x80
LDR R2, off_20000138 ; 0x40022000
STR R0, [R2,#0x10]
MOVS R0, #0
BX LR
; End of function UnInit_20000052
; =============== S U B R O U T I N E =======================================
EraseChip_20000064
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
ORR.W R0, R0, #4
LDR R1, off_20000138 ; 0x40022000
STR R0, [R1,#0x10]
MOV R0, R1
LDR R0, [R0,#0x10]
ORR.W R0, R0, #0x40
STR R0, [R1,#0x10]
B loc_20000084
; ---------------------------------------------------------------------------
loc_2000007C
MOVW R0, #0xAAAA
LDR R1, off_20000144 ; 0x40003000
STR R0, [R1]
loc_20000084
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0xC]
TST.W R0, #1
BNE loc_2000007C
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
BIC.W R0, R0, #4
LDR R1, off_20000138 ; 0x40022000
STR R0, [R1,#0x10]
MOVS R0, #0
BX LR
; End of function EraseChip_20000064
; =============== S U B R O U T I N E =======================================
EraseSector_2000009E
MOV R1, R0
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
ORR.W R0, R0, #2
LDR R2, off_20000138 ; 0x40022000
STR R0, [R2,#0x10]
MOV R0, R2
STR R1, [R0,#0x14]
LDR R0, [R0,#0x10]
ORR.W R0, R0, #0x40
STR R0, [R2,#0x10]
B loc_200000C2
; ---------------------------------------------------------------------------
loc_200000BA
MOVW R0, #0xAAAA
LDR R2, off_20000144 ; 0x40003000
STR R0, [R2]
loc_200000C2
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0xC]
TST.W R0, #1
BNE loc_200000BA
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
BIC.W R0, R0, #2
LDR R2, off_20000138 ; 0x40022000
STR R0, [R2,#0x10]
MOVS R0, #0
BX LR
; End of function EraseSector_2000009E
; =============== S U B R O U T I N E =======================================
ProgramPage_200000DC
PUSH {R4,LR}
MOV R3, R0
ADDS R0, R1, #1
BIC.W R1, R0, #1
B loc_2000012E
; ---------------------------------------------------------------------------
loc_200000E8
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
ORR.W R0, R0, #1
LDR R4, off_20000138 ; 0x40022000
STR R0, [R4,#0x10]
LDRH R0, [R2]
STRH R0, [R3]
NOP
loc_200000FA
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0xC]
TST.W R0, #1
BNE loc_200000FA
LDR R0, off_20000138 ; 0x40022000
LDR R0, [R0,#0x10]
BIC.W R0, R0, #1
LDR R4, off_20000138 ; 0x40022000
STR R0, [R4,#0x10]
MOV R0, R4
LDR R0, [R0,#0xC]
TST.W R0, #0x14
BEQ loc_20000128
MOV R0, R4
LDR R0, [R0,#0xC]
ORR.W R0, R0, #0x14
STR R0, [R4,#0xC]
MOVS R0, #1
locret_20000126
POP {R4,PC}
; ---------------------------------------------------------------------------
loc_20000128
ADDS R3, R3, #2
ADDS R2, R2, #2
SUBS R1, R1, #2
loc_2000012E
CMP R1, #0
BNE loc_200000E8
MOVS R0, #0
B locret_20000126
; End of function ProgramPage_200000DC
; ---------------------------------------------------------------------------
ALIGN 4
off_20000138 DCD 0x40022000
dword_2000013C DCD 0x45670123
dword_20000140 DCD 0xCDEF89AB
off_20000144 DCD 0x40003000
DCD 0
; seg000 ends
END
重构的C代码
#include "stm32f10x_flash.h"
/* Flash Access Control Register bits */
#define ACR_LATENCY_Mask ((uint32_t)0x00000038)
#define ACR_HLFCYA_Mask ((uint32_t)0xFFFFFFF7)
#define ACR_PRFTBE_Mask ((uint32_t)0xFFFFFFEF)
/* Flash Access Control Register bits */
#define ACR_PRFTBS_Mask ((uint32_t)0x00000020)
/* Flash Control Register bits */
#define CR_PG_Set ((uint32_t)0x00000001)
#define CR_PG_Reset ((uint32_t)0x00001FFE)
#define CR_PER_Set ((uint32_t)0x00000002)
#define CR_PER_Reset ((uint32_t)0x00001FFD)
#define CR_MER_Set ((uint32_t)0x00000004)
#define CR_MER_Reset ((uint32_t)0x00001FFB)
#define CR_OPTPG_Set ((uint32_t)0x00000010)
#define CR_OPTPG_Reset ((uint32_t)0x00001FEF)
#define CR_OPTER_Set ((uint32_t)0x00000020)
#define CR_OPTER_Reset ((uint32_t)0x00001FDF)
#define CR_STRT_Set ((uint32_t)0x00000040)
#define CR_LOCK_Set ((uint32_t)0x00000080)
/* FLASH Mask */
#define RDPRT_Mask ((uint32_t)0x00000002)
#define WRP0_Mask ((uint32_t)0x000000FF)
#define WRP1_Mask ((uint32_t)0x0000FF00)
#define WRP2_Mask ((uint32_t)0x00FF0000)
#define WRP3_Mask ((uint32_t)0xFF000000)
#define OB_USER_BFB2 ((uint16_t)0x0008)
/* FLASH Keys */
#define RDP_Key ((uint16_t)0x00A5)
#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
/* FLASH BANK address */
#define FLASH_BANK1_END_ADDRESS ((uint32_t)0x807FFFF)
/* Delay definition */
#define EraseTimeout ((uint32_t)0x000B0000)
#define ProgramTimeout ((uint32_t)0x00002000)
#define BKPT(v) __asm { BKPT v }
void BreakPoint(int r0, char* r1, int len, int r3)
{
int c, temp;
BKPT(0)
for(; len; len--,r1++) {
temp = *r1<<24;
r0 ^= temp;
for(c=8; c; c--) {
temp = r0;
r0 <<= 1;
if(temp&0x80000000) {
r0 ^= r3;
}
}
}
}
int Init()
{
FLASH->ACR = 0; // 0x40022000
FLASH->KEYR = FLASH_KEY1; // 0x45670123, unlock Flash 1/2
FLASH->KEYR = FLASH_KEY2; // 0xCDEF89AB, unlock Flash 2/2
if(FLASH->OBR&4) { // User Option: IWDG_SW(Bit0) is Set
IWDG->KR = 0x5555;
IWDG->PR = 6;
IWDG->RLR = 0xFFF;
}
return 0;
}
int UnInit(void)
{
FLASH->CR |= CR_LOCK_Set;
return 0;
}
int EraseChip(void)
{
FLASH->CR |= CR_MER_Set; // 0x04
FLASH->CR |= CR_STRT_Set; // 0x40
while(FLASH->SR&FLASH_FLAG_BSY) {
IWDG->KR = 0xAAAA;
}
FLASH->CR &= CR_MER_Reset;
return 0;
}
int EraseSector(int sectorNum)
{
FLASH->CR |= CR_PER_Set; // 0x02
FLASH->AR = sectorNum;
FLASH->CR |= CR_STRT_Set; // 0x40
while(FLASH->SR&FLASH_FLAG_BSY) {
IWDG->KR = 0xAAAA;
}
FLASH->CR &= CR_PER_Reset;
return 0;
}
int ProgramPage(char* dst, int size, char* src, int len)
{
// Align 2 bytes
size += 1;
size &= ~1;
for(; size; size-=2) {
FLASH->CR |= CR_PG_Set; // 0x01
*((uint16_t*)dst) = *((uint16_t*)src);
__NOP();
while(FLASH->SR&FLASH_FLAG_BSY);
FLASH->CR &= CR_PG_Reset;
if(FLASH->SR&(FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR)) {
FLASH->SR |= FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR;
return 1;
}
dst += 2;
src += 2;
}
return 0;
}
一个未知问题
由文中可见BreakPoint函数中的操作,联系DAP的上下文,该段代码并没有什么的用途 ,不知具体何用
breakpoint是做为完成函数调用后的返回,里面正常应该是一个死循环,但实际上的操作做了一些数据的运算,实在不知其义
源代码
参考资料
关于STM32Flash详解_stmflash_涂路的博客-CSDN博客
STM32的IWDG(独立看门狗)详细用法_stm32 iwdg_魏波.的博客-CSDN博客
STM32 进阶教程 11 - RAM中运行程序_stm32程序在ram中运行_张十三的博客的博客-CSDN博客