打印
[ZLG-ARM]

写bootloader是遇到的问题,不解?

[复制链接]
1843|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
junovour|  楼主 | 2007-4-5 11:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1 假如我把写好的程序下载到smartarm开发板的flash中,使用ldr取一个标号,比如reset,那么,取得的地址是0x80000000,还是0x00000000呢?
2 假如我写的是bootloader程序,开发板使用flash启动,那中断向量表是不是一定要放到flash中,或者使用跳转指令跳转到ram中,并且要事先把代码转移到ram中呢?我是否可以这样理解。
3 如果可以发生中断时,中断向量表从RAM取值,我该具体怎么做呢?冲映射吗?把RAM映射到0x0位置?具体怎么操作呢?
我是新手,很多问题不太明白,希望好心人能解答,谢谢~

相关帖子

沙发
zlgARM| | 2007-4-5 21:47 | 只看该作者

junovour

   如果一定要弄懂这些问题,那么请自行研究一下startup.s文件,以及存储器映射的概念。

使用特权

评论回复
板凳
VisionShow| | 2007-4-6 00:03 | 只看该作者

回复

1. 是0x80000000, 只是CPU根据MEMMAP把访问地址改变了(只是头64字节)
2. 不是,可以事先把代码拷贝到RAM中
3. MEMMAP=2,此时从RAM中取中断向量
下面是一个LPC2220的启动程序:
@这个文件是LPC2220的外部启动程序
.text
.align 4
.global _start
.global Reboot

_start:
  B      SystemReset
  B      SystemReset
  B      SystemReset
  B      SystemReset
  LDR    PC, DataAbort            @这个地方很奇怪,非这样一条语句才能启动
  .long  0xA3400FF2
  LDR    PC,  [PC, #-0xFF0]       @这个方式也是比较奇怪的,如果用B IRQ此类的语句是不能执行的(下面有例子)
  B      SystemReset

/*
IRQ:
  STMDB   SP!, {R0-R12, LR}   
  MRS     R0,  CPSR               @获取当前CPU状态
  STMDB   SP!, {R0}               @保存当前CPU状态
  BL      IRQ_Handler
  LDMIA   SP!, {R0}               @读回CPU状态
  MSR     CPSR, R0                @恢复CPU状态
  LDMIA   SP!, {R0-R12, LR}
  SUBS    PC,  LR, #4
*/

DataAbort:
.long    0x80000024                @这个地方也很奇怪,非指向0x80000000才行,也就是必须指向FLASH

SystemReset:
  LDR    R0,     =0xFFFFF014       @关闭所有中断
  LDR    R1,     =0xFFFFFFFF
  STR    R1,     [R0]

  LDR    R0,     =0xE0000000       @映射为Flash启动
  MOV    R1,     #0
  STR    R1,     [R0]

  LDR    R0,     =0xE002C014
  LDR    R1,     =0x0F814920
  STR    R1,     [R0]

  LDR    R0,     =0xFFE00000
  LDR    R1,     =0x1000FFEF
  STR    R1,     [R0]

  LDR    R0,     =0xFFE00004
  LDR    R1,     =0x2000FFEF
  STR    R1,     [R0]

  LDR    R0,     =0xFFE00008
  LDR    R1,     =0x0000FFEF
  STR    R1,     [R0]

  LDR    R0,     =0xFFE0000C
  LDR    R1,     =0x00002400
  STR    R1,     [R0]

  MSR    CPSR_c, #0xD2
  LDR    SP,     =0x40010000

  MSR    CPSR_c, #0xD3
  LDR    SP,     =0x4000E000

  LDR    R0,     =0x80000000
  MOV    R1,     #0x40000000
  MOV    R2,     #0xC000
CopyProgram:                        @把程序拷贝到RAM中运行
  LDR    R3,     [R0], #4
  STR    R3,     [R1], #4
  SUBS   R2,     R2,   #4
  BNE    CopyProgram

  LDR    R0,     =0xE01FC040
  MOV    R1,     #2
  STRB   R1,     [R0]
  
  MRS    R1,     CPSR
  BIC    R1,     R1, #0x80
  MSR    CPSR,   R1

  LDR    R0,     DataAbort
  LDR    R1,     =SystemReset
  STR    R1,     [R0]

  LDR    PC,     =Startup

Reboot:
  LDR    PC,     =0x80000000

使用特权

评论回复
地板
high| | 2007-4-6 09:55 | 只看该作者

鼓励一下楼主,我觉得您问的问题很好。

我也困惑很久

我的理解:

1,地址问题

   这也是为什么要用户指定ro_base的原因。所有地址是这个基地址偏移。所以,这个值是您自己定的。
   进阶内容:如果是一个多任务的并有文件系统,每个程序由os来自动加载,--旧象windows做到的那样。我们怎么办?编译器提供了这么个功能:

    ROPI - 位置无关 read only position independece?
   (我从手册获知,并没有应用经验)

2,如果问vector所在位置。在支持remap的系统里面,事实上,vector是可以任意安排所在,只要它是地址0,或者remap后的地址0。

使用特权

评论回复
5
junovour|  楼主 | 2007-4-6 12:55 | 只看该作者

感谢大家解答,还有几点不太明白

通过大家的讲解,我也稍微明白了一些。
看U-Boot中start.S,还有几处不太明白,可能还是没有理解好吧……
#include <config.h>
#include <version.h>

#define PINSEL0 0xe002c000
#define PINSEL2    0xe002c014
#define BCFG0    0xffe00000
#define BCFG1   0xffe00004
#define MEMMAP    0xe01fc040
#define PLLCON    0xe01fc080
#define PLLCFG    0xe01fc084
#define PLLSTAT 0xe01fc088
#define PLLFEED 0xe01fc08c
#define VPBDIV  0xe01fc100
#define RAM_SIZE  0x20000 + 1024 * 128
#define RAM_BASE 0x81000000
.globl _start
_start:
    ldr    pc,reset
    add    pc,pc,#0x01000000                               疑问1
    add    pc,pc,#0x01000000                               
    add    pc,pc,#0x01000000                               
    add    pc,pc,#0x01000000                               
    add    pc,pc,#0x01000000                               
    add    pc,pc,#0x01000000                               
    add    pc,pc,#0x01000000                               

    .balignl    16,0xdeadbeef


_TEXT_BASE:
    .word    TEXT_BASE

.globl    _armboot_start
_armboot_start:
    .word     _start

.globl     _bss_start
_bss_start:
    .word    __bss_start

.globl    _bss_end
_bss_end:
    .word    _end

reset:
/*
**first set cpu to svc32 mode
*/
    mrs    r0,cpsr
    bic    r0,r0,#0x1f
    orr    r0,r0,#0x13
    msr    cpsr,r0
/*
    ok the cpu is setted to svc32 mode
    then we should first close the watch dog
    and the others Interrupt
*/

Init_cpu:
  
    ldr     r1,=PINSEL0
    ldr    r2,=0x0//common io
    str     r2,[r1]
    
    ldr    r1,=PINSEL2
    ldr    r2,=0x0f814914
    str    r2,[r1]

    ldr    r1,=BCFG0
    ldr    r2,=0x1000ffef
    str    r2,[r1]
    
    ldr    r1,=BCFG1
    ldr    r2,=0x1000ffef
    str    r2,[r1]

////////////////////////////////////////////////////////////////////////////////    
PLL_CON:
    .word    0xaa
    .word    0x55

#define Fosc    11059200
#define Fcclk    (Fosc*4)
#define Fcco      (Fcclk*4)
#define Fpclk    (Fcclk/4)*1

Init_target:
    ldr    r1,=MEMMAP
    mov    r2,#3
    str    r2,[r1]

    ldr    r1,=VPBDIV
    mov    r2,#0
    str    r2,[r1]
    
    ldr    r1,=PLLCFG
    mov    r2,#0x23    
    str    r2,[r1]
    
    ldr    r1,=PLLCON
    mov    r2,#01
    str    r2,[r1]
    
    ldr    r1,=PLLFEED
    mov    r2,#0xaa
    str    r2,[r1]

    mov    r2,#0x55
    str    r2,[r1]
wait_lock:
    ldr    r1,=PLLSTAT
    ldr    r2,[r1]
    tst    r2,#0x400
    beq    wait_lock

    ldr    r1,=PLLCON
    mov    r2,#0x03
    str    r2,[r1]
    
    ldr    r1,=PLLFEED
    mov    r2,#0xaa
    str    r2,[r1]
    mov     r2,#0x55
    str    r2,[r1]

/*
    relocate the mem
*/
relocate:
    adr r0,_start                               疑问2
    ldr r1,_TEXT_BASE
 
//compare how many mem we should copy
    ldr r2,_armboot_start
    ldr r3,_bss_start
    sub r2,r3,r2//r3-r2->r2
    add r2,r0,r2//from start to _bss_start
copy_loop:
    ldmia r0!,{r3-r10}
    stmia r1!,{r3-r10}
    cmp r0,r2
    ble copy_loop
//ok ,finish copyed
/////////////////////////////////////////////    
//now setup the stack and ready to jump to C code
    adr r0,real_vectors
    add r2,r0,#1024
    ldr r1,=0x81000000//this is the base of first ram
////////////////////////////////////////////////////////
//new added
    add r1,r1,#0x08
////////////////////////////////////////////////////////
v_copy_loop:
    ldmia r0!,{r3-r10}
    stmia r1!,{r3-r10}
    cmp r0,r2
    ble    v_copy_loop
stack_setup:

    ldr r0,_TEXT_BASE
    sub r0,r0,#CFG_MALLOC_LEN
    sub r0,r0,#CFG_GBL_DATA_SIZE
#ifdef CONFIG_USE_IRQ
    sub r0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
    sub r0,r0,#12
    mov fp,#0                                        疑问3
    mov a2,#0
/////////////////////////////////////////////
    ldr pc,_start_armboot
_start_armboot:
    .word start_armboot


real_vectors:                             疑问4
    b    reset
    b    undefined
    b     software
    b     preabort
    b    dataabort
    b    not_use
    b    irq
    b    fiq

undefined:
    mov     r6,#3
    b    reset
software:
    mov    r6,#4    
    b    reset    
preabort:
    mov    r6,#5
    b    reset
dataabort:
    mov    r6,#6
    b    reset
not_use:
    mov    r6,#7
    b    reset
irq:    
    mov    r6,#8
    b    reset
fiq:
    mov    r6,#9
    b    reset
上边这段代码把MEMMAP设定为0x3,就是说中断向量从外部存储器重新映射,代码已经把中断向量表拷贝到RAM的基地址处0x81000000,那么我在疑问一的地方,是否可以添加add    pc,pc,#0x01000000  这样的指令,发生请求时先到flash去指令(pc指针是0x8@@@@@@@吧?),然后将pc指针相加,指到外部的RAM空间0x81000000中,那里有中断向量表的一份拷贝。
疑问2的地方,为什么要用adr呢?那adr r0,_start, 当程序在flash中运行时和程序在ram运行时r0值是否相同,还是r0值根本不变,是由uboot.lds中指定呢?程序里有一个_start,lds文件也有一个?到底曲哪个呢?
疑问3的地方一直不明白在干什么...
疑问4的地方使用的跳转指令,执行到这的时候,一定在ram里了,那它跳转的时候是到了flash中的代码,还是到了ram中的代码呢
这些问题困扰了我很久了。。。。。

使用特权

评论回复
6
bqt| | 2007-4-6 13:57 | 只看该作者

我用自己写的Bootloader也可以从U盘加载UClinux

我写的Bootloader支持3个功能:
1. 从网卡接收hex或bin程序放到0x81000000的ram中运行,当然该程序链接时要将基地址指定在0x81000000处。
2. 从U盘中加载hex或bin程序放到0x81000000的ram中运行。
3. 从U盘中加载UClinux并运行UClinux。

当然Bootloader本身也是一个程序,它运行于0x80000000的FLASH中。
把RO段、RW段、ZI段,以及程序加载态和运行态之间的关系搞清楚应该可以做到了。

使用特权

评论回复
7
蛋蛋的老公| | 2007-4-8 00:46 | 只看该作者

看来楼主还是不大明白LPC2000的运行...

简单一点可以这样理解,,NXP的ARM7芯片在RESET信号周期内,先是运行芯片内部自带的BOOTBLOCK程序的;复位信号过后才是运行用户的程序.
这个BOOTBLOCK程序DATASHEET给出来的,存放的位置是在7FFFE000~7FFFE03C.但根据ARM7的内核结构,在复位后程序指针应是指向0000000H的,异常向量也是从000000H开始的,按此看来,是根据无法在复位后运行BOOTBLOCK程序.因此可以这样说,在LPC2000芯片中,BOOTBLOCK程序存放的位置应该是从0000000H开始的,而7FFFE000~7FFFE03C是在运行完复位信号结束后重新映射出来的地址;或者是说在其0000000H是存放映射处理程序的,BOOTBLOCK程序的物理位置就在7FFFE000~7FFFE03C.每次异常首先通过芯片的映射程序重新分配处理.这个通过在其DATASHEET中在描述关于各个空间地址的是这样说法可以看出."芯片复位后从用户的角度来看的映射地址是...".不过以上明白这么一回事就行了,不必理它是具体怎么做.
那这个BOOTBLOCK做些什么工作呢?大概如此,1.判断P0.14的状态是否为低,如为低就进入ISP模式;2.若P0.14不为低,就接着判断BOOT(1:0)这个两脚,如为"11"B否设MEMMAP=1(运行内部FLASH),否则设MEMMAP=3(运行外部FLASH);3.如果MEMMAP=1,则异常向量表无需重新映射;如果MEMMAP=3,则将异常向量表重新映射到80000000H开始(准确地说应该是80000000H这个地址重新映射到00000000H上,因为你的异常向量表是放在8000000H中,而人家复位信号过后开始过运行的地址是0000000H.重新映射后,异常发生(含复位)时,即可找到用户程序.)..此后就等待复位信号结束..复位信号结束后就开始运行用户的代码....
整个过程就是这样子,至于它内部的映射方法是怎么实现的,我们就管不着了.

这个如果做过FPGA的人就比较清楚,芯片的内部在RESET信号内通常还有一段自己的初化始过程;这些对于我们用户来说是看不见的..这就是为什么每个芯片都要求复位信号保持一定的周期.
以上关于LPC2000,是我的个人理解,也不知是否完全正确,但这样理解己能帮我去设计自己的应用程序了.希望对LZ也有帮助.

使用特权

评论回复
8
yutu2| | 2007-4-8 11:07 | 只看该作者

re...

蛋蛋真幸福 

使用特权

评论回复
9
junovour|  楼主 | 2007-4-13 10:14 | 只看该作者

明白了好多

谢谢~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

8

帖子

0

粉丝