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 内容的疑问