yjmwxwx 发表于 2017-11-20 02:49:24

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



ybzqw003 发表于 2017-11-20 09:35:32

20多年前学过操作系统,现在完全看不懂了:'(

zystbbs 发表于 2017-11-20 12:49:25

你的是汇编啊,肯定小

yjmwxwx 发表于 2017-11-20 19:05:48

la45088d1 发表于 2017-11-20 18:48
不止这么一点代码吧?J-link要与PC通信,需要USB从机协议,与其它的ARM控制器通信需要JTAG协议。你这点代码 ...

那些东西在官方固件里,这个代码也就是计算CRC和烧写FLASH,没别的功能,就是跳转到官方固件的一个跳板,有更新的时候就把更新的烧写到FLASH。

yjmwxwx 发表于 2017-11-20 19:15:08

la45088d1 发表于 2017-11-20 19:09
LZ下次长点记性,不要再写这样的指令了:
改成这样:
CPSID I


有什么区别呢?

yjmwxwx 发表于 2017-11-20 22:58:22

la45088d1 发表于 2017-11-20 21:51
请LZ注重细节,LZ的汇编之路开始的比我早吧?写了那么久,不是嘲讽,真的要提高了。不然,被一些人看到,又 ...

谢谢提醒,以前还真不知道这些细节。话说我一开始写汇编到现在也没什么提高,只要从我手里出来的东西都会变的杂乱,细节什么的更是不懂了,以后努力学学吧,不知道能不能学会。 其实我用在汇编的上的时间是非常少的,别看我时间很多,大多数时间都在玩,真正用来自学的时间十分之一也没有。 他们笑话我那是很正常的,人家都是专业培养出来的人才,而我全部都是自学的。比如前几个月想写个傅里叶变换的程序,但是看了几天搞不懂,不知道用小学文化怎么理解这个东西,就算是小学我也是班里倒数前5名那种,笑话我就像官员笑话农民工没钱一样。

yjmwxwx 发表于 2017-11-21 00:52:54

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]
查看完整版本: JLINK OB 的bootloader