u-boot 1.1.6分析:start.S分析

一、前言

  我使用的是JZ2440,soc是s3c2440,架构是ARM920t,指令集是ARM9。

  一般来说,开发板的相关配置都存放在board目录,所以根据在board/100ask24x0的链接脚本u-boot.lds可了解到,u-boot的入口地址为_start,其定义在cpu/arm920t/start.S文件中。

ENTRY(_start)
SECTIONS
{
    . = 0x00000000;

    . = ALIGN(4);
    .text      :
    {
      cpu/arm920t/start.o    (.text)
          board/100ask24x0/boot_init.o (.text)
      *(.text)
    }

二、对start.S的主要代码分析

  1、将CPU设为SVC32模式(CPSR寄存器的具体每一位的含义可参考s3c2440手册)。在该模式下,可以访问受控资源,拥有更多的硬件资源,有利于u-boot进行硬件资源的初始化。

1 .globl _start
2 _start:    b       reset
3 
4 reset:
5     mrs    r0,cpsr
6     bic    r0,r0,#0x1f
7     orr    r0,r0,#0xd3
8     msr    cpsr,r0

  

  2、关闭看门狗定时器,禁止中断(s3c2440有两个中断控制器)。

 1 # define pWTCON        0x53000000
 2 
 3 # define INTMSK        0x4A000008    
 4 # define INTSUBMSK     0x4A00001C      
 5 
 6     ldr    r0, =pWTCON
 7     mov    r1, #0x0
 8     str    r1, [r0]
 9 
10     mov    r1, #0xffffffff
11     ldr    r0, =INTMSK
12     str    r1, [r0]
13 
14     ldr    r1, =0x7fff
15     ldr    r0, =INTSUBMSK
16     str    r1, [r0]

  

  3、开始配置s3c2440的时钟。之所以在这里就开始配置时钟,是因为后续的SDRAM初始化使用需要用到时钟进行刷下配置。

    (1)在配置完CLKDIVN寄存器后,该寄存器的HDIVN=0x10,根据芯片手册,当HDIVN不为零的时候,CPU总线模式必须由快速总线模式改为异步总线模式。

    (2)在配置PPL之前,我们需要配置LOCKTIME寄存器,这是因为配置PPL后到PPL输出稳定的时钟信号也是需要一定的时间的。

//FCLK:HCLK:PCLK = 1:4:8, UCLK=UPLL 
//FCLK=400MHz, HCLK=100MHz, PCLK=50MHz, UCLK=48MHz
#define    CLKDIVN   0x4C000014         //Clock divider control register
#define    MPLLCON   0x4C000004         //MPLL configuration register
#define    UPLLCON   0x4C000008         //UPLL configuration register
#define    LOCKTIME  0x4C000000         //PLL lock time count register

#define S3C2440_MPLL_400MHZ     ((0x5c<<12)|(0x01<<4)|(0x01))
#define S3C2440_UPLL_48MHZ      ((0x38<<12)|(0x02<<4)|(0x02))
#define S3C2440_CLKDIV          (0x05)

     ldr r1, =CLKDIVN
     ldr r2, =S3C2440_CLKDIV
     str r2, [r1]
 
     //设为异步总线模式    
     mrc p15, 0, r1, c1, c0, 0       // read ctrl register 
     orr r1, r1, #0xc0000000         // Asynchronous    
     mcr p15, 0, r1, c1, c0, 0       // write ctrl register 
 
     ldr r0,=LOCKTIME
     ldr r1,=0xffffff
     str r1,[r0]    
 
     ldr r0,=MPLLCON          
     ldr r1,=S3C2440_MPLL_400MHZ
     str r1,[r0]
 
     ldr r0, =UPLLCON          
     ldr r1, =S3C2440_UPLL_48MHZ
     str r1, [r0]

 

  4、根据GSTATUS2寄存器来判断当前进入这里是复位还是唤醒,若是唤醒,则调用唤醒函数。

#define GSTATUS2       (0x560000B4)

    ldr r0, =GSTATUS2
    ldr r1, [r0]
    tst r1, #(1<<1)      /* r1&(1<<1) */
    bne wake_up

  

  5、判断当前的代码是否运行在SDRAM中,如果没有运行在SDRAM中,则进行cpu的初始化。

    (1)_TEXT_BASE定义的是u-boot在SDRAM中运行的入口地址(即_start地址),其定义在board/100ask24x0/config.mk中,值为0x33F80000。

    (2)CPU的初始化包括flush v4 I/D caches、disable MMU stuff and caches、lowlevel_init(SDRAM初始化)。

    adr    r0, _start        /* current position of code  */
    ldr    r1, _TEXT_BASE    /* test if we run from flash or RAM */
    cmp    r0, r1            /* don't reloc during debug */
    blne   cpu_init_crit

  

  6、在调用C语言函数之前,需要设置好堆栈,这是因为CPU在运行C语言函数时候,会自动使用堆栈

    (1)以"CONFIG_"开头的宏一般都定义在include/configs/100ask24x0.h这个头文件中

    (2)栈是向下增长的,所以这里是指向栈顶

#define CFG_ENV_SIZE        0x20000                       /* 环境变量的总大小,共128K */
#define CFG_MALLOC_LEN      (CFG_ENV_SIZE + 128*1024)     /* 为malloc()函数分配的大小,共256K */ 
#define CFG_GBL_DATA_SIZE   128                /* 全局变量struct gd_t gd的大小,共128 */ 

#define CONFIG_STACKSIZE_IRQ    (4*1024)    /* IRQ stack,共4K */
#define CONFIG_STACKSIZE_FIQ    (4*1024)    /* FIQ stack,共4K */       

    ldr    r0, _TEXT_BASE                   
    sub    r0, r0, #CFG_MALLOC_LEN    
    sub    r0, r0, #CFG_GBL_DATA_SIZE

    sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    sub    sp, r0, #12          /* leave 3 words for abort-stack    */

    (3)示意图如下所示

           

  7、代码的重定向,也就是将代码从Flash中拷贝到SDRAM中

    (1)根据APCS(ARM过程调用标准),C语言的前四个形参可以通过访问r0~r3寄存器得到,其余的形参就在堆栈中了

.globl _armboot_start
_armboot_start:
    .word _start

relocate:                    /* relocate U-Boot to RAM */
    adr    r0, _start        /* r0 <- current position of code */
    ldr    r1, _TEXT_BASE    /* test if we run from flash or RAM */
    cmp    r0, r1            /* don't reloc during debug */
    beq    clear_bss      /* bss段清零 */ 
    
    ldr    r2, _armboot_start
    ldr    r3, _bss_start
    sub    r2, r3, r2        /* r2 <- size of armboot */

    bl  CopyCode2Ram         /* r0: source, r1: dest, r2: size */

    clear_bss:
    ldr    r0, _bss_start    /* find start of bss segment */
    ldr    r1, _bss_end      /* stop here */
    mov r2, #0x00000000      /* clear */

    clbss_l:
    str    r2, [r0]          /* clear loop... */
    add    r0, r0, #4
    cmp    r0, r1
    ble    clbss_l

  8、设置一个全局变量,用于后续的u-boot运行

.globl PreLoadedONRAM
PreLoadedONRAM:
    .word    0

SetLoadFlag:
    /* Set a global flag, PreLoadedONRAM */
    adr    r0, _start            /* r0 <- current position of code   */
    ldr    r1, _TEXT_BASE        /* test if we run from flash or RAM */
    cmp    r0, r1                /* don't reloc during debug         */
    ldr    r2, =PreLoadedONRAM
    mov    r3, #1
    streq  r3, [r2]        /* 如果r0=r1,也就是已经在SDRAM中运行了,那么 PreLoadedONRAM 就为1 */

  9、跳入start_armboot函数,进行相关硬件的初始化

_start_armboot:    .word start_armboot

  ldr    pc, _start_armboot

猜你喜欢

转载自www.cnblogs.com/Recca/p/11443734.html