JLINK OB 的bootloader
差不多10年前,minux 写了这个东西让人们用上了便宜的JLINK。他写的程序:
/* filename: stm32boot.c, bootloader for JLink ARM-OB STM32 */
/* To Test: burn ob-stm32-after-update.bin to 0x08000000,
* and then burn stm32boot.bin to 0x08000000.
* Power up, LED0 and LED1 should light up and then off,
* and LED0 on for a moment(during copy_firmware()), and LED0 off, LED1 on to
* indicate finished. LED0 on PE6, LED1 on PE1. */
//#define DEBUG
const char *pId = "$Id: stm32boot.c 21 2009-10-14 12:38:12Z minux $";
typedef volatile unsigned int vu32;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
#define GPIOE_CRL (*((vu32*)(0x40011800)))
#define GPIOE_ODR (*((vu32*)(0x4001180C)))
#define GPIOE_BSRR (*((vu32*)(0x40011810)))
#define GPIOE_BRR (*((vu32*)(0x40011814)))
#define RCC_APB2ENR(*((vu32*)(0x40021018)))
#define FLASH_KEY1 0x45670123
#define FLASH_KEY2 0xcdef89ab
#define FLASH_ACR (*((vu32*)(0x40022000)))
#define FLASH_KEYR (*((vu32*)(0x40022004)))
#define FLASH_OPTKEYR (*((vu32*)(0x40022008)))/* patch this to FLASH_KEYR */
#define FLASH_SR (*((vu32*)(0x4002200c)))
#define FLASH_CR (*((vu32*)(0x40022010)))
#define FLASH_AR (*((vu32*)(0x40022014)))
#define SCB_BASE (0xe000ed00)
#define SCB_VTOR (*((vu32*)(SCB_BASE + 0x08)))
#define LED0 (1 << 6)
#define LED1 (1 << 1)
#ifdef DEBUG
# define LED_ON(led) (GPIOE_BRR = led)
# define LED_OFF(led) (GPIOE_BSRR = led)
# define LED_TOGGLE(led) (GPIOE_ODR ^= led)
#else
# define LED_ON(led)
# define LED_OFF(led)
# define LED_TOGGLE(led)
#endif
#ifndef STACK_SIZE
#define STACK_SIZE 1024
#endif
void ResetISR(void);
void NMIException(void);
void HardFaultException(void);
void delay(void);
typedef void (* pfnISR)(void); // Pointer to exception handle function
// mthomas: added section -> alignment thru linker-script
__attribute__ ((section(".stackarea")))
static unsigned long pulStack;
__attribute__ ((section(".isr_vector")))
pfnISR VectorTable[] =
{
(pfnISR)((unsigned long)pulStack + sizeof(pulStack)), // The initial stack pointer
ResetISR, // The reset handler
NMIException,
HardFaultException
};
void delay(void)
{
unsigned int i;
for( i = 0; i < 0x3ffff; ++i)
asm("nop");
}
// The following are constructs created by the linker, indicating where the
// the "data" and "bss" segments reside in memory.The initializers for the
// for the "data" segment resides immediately following the "text" segment.
extern unsigned long _etext;
extern unsigned long _data;
extern unsigned long _edata;
extern unsigned long _bss;
extern unsigned long _ebss;
int main(void);
void ResetISR(void) {
unsigned long *pulSrc, *pulDest;
// Copy the data segment initializers from flash to SRAM.
pulSrc = &_etext;
for(pulDest = &_data; pulDest < &_edata; ) *pulDest++ = *pulSrc++;
// Zero fill the bss segment.
for(pulDest = &_bss; pulDest < &_ebss; ) *pulDest++ = 0;
main();
}
void NMIException(void) { return; }
void HardFaultException(void) { return; }
void init(void)
{
#ifndef DEBUG
return;
#endif
RCC_APB2ENR |= (1<<6); // enable GPIOE
GPIOE_CRL = 0x03000030; // PE6, PE1 output push-pull
//GPIOE_CRL |= 0x33330000;
LED_ON(LED0);
LED_ON(LED1);
delay();
LED_OFF(LED0);
LED_OFF(LED1);
/* int i;
for (i = 0; i < 1; i++) {
LED_TOGGLE(LED0);
delay();
}
LED_OFF(LED0);
*/
}
// stm32 bootloader for ob-stm32
#define FIRMWARE_SIZE 0x5C00
#define FIRMWARE_BASE 0x4000
#define FROM (0x08000000+FIRMWARE_BASE+FIRMWARE_SIZE)
#define TO (0x08000000+FIRMWARE_BASE)
#define PAGE_SIZE 1024
unsigned short CalcCrc(unsigned char *R4, int count) // huge thanks to DASM!
{
unsigned R0 = 0, R3, R5, i;
R3 = 0x8408;
for (;count != 0; count--)
{
R5 = R0;
R0 = *R4;
R4++;
R0 ^= R5;
for (i = 8; i !=0; i--)
{
int last = R0;
R0 >>= 1;
if (last & 1)
R0 ^= R3;
}
}
return R0;
}
void flash_unlock(void) { // unlock the flash program erase controller
FLASH_KEYR = FLASH_KEY1;
FLASH_KEYR = FLASH_KEY2;
}
void flash_wait(void) {
while (FLASH_SR & 0x1/*FLASH_FLAG_BSY*/)
;
FLASH_SR = 0x35;
}
void flash_erase_page(uint32_t addr) {
//LED_TOGGLE(LED1);
FLASH_CR |= 0x02;
FLASH_AR = addr;
FLASH_CR |= 0x40;
flash_wait();
FLASH_CR &= ~0x02;
}
static inline int flash_write_halfword(uint32_t addr, uint16_t word) {
flash_wait();
FLASH_CR |= 0x01;
*((volatile uint16_t *)addr) = word;
flash_wait();
FLASH_CR &= ~0x01;
return *((volatile uint16_t *)addr) == word;
}
static inline int flash_write_word(uint32_t addr, uint32_t word) {
flash_wait();
FLASH_CR |= 0x01;
asm volatile ("nop");
*((volatile uint16_t *)addr) = word & 0xffff;
flash_wait();
*((volatile uint16_t *) (addr + 2)) = word >> 16;
flash_wait();
FLASH_CR &= ~0x01;
return *((volatile uint32_t *)addr) == word;
}
void copy_firmware(void) {
uint32_t addr, waddr, data;
for (addr = TO; addr < TO + FIRMWARE_SIZE; addr += PAGE_SIZE) {
int i;
data = ~0;
for (i = 0; i < PAGE_SIZE; i += 4) {
data &= *((uint32_t *)(addr + i));
if (data != (uint32_t)~0) { // need erase
//LED_ON(LED1); delay();
flash_erase_page(addr);
break;
}
}
}
for (addr = FROM, waddr = TO; addr < FROM + FIRMWARE_SIZE; ) {
//if (addr & 0x1FF == 0x100) LED_TOGGLE(LED1);
data = *((uint32_t *)addr);
if (data == (uint32_t)&FLASH_OPTKEYR)
data = (uint32_t)&FLASH_KEYR; // patch firmware
flash_write_word(waddr, data);
addr += 4;
waddr += 4;
}
}
void mark_firmware_invalid(void) {
flash_erase_page(FROM);
}
unsigned char IsValideFirmware(void) {
unsigned int *i = (unsigned int *)FROM;
int cnt = 0;
unsigned int result = 0xFFFFFFFF;
for (cnt = 0; cnt < 32; cnt++)
result &= (*i++);
if (result == 0xFFFFFFFF)
return 0;
unsigned short crc = CalcCrc((unsigned char *) FROM, FIRMWARE_SIZE - 2);
if (*(unsigned short*)(FROM + FIRMWARE_SIZE- 2) != crc)
return 0;
return 1;
}
int main() {
init(); // flash LED to indicate we started!
if (IsValideFirmware())
{
flash_unlock();
LED_ON(LED0);
copy_firmware();
LED_OFF(LED0);
mark_firmware_invalid();
LED_ON(LED1);
}
FLASH_CR |= (1 << 7); // lock the FPEC
// relocate vector table
SCB_VTOR = TO;
asm volatile ("ISB");
asm volatile ("movw r3, #:lower16:134234112"); // FROM == 134234112
asm volatile ("movt r3, #:upper16:134234112");
asm volatile ("ldr r6, ");
asm volatile ("msr msp, r6"); // load new stack pointer
asm volatile ("ldr r6, ");
asm volatile ("bx r6"); // direct branch to new reset routine
return 0;
}
OB不会更新了,这个也没用了。
自己也写个玩玩,参考他的自己写了个,他这个792字节,我这个348字节。
也能从JLINK驱动更新
.thumb
.syntax unified
.section .data
.equ STACKINIT, 0x20005000
yjmwxwx: .ascii "jlink ob boot 2017-11-19 yjmwxwx"
.section .text
_xiangliangbiao:
.word STACKINIT
.word _start + 1
.word _nmi_handler + 1
.word _hard_fault+ 1
.word _memory_fault + 1
.word _bus_fault + 1
.word _usage_fault + 1
_start:
cpsid i
sub sp, sp, # 0x5000
ldr r0, = yjmwxwx
str r0,
add sp, sp, # 0x5000
ldr r0, = 0xffffffff
ldr r1, = 0x8009c00
ldr r1,
cmp r1, r0
bne _crcjisuan
_daogujian:
ldr r0, = 0xe000ed08
ldr r1, = 0x8004000
str r1,
add r1, r1, # 4
ldr r1,
cpsie i
bx r1
_crcjisuan:
ldr r0, = 0x8009c00
ldr r1, = 0x5bfe
mov r6, # 0
movw r4, # 0x8408
_crcxunhuan:
ldrb r5, , # 1
eor r6, r6, r5
mov r2, # 8
_crcxunhuan1:
mov r5, r6
lsrs r6, r6, # 1
tst r5, # 1
it ne
eorne r6, r6, r4
subs r2, r2, # 1
bne _crcxunhuan1
subs r1, r1, # 1
bne _crcxunhuan
ldr r0, = 0x800f7fe
ldr r1,
cmp r6, r1
bne _daogujian
@ flsh解锁
ldr r0, = 0x40022000
ldr r1, = 0x45670123
str r1,
ldr r1, = 0xcdef89ab
str r1,
@擦除23页
mov r5, # 23
ldr r4, = 0x8004000
movw r8, # 0x400
_flashmang:
ldr r2,
lsls r2, r2, # 31
bmi _flashmang
mov r1, # 2
str r1,
str r4,
mov r1, # 0x42
str r1,
add r4, r4, r8
subs r5, # 1
bne _flashmang
@写FLASH
ldr r8, = 0x8004000
ldr r4, = 0x8009c00
mov r5, # 0
movw r6, # 0x1700
_flashmang1:
ldr r2,
lsls r2, r2, # 31
bmi _flashmang1
mov r1, # 1
str r1,
ldrh r3,
strh r3,
add r5, r5, # 2
_flashmang2:
ldr r2,
lsls r2, r2, # 31
bmi _flashmang2
ldrh r3,
strh r3,
add r5, r5, # 2
subs r6, r6, # 1
bne _flashmang1
_flashmang3:
ldr r2,
lsls r2, r2, # 31
bmi _flashmang3
mov r1, # 2
str r1,
ldr r3, = 0x8009c00 @ 擦去更新的一页
str r3,
mov r1, # 0x42
str r1,
_flashmang4:
ldr r2,
lsls r2, r2, # 31
bmi _flashmang4
mov r1, # 0x80
str r1, @flsh上锁
ldr r0, = 0xe000ed0c
ldr r1, = 0x05fa0004
str r1, @复位
_nmi_handler:
bx lr
_hard_fault:
bx lr
_memory_fault:
bx lr
_bus_fault:
bx lr
_usage_fault:
bx lr
20多年前学过操作系统,现在完全看不懂了:'( 你的是汇编啊,肯定小 la45088d1 发表于 2017-11-20 18:48
不止这么一点代码吧?J-link要与PC通信,需要USB从机协议,与其它的ARM控制器通信需要JTAG协议。你这点代码 ...
那些东西在官方固件里,这个代码也就是计算CRC和烧写FLASH,没别的功能,就是跳转到官方固件的一个跳板,有更新的时候就把更新的烧写到FLASH。 la45088d1 发表于 2017-11-20 19:09
LZ下次长点记性,不要再写这样的指令了:
改成这样:
CPSID I
有什么区别呢? la45088d1 发表于 2017-11-20 21:51
请LZ注重细节,LZ的汇编之路开始的比我早吧?写了那么久,不是嘲讽,真的要提高了。不然,被一些人看到,又 ...
谢谢提醒,以前还真不知道这些细节。话说我一开始写汇编到现在也没什么提高,只要从我手里出来的东西都会变的杂乱,细节什么的更是不懂了,以后努力学学吧,不知道能不能学会。 其实我用在汇编的上的时间是非常少的,别看我时间很多,大多数时间都在玩,真正用来自学的时间十分之一也没有。 他们笑话我那是很正常的,人家都是专业培养出来的人才,而我全部都是自学的。比如前几个月想写个傅里叶变换的程序,但是看了几天搞不懂,不知道用小学文化怎么理解这个东西,就算是小学我也是班里倒数前5名那种,笑话我就像官员笑话农民工没钱一样。 la45088d1 发表于 2017-11-20 21:35
LZ肯定没有好好看我之前发的文章,说实话,这个问题搞不明白,真的没必要再执着于汇编了,连C编译器再 ...
谢谢你提供的资料,长篇大论看不懂,没想到代码位置不同差别这么大, 做了个简单测试,设置SYSTICK定时器重载值0XFFFFFF,中断后跳出这个死循环。 第一个R1结果0XF0F0F ,第二个R1结果0XD7943
d1:
sub sp, sp, # 0x5000
ldr r0, = yjmwxwx
str r0,
add sp, sp, # 0x5000
add r1, r1, # 1
b d1
d1:
ldr r0, = yjmwxwx
sub sp, sp, # 0x5000
str r0,
add sp, sp, # 0x5000
add r1, r1, # 1
b d1
页:
[1]