u-boot执行顺序start_armboot

版权声明:本文为博主原创文章,任何组织或者个人可以在任何媒介上发表或转载我的文章、图片等.且转载后必须注明出处和邮箱,博客地址(https://blog.csdn.net/u011011827),本人邮箱([email protected]) https://blog.csdn.net/u011011827/article/details/76686804

start_armboot


    init_fnc_t **init_fnc_ptr;

    /* Pointer is writable since we allocated a register for it */
    gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");

    memset ((void*)gd, 0, sizeof (gd_t));
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    memset (gd->bd, 0, sizeof (bd_t));

    gd->flags |= GD_FLG_RELOC;

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang (); 
        }   
    }   

1/init_fnc_t
typedef int (init_fnc_t) (void);
//这是一个函数类型,但是我们一般定义 是要这么定义的
//typedef int (*init_fnc_t) (void);
2/ init_fnc_t **init_fnc_ptr;
//定义了一个二级指针.
//init_fnc_t * 是个函数地址类型的指针.
//那么 init_fnc_t ** 类型是个函数地址类型的指针的地址类型.
//对应于 init_fnc_t *init_sequence[];中的  init_sequence(元素首地址),元素为 init_fnc_t * ,那么地址是 init_fnc_t **,对元素的引用是 (*init_sequence)()
3/_armboot_start
//这玩意的出处是 arch/arm/cpu/hi3531a/start.S 中的
.globl _armboot_start
_armboot_start:
在汇编中, 这仅仅是一个地址而已.也就是说将该地址标号为_armboot_start,以便后面使用,而这个地方的地址究竟为多少,则由链接器决定.
4/CONFIG_SYS_MALLOC_LEN 
//这玩意的处处是 include/configs/hi3531a.h ,值为 0x40000 + 128 * 1024 = 384KB
5/sizeof(gd_t)
gt_t 是一个结构体类型.求所占字节数的时候要考虑对齐
6/gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
//这里只是一个赋值,那么这个变量的定义在哪呢?
//在 arch/arm/lib/board.c中的 DECLARE_GLOBAL_DATA_PTR;
//#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
//这里定义了一个变量,这个变量的值在 寄存器 r8中, 在赋值后,(gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)) 的值放在 r8 中.
//求得的地址是在哪呢?这是虚拟地址还是什么地址?
80801054 <_armboot_start>:
80801054:   80800000    addhi   r0, r0, r0       2056MB
//这个 _armboot_start 为  0x80801054,大约2GB左右.肯定不是物理地址.因为我的ram没有2GB. 
/*
 * The following data structure is placed in some memory wich 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 (128) CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t)
 */

//这个结构体不在RAM中,那么在哪里?
7/__asm__ __volatile__("": : :"memory");
//memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作 废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。 
8/memset ((void*)gd, 0, sizeof (gd_t));
清gd
9/gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
赋值成员bd
10/memset (gd->bd, 0, sizeof (bd_t));
清bd
11/gd->flags |= GD_FLG_RELOC;
赋值成员flags
12/然后就是序列初始化
init_fnc_t *init_sequence[] = { 
    timer_init,     /* initialize timer before usb init */
    board_init,     /* basic board dependent setup */
//  timer_init,     /* initialize timer */
    env_init,       /* initialize environment */
    init_baudrate,      /* initialze baudrate settings */
    serial_init,        /* serial communications setup */
    console_init_f,     /* stage 1 init of console */
    display_banner,     /* say that we are here */
    dram_init,      /* configure available RAM banks */
/*  display_dram_config */
    NULL,
};
12.1/timer_init
步骤:
    1/设置时钟频率(系统控制器)
    2/设置控制器(清空)
    3/装载计数值
    4/设置控制器(启动)
12.2/board_init
步骤:
    1/选择晶振
    2/设置bd
    3/boot_flag_init//查到是spi 还是 nand
12.3/env_init
步骤:
    1/判断是spi还是nand
    2/并调用相应的函数.
    3/设置gd->env_addr为环境变量数组第一个元素的地址
12.4/init_baudrate
步骤:
    1/从环境变量中取值,得到波特率.
    2/将波特率存入gd->baudrate gd->bd->bi_baudrate
12.5/serial_init
步骤:
    1/dsiable
    2/设置波特率
    3/enable
12.6/console_init_f
步骤:
    1/gd->have_console = 1
12.7/display_banner
步骤:
    打印信息
    printf//不知道现在能不能打印出来
    debug//不知道打印到哪里
12.8/dram_init
步骤:
    设置 gd->bd->bi_dram[0]
.text           0x40800000    0x387a8
                0x40800000                __text_start = .
 arch/arm/cpu/hi3531a/start.o(.text)
 .text          0x40800000     0x28c0 arch/arm/cpu/hi3531a/start.o
                0x40800000                _start
                0x40802040                _blank_zone_start
                0x40802044                _blank_zone_end
                0x40802054                _armboot_start
                0x40802058                _bss_start
                0x4080205c                _bss_end
                0x408025e0                v7_flush_dcache_all
                0x4080268c                init_registers
13/mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,CONFIG_SYS_MALLOC_LEN);
//将 _armboot_start - CONFIG_SYS_MALLOC_LEN 到 _armboot_start 清空 ,设置为内存,由全局变量存储
14/display_flash_config (flash_init ());
//没找到flash_init 函数
//display_flash_config为打印信息函数
15/spi_flash_probe(0, 0, 0, 0); 
//spiflash = hifmc100_spi_nor_probe(&spiinfo_ex);
//drivers/mtd/spi/spi_compatible.c
//这里主要是填充一个spiflash 结构体变量
//里面做了
//1/和芯片交互,得到ids(很多身份验证码)
//2/然后和写好的表进行比较,比较之后,将读写擦除,赋值.但是只是验证是否表里有没有相应的flash
//3/填充对应的读写函数.(不根据芯片来区分)(好怪,那为什么第二步要遍历,并且赋值)

/* it is not needed in A7 in A17-A7  */
16/nand_init();        /* go init the NAND */
    /* initialize environment */
17/env_relocate ();
//从flash里面读,读出来的值更新环境变量,更新gd->env_addr

    /* IP Address */
18/gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
//得到ip
19/stdio_init ();  /* get the devices list going. */
//这是一个链表,只要是在这个链表里面的,都会被发送字符.
//新建一个stdio_init链表,并且将一些设备加入到链表里面.
20/jumptable_init ();
//gd->jt 申请内存,并填充  一些函数指针 ,填充getc 到 gd->jt[XF_getc]
//但是这些 XF_getc 是什么,并不知道
20/console_init_r ();  /* fully init console as a device */ 
//设置一些跟串口有关的 gd->jt[XF_getc]
//设置 inputdev outputdev errdev ,并将其装进 stdio_devices
    /* miscellaneous platform dependent initialisations */
21/misc_init_r ();
//setenv("verify", "n");
/* enable exceptions */
22/enable_interrupts ();

/* enable IRQ interrupts */
void enable_interrupts (void)
{
    unsigned long temp;
    __asm__ __volatile__("mrs %0, cpsr\n"
                 "bic %0, %0, #0x80\n"
                 "msr cpsr_c, %0"
                 : "=r" (temp)
                 :   
                 : "memory");
}
    /* Perform network card initialisation if necessary */

  /* Initialize from environment */
23/if ((s = getenv ("loadaddr")) != NULL) {
        load_addr = simple_strtoul (s, NULL, 16);
    }

24/if ((s = getenv ("bootfile")) != NULL) {
        copy_filename (BootFile, s, sizeof (BootFile));
    }
//一般情况下这两个环境变量不设置

25/eth_initialize(gd->bd);
//
1/新建一个链表头,mii_devs
    extern void download_boot(const int (*handle)(void));
    download_boot(NULL);
    product_control();

参考资料

_armboot_start 内容的疑问

猜你喜欢

转载自blog.csdn.net/u011011827/article/details/76686804