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

u-boot简介

简单的说,u-boot的核心功能是加载内核。 
为什么需要它,上电之后直接加载内核不可以吗? 
虽然目前的内核没有这么做且理论上也可以实现,但没有必要这么做。 
这就类似于几十万大军在行军,通常的做法是派出几千人的不断在前面探路,而非几十万大军一股脑的往前走。 
总结一下,u-boot的作用,初始化各类的硬件,加载内核,在加载内核的同时,把硬件的基本信息通过参数的形式传递给内核。

启动过程

AM335x通常的启动分为三个阶段,ROM Code、SPL、u-boot,最终加载内核。

ROM Code

顾名思义,这块的代码是TI内置的。上电后,硬件去加载该代码。这块的代码作用,是根据启动选项来从不同的启动源启动。目前支持的启动源有MMC、Nand、Uart、USB、net等方式。如,我们的项目用的Nand,ROM Code运行后,会初始化Nand,然后在Nand的0x0的位置加载下一阶段的代码,即SPL的代码。把SPL的代码,加载到内部存储器中运行。

SPL

SPL和MLO有什么区别,可以认为是没有区别。具体的区别是SPL代码中包含了调试等描述信息,MLO作为裁剪后的代码,烧写进Nand中。最大的疑问是,为什么需要SPL阶段,直接ROM Code启动u-boot不是更快吗?因为硬件,目前,ROM Code只能把代码加载到内部存储器中运行,而内部存储器资源非常有限,运行不了正常的u-boot,所以先运行精简版的u-boot,再去加载正常的u-boot。 
所以,SPL阶段的使命很明确,初始化外存,加载u-boot到外存。

u-boot

不必多言了,这就是正常的u-boot,一是提供交互界面,供用户进行配置;二是初始化硬件环境加载内核运行。当然,核心功能上面也说了,是加载内核。

另外,目前AM335x也支持Falcon模式,在该模式下,SPL直接加载内核启动,后面会有详细的介绍。

本文转载自donglicaiju76152的博客:https://blog.csdn.net/donglicaiju76152/article/details/77917196

参考文件:

1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.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的 Internal SRAM 中。

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

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

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

MLO(SPL)内存分布如下:

SPL内存重映射:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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

5

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

5

6

7

<PATH : /arch/arm/cpu/armv7/start.S>

/*

 * the actual reset code

 */

reset:

    bl  save_boot_params

1

2

3

4

5

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

5

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 中:

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

    @a2@ 设置 CPU 为 SVC32 模式

1

2

3

4

5

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

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

CPSR格式如下所示。SPSR和CPSR格式相同。
31 30 29 28 27 26 7 6 5 4 3 2 1 0
N Z C V Q DNM(RAZ) I F T M4 M3 M2 M1 M0

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

    @a3@ CPU的初始化

1

2

3

4

5

《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

5

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

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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

5

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

5

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

5

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

5

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

5

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

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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

5

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

5

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

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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@ 设置 internal RAM 内存空间的栈指针,调用 board_init_f()函数

1

2

3

4

5

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

5

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

5

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

5

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 Flash 和Nand Flash 本质区别就在于是否进行代码拷贝,也就是下面代码所表述:无论
是Nor Flash 还是Nand Flash,核心思想就是将 uboot 代码搬运到内存中去运行,但是没有拷
贝bss 后面这段代码,只拷贝bss 前面的代码,bss 代码是放置全局变量的。Bss 段代码是为
了清零,拷贝过去再清零重复操作。

1

2

3

4

5

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

5

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

5

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

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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

5

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

5

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's header,这个header的数据保存在内存的0x807FFFCO,大小为 64字节

1

2

3

4

5

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

5

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

AM335x启动流程(BootRom-MLO-Uboot)相关推荐

  1. AM335x启动流程(bootrom)

    参考文件: 1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf: 2,am3359.pdf: 1, ...

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

    http://blog.chinaunix.net/uid-28458801-id-3486399.html 参考文件: 1,AM335x ARM Cortex-A8微处理器(MPU)技术参考手册.p ...

  3. AM335x启动流程(BootRom-MLO-Uboot)超详细源码分析

    转载地址:https://blog.csdn.net/p942005405/article/details/83376464 写的非常好,收藏学习 参考文件: 1,AM335x ARM Cortex- ...

  4. AM335x启动流程

    写的非常好,收藏学习 参考文件: 1,AM335x ARM Cortex-A8 Microprocessors (MPUs) Technical Reference Manual.pdf: 2,am3 ...

  5. ARMv8架构u-boot启动流程详细分析(二)

    文章目录 1 u-boot在汇编启动阶段对系统的一些初始化 1.1 启动前为后续流程做的一些平台相关操作 1.2 开启地址无关后的重定位地址操作 1.3 进入_main之前系统寄存器初始化和从核的引导 ...

  6. U-Boot启动流程详解

    参考:U-Boot顶层目录链接脚本文件(u-boot.lds)介绍 作者:一只青木呀 发布时间: 2020-10-23 13:52:23 网址:https://blog.csdn.net/weixin ...

  7. S5PV210 Uboot开发与移植03:Uboot启动流程详解

    目录 1. start.S解析 1.1 uboot入口分析 1.2 头文件包含 1.2.1 config.h 1.2.2 version.h 1.2.3 asm/proc/domain.h 1.2.4 ...

  8. 【正点原子Linux连载】第三十二章 U-Boot启动流程详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  9. ARMv8架构u-boot启动流程详细分析(一)

    文章目录 1 概述 2 armv8 u-boot的启动 3 u-boot源码整体结构和一些编译配置方式 3.1 编译配置方式 3.2 u-boot源码结构 4 u-boot armv8链接脚本 4.1 ...

最新文章

  1. 出现link错误,说找不到IPHlpApi.Lib(VC6.0)
  2. werkzeug中服务器处理请求的实现
  3. Solr配置与简单Demo[转]
  4. vscode快捷操作
  5. 4、以太网基础知识——ICMP协议详解
  6. SpringBoot 集成Web
  7. 模块间holder的Boost.Flyweight测试
  8. JDK10的新特性:本地变量类型var
  9. 【NLP】毕设学习笔记(一):词袋模型、主题模型、词嵌入
  10. iOS最为简单时间轴(GZTimeLine)
  11. opencv 2d直方图
  12. percona mysql 同步_Percona MySQL5.6 半同步复制
  13. html网站地图在线生成,网站地图(sitemap)在线制作工具
  14. 【重点递归】剑指offer——面试题18:树的子结构
  15. BZOJ1969 [AHIO2005]航线规划
  16. java 文件读取大全
  17. VBS中实现99乘法表的输出
  18. AR入门之动画的制作与导入
  19. class path resource [applicationContext.xml] cannot be opened because it does not exist,jar包缺失
  20. 载誉而归!昂视荣膺CAIMRS 2023「自动化创新奖」

热门文章

  1. 基于android的美食食谱分享推荐系统app
  2. printf函数输出问题
  3. 踩坑sunbeam rbt 去除host reads
  4. html5图片并列排版,小编,图片与文字并排怎么排版呢?
  5. GRAIL Efficient Time Series Representation Learning论文阅读笔记(一)
  6. 2022工作中遇到的问题二
  7. 微软一个罕为人知的无敌命令
  8. 微信小程序中的授权、登录注册token和code
  9. Java毕设项目:房屋租赁管理系统(java+SSM+Maven+Mysql+Jsp)
  10. TypeScript:Aho–Corasick算法实现敏感词过滤