学习UBOOT前奏之hardware-sdram[s3c2440]

来源:互联网 发布:林彪军事才能 知乎 编辑:程序博客网 时间:2024/05/19 03:29

今天我们来学习下S3C2440的SDRAM,同样以代码的形式分析。

@*************************************************************************@ File:head.S@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行@*************************************************************************       .equ        MEM_CTL_BASE,       0x48000000.equ        SDRAM_BASE,         0x30000000.text.global _start_start:    bl  disable_watch_dog               @ 关闭WATCHDOG,否则CPU会不断重启    bl  memsetup                        @ 设置存储控制器    bl  copy_steppingstone_to_sdram     @ 复制代码到SDRAM中    ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行on_sdram:    ldr sp, =0x34000000                 @ 设置堆栈    bl  mainhalt_loop:    b   halt_loopdisable_watch_dog:    @ 往WATCHDOG寄存器写0即可    mov r1,     #0x53000000    mov r2,     #0x0    str r2,     [r1]    mov pc,     lr      @ 返回copy_steppingstone_to_sdram:    @ 将Steppingstone的4K数据全部复制到SDRAM中去    @ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000    mov r1, #0    ldr r2, =SDRAM_BASE    mov r3, #4*10241:      ldr r4, [r1],#4     @ 从Steppingstone读取4字节的数据,并让源地址加4    str r4, [r2],#4     @ 将此4字节的数据复制到SDRAM中,并让目地地址加4    cmp r1, r3          @ 判断是否完成:源地址等于Steppingstone的未地址?    bne 1b              @ 若没有复制完,继续    mov pc,     lr      @ 返回memsetup:    @ 设置存储控制器以便使用SDRAM等外设    mov r1,     #MEM_CTL_BASE       @ 存储控制器的13个寄存器的开始地址    adrl    r2, mem_cfg_val         @ 这13个值的起始存储地址    add r3,     r1, #52             @ 13*4 = 541:      ldr r4,     [r2], #4            @ 读取设置值,并让r2加4    str r4,     [r1], #4            @ 将此值写入寄存器,并让r1加4    cmp r1,     r3                  @ 判断是否设置完所有13个寄存器    bne 1b                          @ 若没有写成,继续    mov pc,     lr                  @ 返回.align 4mem_cfg_val:    @ 存储控制器13个寄存器的设置值    .long   0x22011110      @ BWSCON   总线宽度与等待控制寄存器    .long   0x00000700      @ BANKCON0  BANK控制寄存器    .long   0x00000700      @ BANKCON1    .long   0x00000700      @ BANKCON2    .long   0x00000700      @ BANKCON3      .long   0x00000700      @ BANKCON4    .long   0x00000700      @ BANKCON5    .long   0x00018005      @ BANKCON6  0001 1000 0000 0000 0101    .long   0x00018005      @ BANKCON7    .long   0x008C07A3      @ REFRESH 设置刷新周期    .long   0x000000B1      @ BANKSIZE 设置BANK6,和7的size    .long   0x00000030      @ MRSRB6    .long   0x00000030      @ MRSRB7 0011 0000

这个程序的功能是初始化SDRAM,并将自身代码复制到SDRAM中,执行点灯的功能。点灯的功能main()函数在leds.c中定义,这里没有列出。代码编译的Makefile如下:

sdram.bin : head.S  leds.c    arm-linux-gcc  -c -o head.o head.S    arm-linux-gcc -c -o leds.o leds.c    arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf    arm-linux-objcopy -O binary -S sdram_elf sdram.bin    arm-linux-objdump -D -m arm  sdram_elf > sdram.disclean:    rm -f   sdram.dis sdram.bin sdram_elf *.o

这里我们重点关注下如下这句:

arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf

它表示链接完成后的代码运行地址是0x3000 0000
下面是反汇编生成的结果的部分片段:

30000000 <_start>:30000000:   eb000005    bl  3000001c <disable_watch_dog> 30000004:   eb000010    bl  3000004c <memsetup>30000008:   eb000007    bl  3000002c <copy_steppingstone_to_sdram>3000000c:   e59ff090    ldr pc, [pc, #144]  ; 300000a4 <mem_cfg_val+0x34>30000010 <on_sdram>:30000010:   e3a0d30d    mov sp, #872415232  ; 0x3400000030000014:   eb000032    bl  300000e4 <main>30000018 <halt_loop>:30000018:   eafffffe    b   30000018 <halt_loop>3000001c <disable_watch_dog>:3000001c:   e3a01453    mov r1, #1392508928 ; 0x5300000030000020:   e3a02000    mov r2, #0  ; 0x030000024:   e5812000    str r2, [r1]30000028:   e1a0f00e    mov pc, lr3000002c <copy_steppingstone_to_sdram>:3000002c:   e3a01000    mov r1, #0  ; 0x030000030:   e3a02203    mov r2, #805306368  ; 0x3000000030000034:   e3a03a01    mov r3, #4096   ; 0x100030000038:   e4914004    ldr r4, [r1], #43000003c:   e4824004    str r4, [r2], #430000040:   e1510003    cmp r1, r330000044:   1afffffb    bne 30000038 <copy_steppingstone_to_sdram+0xc>30000048:   e1a0f00e    mov pc, lr3000004c <memsetup>:3000004c:   e3a01312    mov r1, #1207959552 ; 0x4800000030000050:   e28f2018    add r2, pc, #24 ; 0x1830000054:   e1a00000    nop         (mov r0,r0)30000058:   e2813034    add r3, r1, #52 ; 0x343000005c:   e4924004    ldr r4, [r2], #430000060:   e4814004    str r4, [r1], #430000064:   e1510003    cmp r1, r330000068:   1afffffb    bne 3000005c <memsetup+0x10>3000006c:   e1a0f00e    mov pc, lr

从上面的反汇编结果可以看出,代码运行地址从30000000开始,这就是arm-linux-ld -Ttext 0x30000000的作用。
我们知道S3C2440 NAND启动时,NAND flash的前4k字节的内容,被硬件直接拷贝的片内0地址开始的4K,也就是一开始的运行地址应该是从0开始的,为什么还能正常运行呢?

其实这里就是用到上一篇中说到位置无关代码的机制。请看下面的反汇编代码片段:

30000000 <_start>:30000000:   eb000005    bl  3000001c <disable_watch_dog>30000004:   eb000010    bl  3000004c <memsetup>30000008:   eb000007    bl  3000002c <copy_steppingstone_to_sdram>3000000c:   e59ff090    ldr pc, [pc, #144]  ; 300000a4 <mem_cfg_val+0x34>30000010 <on_sdram>:30000010:   e3a0d30d    mov sp, #872415232  ; 0x3400000030000014:   eb000032    bl  300000e4 <main>

前面三条都是BL跳转指令,我们说BL是可以实现位置无关代码的,为什么呢?很简单,因为他是相对于PC指针来进行寻址的,当代码从0地址开始运行时,相对PC指针的偏移并没有变,所以能够能够正常运行。
首先我们来解析下看看BL 指令如何跳转到指定的地方,分析下BL指令的机器码

32位的机器码分为以下3个部分[31:28]:条件码[27:24]:指令码[23:0]:用来表示偏移地址30000000:   eb000005    bl  3000001c <disable_watch_dog>机器码:eb00 0005:1110 1010 0000 0000 0000 0000 0000 0101其中0xb:1010b 表示这条指令为BL指令0x00 0005:表示偏移地址如何通过偏移地址得到将要跳转的地方呢?方法:将指令中24位带符号的补码立即数扩展为32(扩展其符号位);将此32位数左移两位;将得到的值加到pc寄存器中,即得到跳转的目标地址通过上面的方法,我们能得到相对PC的偏移地址为0x14,那么此时的PC为多少呢?现在是零地址的开始执行的,我们知道ARM有三级流水线,也就是PC的值=当前执行的指令的地址+8,那么 bl  disable_watch_dog 跳转到 0000 001c,这里刚好放置的disable_watch_dog函数,成功实现了跳转

当下面程序执行完成以后,代码已经被拷贝到SDRAM当中了

    bl  disable_watch_dog               @ 关闭WATCHDOG,否则CPU会不断重启    bl  memsetup                        @ 设置存储控制器    bl  copy_steppingstone_to_sdram

接着一条ldr pc, =on_sdram伪指令,直接对pc进行赋值,实现跳转到SDRAM到执行,接着设置调用c程序必须的堆栈,最后通过bl main 跳转到点灯的程序,跳转地址计算方式跟上面的分析是一致的

    ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行on_sdram:    ldr sp, =0x34000000                 @ 设置堆栈    bl  main

有问题,可直接留言讨论

如果想理解ARM流水线相关知识可以点这里
arm 流水线

原创粉丝点击