AM335x启动流程(BootRom-> MLO->的Uboot)

http://blog.chinaunix.net/uid-28458801-id-3486399.html


参考文件:

1,AM335x ARM Cortex-A8微处理器(MPU)技术参考手册.pdf;

2,am3359.pdf;


1,am335x的CPU上电后,会跳到哪个地址去执行?

答:


芯片到uboot的启动流程 :ROM→MLO(SPL)→uboot.img

AM335x中bootloader被分成了3个部分:

第一级bootloader:引导加载程序,板子上电后会自动执行这些代码,如选择哪种方式启动(NAND,SDcard,UART ...),然后跳转转到第二级bootloader这些代码应该是存放于176KB的ROM中。


第二级bootloader: MLO(SPL),用于硬件初始化:关闭看门狗,关闭中断,设置CPU时钟频率,速度等操作。然后会跳转到第三级bootloader.MLO文件应该会被映射到64 KB的内部SRAM中。


第三级bootloader: uboot.img,C代码的入口。


其中第一级bootloader是板子固化的,第二级和第三级是通过编译uboot所得的。



2,第二级bootloader: MLO(SPL)做了哪些事情?

MLO(SPL)内存分布如下:

SPL内存重映射:


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
< PATH :  /arch/arm/cpu/armv7/omap-common/u-boot-spl .lds >
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
         LENGTH = CONFIG_SPL_MAX_SIZE }
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
         LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
 
OUTPUT_FORMAT( "elf32-littlearm" "elf32-littlearm" "elf32-littlearm" )
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
     .text      :
     {
     __start = .;
       arch /arm/cpu/armv7/start .o    (.text)
       *(.text*)
     } >.sram
 
     . = ALIGN(4);
     .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
 
     . = ALIGN(4);
     .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
     . = ALIGN(4);
     __image_copy_end = .;
     _end = .;
 
     .bss :
     {
         . = ALIGN(4);
         __bss_start = .;
         *(.bss*)
         . = ALIGN(4);
         __bss_end__ = .;
     } >.sdram
}



1
2
3
4
6
7
<PATH : /include/configs/am335x_evm.h>
#define CONFIG_SPL_TEXT_BASE        0x402F0400
#define CONFIG_SPL_MAX_SIZE     (46 * 1024)
#define CONFIG_SPL_STACK        LOW_LEVEL_SRAM_STACK
 
#define CONFIG_SPL_BSS_START_ADDR   0x80000000
#define CONFIG_SPL_BSS_MAX_SIZE     0x80000     /* 512 KB */ <span style="font-size:16px;color:#003399;"><strong></strong></span>


    @ 1 @保存启动参数 bl save_boot_params


1
2
3
4
6
7
<PATH :  /arch/arm/cpu/armv7/start .S>
/*
  * the actual reset code
  */
 
reset:
     bl  save_boot_params

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<PATH :  /arch/arm/cpu/armv7/omap-common/lowlevel_init .S>
.global save_boot_params
save_boot_params:
     /*
      * See  if  the rom code passed pointer is valid:
      * It is not valid  if  it is not  in  non-secure SRAM
      * This may happen  if  you are booting with the help of
      * debugger
      */
     ldr     r2, =NON_SECURE_SRAM_START
     cmp  r2, r0
     bgt 1f
     ldr r2, =NON_SECURE_SRAM_END
     cmp  r2, r0
     blt 1f
 
     /*
      * store the boot params passed from rom code or saved
      * and passed by SPL
      */
     cmp  r0,  #0
     beq 1f
     ldr r1, =boot_params
     str r0, [r1]
1
2
3
4
6
7
8
/*《PATH: /arch/arm/include/asm/arch-ti81xx/omap.h》
  * Non-secure SRAM Addresses
  * Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE
  * at 0x40304000(EMU base) so that our code works for both EMU and GP
  */
#define NON_SECURE_SRAM_START   0x40304000
#define NON_SECURE_SRAM_END 0x4030E000
#define LOW_LEVEL_SRAM_STACK    0x4030B7FC


问题:这些参数是保存在哪里的大概有哪些参数?

答:

这些参数保存的内存地址为64 KB的OCM RAM中:

注:下载图片区域:是用来保存MLO(SPL )文件的,其最大可达到109 KB



    @ a2 @设置CPU为SVC32模式

1
2
3
4
6
7
8
     <PATH : /arch/arm/cpu/armv7/start .S>       
         /*
      set  the cpu to SVC32 mode
      */
     mrs r0, cpsr
     bic r0, r0,  #0x1f
     orr r0, r0,  #0xd3
     msr cpsr,r0


   CPSR:程序状态寄存器(当前程序状态寄存器),在任何处理器模式下被访问。它包含了条件标志位,中断禁止位,当前处理器模式标志以及其他的一些控制和状态位
CPSR在用户级编程时用于存储条件码。

  SPSR:程序状态保存寄存器(保存程序状态寄存器),每一种处理器模式下都有一个状态寄存器SPSR,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。中断发生时,这个寄存器用于存放当前程序状态寄存器的内容。在异常中断退出时,可以用SPSR来恢复CPSR。由于用户模式和系统模式不是异常中断模式,所以他没有SPSR。当用户在用户模式或系统模式访问SPSR,将产生不可预知的后果。

CPSR格式如下所示.SPSR和CPSR格式相同
31 30 29 28 27 26 7 6 5 4 3 2 1 0 
NZCVQ DNM(RAZ)IFT M4 M3 M2 M1 M0



详解:http : //blog.chinaunix.net/uid-28458801-id-3487199.html


    @ a3 @ C​​PU的初始化

1
2
3
4
《PATH : /arch/arm/cpu/armv7/start.S》
     /* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
     bl  cpu_init_crit
#endif


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
<PATH :  /arch/arm/cpu/armv7/omap-common/lowlevel_init .S>
.globl lowlevel_init
lowlevel_init:
     /*
      * Setup a temporary stack
      */
     ldr sp, =LOW_LEVEL_SRAM_STACK
 
     /*
      * Save the old lr(passed  in  ip) and the current lr to stack
      */
     push    {ip, lr}
 
     /*
      * go setup pll, mux, memory
      */
     bl  s_init
     pop {ip, pc}


问题:CPU初始化的有哪些内容?

答:

            @ b1 @首先要设置堆栈区,因为将会调用C函数来实现CPU的初始化

问题:这个堆栈在什么位置,其内存大小是多少?

1
2
《PATH :/arch/arm/ include /asm/arch-ti81xx/omap.h》
#define LOW_LEVEL_SRAM_STACK     0x4030B7FC <strong></strong>




            @ b2 @执行s_init()函数,实现CPU的初始化


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<PATH : /board/ti/am335x/evm.c>
/*
  * early system init of muxing and clocks.
  */
void  s_init( void )
{
     /* Can be removed as A8 comes up with L2 enabled */
     l2_cache_enable();
 
     /* WDT1 is already running when the bootloader gets control
      * Disable it to avoid "random" resets
      */
     __raw_writel( 0xAAAA , WDT_WSPR);
     while (__raw_readl(WDT_WWPS) !=  0x0 );
     __raw_writel( 0x5555 , WDT_WSPR);
     while (__raw_readl(WDT_WWPS) !=  0x0 );
 
#ifdef CONFIG_SPL_BUILD
     /* Setup the PLLs and the clocks for the peripherals */
     pll_init();
 
     /* Enable RTC32K clock */
     rtc32k_enable();
 
     /* UART softreset */
     u32 regVal;
     u32 uart_base = DEFAULT_UART_BASE;
 
     enable_uart0_pin_mux();
     /* IA Motor Control Board has default console on UART3*/
     /* XXX: This is before we've probed / set board_id */
     if  (board_id == IA_BOARD) {
         uart_base = UART3_BASE;
     }
 
     regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);
     regVal |= UART_RESET;
     __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );
     while  ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &
             UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);
 
     /* Disable smart idle */
     regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));
     regVal |= UART_SMART_IDLE_EN;
     __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));
 
     /* Initialize the Timer */
     init_timer();
 
     preloader_console_init();
 
     printf( "\nlocation /board/ti/am335x\n" );         //@@
/*@@*/
//  led();
/*@@*/
     
     config_am335x_ddr();
 
#endif
}

                    @ c1 @使能第二级缓冲区


1
2
3
4
6
7
8
9
10
     /* Can be removed as A8 comes up with L2 enabled */
     l2_cache_enable();
 
<PATH : /arch/arm/cpu/armv7/ti81xx/cache.S>
l2_cache_enable:
     push    {r0, r1, r2, lr}
     mrc 15, 0, r3, cr1, cr0, 1
     orr r3, r3, #2
     mcr 15, 0, r3, cr1, cr0, 1
     pop {r1, r2, r3, pc}


                    @ c2 @关闭看门狗(WDT)


1
2
3
4
6
7
/* WDT1 is already running when the bootloader gets control
  * Disable it to avoid "random" resets
  */
__raw_writel(0xAAAA, WDT_WSPR);
while (__raw_readl(WDT_WWPS) != 0x0);
__raw_writel(0x5555, WDT_WSPR);
while (__raw_readl(WDT_WWPS) != 0x0);



1
2
3
4
6
7
8
9
10
11
<PATH : /arch/arm/ include /asm/arch-ti81xx/cpu.h>
#define WDT_WSPR    (WDT_BASE +  0x048 )
 
 
<PATH : /arch/arm/ include /asm/arch-ti81xx/hardware.h>
/* Watchdog Timer */
#ifdef CONFIG_AM335X
#define WDT_BASE             0x44E35000
# else
#define WDT_BASE             0x480C2000
#endif



                    @ c3 @ 给外设设置好PLL和时钟频率等


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     /* Setup the PLLs and the clocks for the peripherals */
     pll_init();
 
 
<PATH : /board/ti/am335x/pll.c>
/*
  * Configure the PLL/PRCM for necessary peripherals
  */
void  pll_init()
{
     mpu_pll_config(MPUPLL_M_500);
     core_pll_config();
     per_pll_config();
     ddr_pll_config();
     /* Enable the required interconnect clocks */
     interface_clocks_enable();
     /* Enable power domain transition */
     power_domain_transition_enable();
     /* Enable the required peripherals */
     per_clocks_enable();
}



                    @ c4 @使能32-KHz频率的实时时钟


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
     /* Enable RTC32K clock */
     rtc32k_enable();
 
 
《PATH : /board/ti/am335x/evm.c》
static  void  rtc32k_enable( void )
{
     /* Unlock the rtc's registers */
     __raw_writel( 0x83e70b13 , (AM335X_RTC_BASE + RTC_KICK0_REG));
     __raw_writel( 0x95a4f1e0 , (AM335X_RTC_BASE + RTC_KICK1_REG));
 
     /* Enable the RTC 32K OSC */
     __raw_writel( 0x48 , (AM335X_RTC_BASE + RTC_OSC_REG));
}
 
<PATH : /arch/arm/ include /asm/arch-ti81xx/hardware.h>
/* RTC base address */
#define AM335X_RTC_BASE             0x44E3E000
 
<PATH : /board/ti/am335x/evm.c>
#define RTC_KICK0_REG         0x6c
#define RTC_KICK1_REG         0x70
#define RTC_OSC_REG         0x54


                    @ c5 @使能UART0


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
     /* UART softreset */
     u32 regVal;
     u32 uart_base = DEFAULT_UART_BASE;
 
     enable_uart0_pin_mux();
     /* IA Motor Control Board has default console on UART3*/
     /* XXX: This is before we've probed / set board_id */
     if  (board_id == IA_BOARD) {
         uart_base = UART3_BASE;
     }
 
     regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);
     regVal |= UART_RESET;
     __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );
     while  ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &
             UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);
 
     /* Disable smart idle */
     regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));
     regVal |= UART_SMART_IDLE_EN;
     __raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));
 
 
<PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h>
#ifdef CONFIG_AM335X
#define DEFAULT_UART_BASE       UART0_BASE
#endif
 
<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h>
#ifdef CONFIG_AM335X
#define UART0_BASE          0x44E09000
#else
#define UART0_BASE          0x48020000
#endif


                    @ c6 @初始化定时器


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
     /* Initialize the Timer */
     init_timer();
 
 
<PATH : /board/ti/am335x/evm.c>
static  void  init_timer( void )
{
     /* Reset the Timer */
     __raw_writel( 0x2 , (DM_TIMER2_BASE + TSICR_REG));
 
     /* Wait until the reset is done */
     while  (__raw_readl(DM_TIMER2_BASE + TIOCP_CFG_REG) &  1 );
 
     /* Start the Timer */
     __raw_writel( 0x1 , (DM_TIMER2_BASE + TCLR_REG));
}
 
<PATH : /arch/arm/ include /asm/arch-ti81xx/hardware.h>
/* DM Timer base addresses */
#define DM_TIMER0_BASE           0x4802C000
#define DM_TIMER1_BASE           0x4802E000
#define DM_TIMER2_BASE           0x48040000
#define DM_TIMER3_BASE           0x48042000
#define DM_TIMER4_BASE           0x48044000
#define DM_TIMER5_BASE           0x48046000
#define DM_TIMER6_BASE           0x48048000
#define DM_TIMER7_BASE           0x4804A000


                    @ c7 @初始化控制台,通过UART可以查看相关信息


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
     preloader_console_init();
 
《PATH : /arch/arm/cpu/armv7/omap-common/spl.c》
/* This requires UART clocks to be enabled */
void  preloader_console_init( void )
{
     const  char  *u_boot_rev = U_BOOT_VERSION;
     char  rev_string_buffer[50];
 
     gd = &gdata;
     gd->bd = &bdata;
     gd->flags |= GD_FLG_RELOC;
     gd->baudrate = CONFIG_BAUDRATE;
 
     serial_init();       /* serial communications setup */
 
     /* Avoid a second "U-Boot" coming from this string */
     u_boot_rev = &u_boot_rev[7];
 
     printf ( "\nU-Boot SPL %s (%s - %s)\n" , u_boot_rev, U_BOOT_DATE,
         U_BOOT_TIME);
     omap_rev_string(rev_string_buffer);
     printf ( "Texas Instruments %s\n" , rev_string_buffer);
} <span style= "font-size:14px;color:#003399;" ></span>


                    @ c8 @配置DDR


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
     config_am335x_ddr();
 
《PATH :》
/*  void DDR2_EMIF_Config(void); */
static  void  config_am335x_ddr( void )
{
     int  data_macro_0 = 0;
     int  data_macro_1 = 1;
 
     enable_ddr_clocks();
 
     config_vtp();
 
     Cmd_Macro_Config();
 
     Data_Macro_Config(data_macro_0);
     Data_Macro_Config(data_macro_1);
 
     __raw_writel(PHY_RANK0_DELAY, DATA0_RANK0_DELAYS_0);
     __raw_writel(PHY_RANK0_DELAY, DATA1_RANK0_DELAYS_0);
 
     __raw_writel(DDR_IOCTRL_VALUE, DDR_CMD0_IOCTRL);
     __raw_writel(DDR_IOCTRL_VALUE, DDR_CMD1_IOCTRL);
     __raw_writel(DDR_IOCTRL_VALUE, DDR_CMD2_IOCTRL);
     __raw_writel(DDR_IOCTRL_VALUE, DDR_DATA0_IOCTRL);
     __raw_writel(DDR_IOCTRL_VALUE, DDR_DATA1_IOCTRL);
 
     __raw_writel(__raw_readl(DDR_IO_CTRL) & 0xefffffff, DDR_IO_CTRL);
     __raw_writel(__raw_readl(DDR_CKE_CTRL) | 0x00000001, DDR_CKE_CTRL);
 
     config_emif_ddr2();
}
 
 
《PATH : /arm/include/asm/arch-ti81xx/cpu.h》
#define DATA0_RANK0_DELAYS_0        (DDR_PHY_BASE_ADDR + 0x134)
#define DATA1_RANK0_DELAYS_0        (DDR_PHY_BASE_ADDR + 0x1D8)
 
/* DDR offsets */
#define DDR_PHY_BASE_ADDR       0x44E12000
#define DDR_IO_CTRL         0x44E10E04
#define DDR_CKE_CTRL            0x44E1131C
#define CONTROL_BASE_ADDR       0x44E10000


                    @c DONE @

            @b DONE @

    @ a4 @设置内部RAM内存空间的指针,调用board_init_f()函数


1
2
3
4
6
/* Set stackpointer  in  internal RAM to call board_init_f */
call_board_init_f:
     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
     bic sp, sp,  #7 /* 8-byte alignment for ABI compliance */
     ldr r0,=0x00000000
     bl  board_init_f



1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<PATH: include/configs/am335x_evm.h>
#define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_INIT_RAM_ADDR + \
                      CONFIG_SYS_INIT_RAM_SIZE - \
                      GENERATED_GBL_DATA_SIZE)
 
#define CONFIG_SYS_INIT_RAM_ADDR    SRAM0_START
#define CONFIG_SYS_INIT_RAM_SIZE    SRAM0_SIZE
 
<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h : begin>
#ifdef CONFIG_AM335X
#define SRAM0_START         0x402F0400
#else
#define SRAM0_START         0x40300000
#endif
<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h : end>
 
<PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h : begin>
#if defined(CONFIG_AM335X) || defined(CONFIG_TI814X)
#define SRAM0_SIZE          (0x1B400) /* 109 KB */
#define SRAM_GPMC_STACK_SIZE        (0x40)
#endif
<PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h : end>
 
<PATH : /am335x/include/generated/generic-asm-offsets.h : begin>
#define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */
<PATH : /am335x/include/generated/generic-asm-offsets.h : end>



1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<PATH : /arch/arm/cpu/armv7/omap-common/spl.c'>
void  board_init_f(ulong dummy)
{
     /*
      * We call relocate_code() with relocation target same as the
      * CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
      * skipped. Instead, only .bss initialization will happen. That's
      * all we need
      */
     debug( ">>board_init_f()\n" );
     relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
}
 
<PATH : /arch/arm/cpu/armv7/omap-common/spl.c : begin>
#define CONFIG_SPL_TEXT_BASE        0x402F0400
#define CONFIG_SPL_MAX_SIZE     (46 * 1024)
#define CONFIG_SPL_STACK        LOW_LEVEL_SRAM_STACK
<PATH : /arch/arm/cpu/armv7/omap-common/spl.c : end>
 
<PATH : /arch/arm/include/asm/arch-ti81xx/omap.h : begin>
#define LOW_LEVEL_SRAM_STACK    0x4030B7FC
<PATH : /arch/arm/include/asm/arch-ti81xx/omap.h : end>




1
2
3
4
6
7
8
9
10
11
12
13
<PATH :  /arch/arm/cpu/armv7/start .S>
/*
  * void relocate_code (addr_sp, gd, addr_moni)
  *
  * This  "function"  does not  return , instead it continues  in  RAM
  * after relocating the monitor code.
  *
  */
     .globl  relocate_code
relocate_code:
     mov r4, r0  /* save addr_sp */
     mov r5, r1  /* save addr of gd */
     mov r6, r2  /* save addr of destination 0x402F0400*/


    @ a5 @代码重定位

代码重定向,它首先检测自己(MLO)是否已经在内存中:

如果是直接跳到下面的堆栈初始化代码clear_bss

如果不是就将自己从Nor Flash中拷贝到内存中。


NOR闪存和Nand Flash的本质区别就在于是否进行代码拷贝,也就是下面代码所表述:无论
的英文NOR闪存还是NAND闪存,核心思想就是将UBOOT代码搬运到内存中去运行,但是拷没有
贝BSS后面这段代码,只拷贝BSS前面的代码,BSS代码是放置全局变量的.BSS代码段的英文为
了清零,拷贝过去再清零重复操作。


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
     /* Set up the stack                         */
stack_setup:
     mov sp, r4
 
     adr r0, _start
     cmp  r0, r6
     moveq   r9,  #0      /* no relocation. relocation offset(r9) = 0 */
     beq clear_bss       /* skip relocation */
     mov r1, r6          /* r1 <- scratch  for  copy_loop */
     ldr r3, _image_copy_end_ofs
     add r2, r0, r3      /* r2 <-  source  end address      */
 
copy_loop:                              /* 自拷贝 */
     ldmia   r0!, {r9-r10}       /* copy from  source  address [r0]    */
     stmia   r1!, {r9-r10}       /* copy to   target address [r1]    */
     cmp  r0, r2          /*  until  source  end address [r2]    */
     blo copy_loop

    @ a6 @清空bss段


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
clear_bss:
 
     ldr r0, _bss_start_ofs
     ldr r1, _bss_end_ofs
     mov r4, r6          /* reloc addr */
     add r0, r0, r4
     add r1, r1, r4
 
     mov r2,  #0x00000000     /* clear                */
 
clbss_l:str r2, [r0]        /*  clear  loop...            */
     add r0, r0,  #4
     cmp  r0, r1
     bne clbss_l
 
/*
  * These are defined  in  the board-specific linker script.
  */
.globl _bss_start_ofs
_bss_start_ofs:
     .word __bss_start - _start          /* __bss_start = 0x80000000 */


    @ a7 @调用函数board_init_r,用以完成MLO(SPI)阶段的所有初始化,并跳转到uboot.img阶段


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
  * We are  done . Do not  return , instead branch to second part of board
  * initialization, now running from RAM.
  */
jump_2_ram:
/*
  * If I-cache is enabled invalidate it
  */
#ifndef CONFIG_SYS_ICACHE_OFF
     mcr p15, 0, r0, c7, c5, 0   @ invalidate icache
     mcr     p15, 0, r0, c7, c10, 4  @ DSB
     mcr     p15, 0, r0, c7, c5, 4   @ ISB
#endif
     ldr r0, _board_init_r_ofs
     adr r1, _start
     add lr, r0, r1
     add lr, lr, r9
     /* setup parameters  for  board_init_r */
     mov r0, r5      /* gd_t */
     mov r1, r6      /* dest_addr */
     /* jump to it ... */
     mov pc, lr
 
_board_init_r_ofs:
     .word board_init_r - _start




1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
《PATH : /arch/arm/cpu/armv7/omap-common/spl.c 》
void  board_init_r(gd_t *id, ulong dummy)
{
     u32 boot_device;
     debug( ">>spl:board_init_r()\n" );
 
     timer_init();
     i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
 
#ifdef CONFIG_SPL_BOARD_INIT
     spl_board_init();
#endif
 
     boot_device = omap_boot_device();
     debug( "boot device - %d\n" , boot_device);
     switch  (boot_device) {
#ifdef CONFIG_SPL_MMC_SUPPORT
     case  BOOT_DEVICE_MMC1:
     case  BOOT_DEVICE_MMC2:
         spl_mmc_load_image();
         break ;
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
     case  BOOT_DEVICE_NAND:
         spl_nand_load_image();
         break ;
#endif
#ifdef CONFIG_SPL_YMODEM_SUPPORT
     case  BOOT_DEVICE_UART:
         spl_ymodem_load_image();
         break ;
#endif
     default :
         printf ( "SPL: Un-supported Boot Device - %d!!!\n" , boot_device);
         hang();
         break ;
     }
 
     switch  (spl_image.os) {
     case  IH_OS_U_BOOT:
         debug( "Jumping to U-Boot\n" );
         jump_to_image_no_args();
         break ;
     default :
         puts ( "Unsupported OS image.. Jumping nevertheless..\n" );
         jump_to_image_no_args();
     }
}


    @a DONE @


3,第三级bootloader:uboot.img 做了哪些事情?

uboot.img内存分布如下:

访问 /arch/arm/lib/board.c中 的board_init_f()函数


在uboot.img运行过程中,有两个非常重要的结构体:gd_t和bd_t。

其中gd_t:global_data数据结构的定义,位于:/arch/arm/include/asm/global_data.h中。

                 其成员主要是一些全局的系统初始化参数。

其中bd_t:bd_info数据结构的定义,位于:/arch/arm/include/asm/u-boot.h中。

                 其成员是开发板的相关参数。



1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
三十
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<PATH : /arch/arm/include/asm/global_data.h >
/*
  * The following data structure is placed in some memory which is
  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
  * some locked parts of the data cache) to allow for a minimum set of
  * global variables during system initialization (until we have set
  * up the memory controller so that we can use RAM).
  *
  * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
  */
 
typedef  struct   global_data {
     bd_t        *bd;
     unsigned  long    flags;
     unsigned  long    baudrate;
     unsigned  long    have_console;    /* serial_init() was called */
     unsigned  long    env_addr;    /* Address  of Environment struct */
     unsigned  long    env_valid;   /* Checksum of Environment valid? */
     unsigned  long    fb_base;     /* base address of frame buffer */
#ifdef CONFIG_FSL_ESDHC
     unsigned  long    sdhc_clk;
#endif
#ifdef CONFIG_AT91FAMILY
     /* "static data" needed by at91's clock.c */
     unsigned  long    cpu_clk_rate_hz;
     unsigned  long    main_clk_rate_hz;
     unsigned  long    mck_rate_hz;
     unsigned  long    plla_rate_hz;
     unsigned  long    pllb_rate_hz;
     unsigned  long    at91_pllb_usb_init;
#endif
#ifdef CONFIG_ARM
     /* "static data" needed by most of timer.c on ARM platforms */
     unsigned  long    timer_rate_hz;
     unsigned  long    tbl;
     unsigned  long    tbu;
     unsigned  long  long   timer_reset_value;
     unsigned  long    lastinc;
#endif
#ifdef CONFIG_IXP425
     unsigned  long    timestamp;
#endif
     unsigned  long    relocaddr;   /* Start address of U-Boot in RAM */
     phys_size_t ram_size;    /* RAM size */
     unsigned  long    mon_len;     /* monitor len */
     unsigned  long    irq_sp;      /* irq stack pointer */
     unsigned  long    start_addr_sp;   /* start_addr_stackpointer */
     unsigned  long    reloc_off;
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
     unsigned  long    tlb_addr;
#endif
     void         **jt;        /* jump table */
     char         env_buf[32];     /* buffer for getenv() before reloc. */
} gd_t;
 
#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
 
 
<PATH : /arch/arm/include/asm/u-boot.h >
typedef  struct  bd_info {
     int          bi_baudrate;     /* serial console baudrate */
     unsigned  long    bi_ip_addr;  /* IP Address */
     ulong           bi_arch_number;  /* unique id for this board */
     ulong           bi_boot_params;  /* where this board expects params */
     struct               /* RAM configuration */
     {
     ulong start;
     ulong size;
     }           bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
其中 DECLARE_GLOBAL_DATA_PTR 宏定义在系统初始化过程中会被频繁调用


的作用英文的英文,声明GD这么一个全局的指针,这个指针指向gd_t结构体类型,并且这个GD指针是保存在ARM的R8这个寄存器里面的。


uboot.img第一个运行的文件还是start.o,其在运行访问的board_init_f()函数定义在/arch/arm/lib/board.c中:


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
<PATH : /arch/arm/lib/board.c >
void  board_init_f(ulong bootflag)
{
     bd_t *bd;
     init_fnc_t **init_fnc_ptr;
     gd_t *id;
     ulong addr, addr_sp;
 
     /* Pointer is writable since we allocated a register for it */
     gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
     /* compiler optimization barrier needed for GCC >= 3.4 */
     __asm__ __volatile__( "" : : : "memory" );
 
     memset (( void  *)gd, 0,  sizeof (gd_t));
 
         ...
}



1
2
3
4
6
7
8
9
10
11
12
13
14
15
<PATH : /include/configs/am335x_evm>
#define CONFIG_SYS_INIT_RAM_ADDR    SRAM0_START
#define CONFIG_SYS_INIT_RAM_SIZE    SRAM0_SIZE
#define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_INIT_RAM_ADDR + \
                      CONFIG_SYS_INIT_RAM_SIZE - \
                      GENERATED_GBL_DATA_SIZE)
 
<PATH : /arch/arm/include/asm/arch-ti81xx/hardware.h>
#define SRAM0_START         0x402F0400
 
<PATH : /arch/arm/include/asm/arch-ti81xx/cpu.h>
#define SRAM0_SIZE          (0x1B400) /* 109 KB */
 
<PATH : /am335x/include/generated/generic-asm-offsets.h>
#define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */


因此,系统初始化参数将会被保存在(保存MLO(SPL)文件的内存空间的)末尾2 KB处。

通过计算的gb指针指向的内存空间地址为gb = 0x4030B000

gb_t结构体中某些元素的值是来自于uboot.img的标题,这个标题的数据保存在内存的0x807FFFCO,大小为64字节


1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<PATH : /include/image.h>
/*
  * Legacy format image header,
  * all data in network byte order (aka natural aka bigendian).
  */
typedef  struct  image_header {
     uint32_t    ih_magic;    /* Image Header Magic Number    */
     uint32_t    ih_hcrc;     /* Image Header CRC Checksum    */
     uint32_t    ih_time;     /* Image Creation Timestamp */
     uint32_t    ih_size;     /* Image Data Size      */
     uint32_t    ih_load;     /* Data  Load  Address      */
     uint32_t    ih_ep;       /* Entry Point Address      */
     uint32_t    ih_dcrc;     /* Image Data CRC Checksum  */
     uint8_t     ih_os;       /* Operating System     */
     uint8_t     ih_arch;     /* CPU architecture     */
     uint8_t     ih_type;     /* Image Type           */
     uint8_t     ih_comp;     /* Compression Type     */
     uint8_t     ih_name[IH_NMLEN];   /* Image Name       */
} image_header_t;



1
2
3
4
6
7
8
<PATH : / include /configs/am335x_evm.h>
/*
  * 8MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM.
  * 64 bytes before this address should be set aside for u-boot.img's
  * header. That is 0x807FFFC0--0x80800000 should not be used for any
  * other needs.
  */
#define CONFIG_SYS_TEXT_BASE         0x80800000

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值