start_armboot函数在lib_arm/board.c中定义,是U-Boot第二阶段代码的入口。U-Boot启动第二阶段流程如下:
图 2.3 U-Boot第二阶段执行流程
在分析start_armboot函数前先来看看一些重要的:
(1)gd_t结构体
U-Boot使用了一个结构体gd_t来存储全局数据区的数据,这个结构体在include/asm-arm/global_data.h中定义如下:
-
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 */
-
-
void **jt; /* jump table */
-
-
} gd_t;
U-Boot使用了一个存储在寄存器中的指针gd来记录全局数据区的地址:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
DECLARE_GLOBAL_DATA_PTR定义一个gd_t全局数据结构的指针,这个指针存放在指定的寄存器r8中。这个声明也避免编译器把r8分配给其它的变量。任何想要访问全局数据区的代码,只要代码开头加入“DECLARE_GLOBAL_DATA_PTR”一行代码,然后就可以使用gd指针来访问全局数据区了。
根据U-Boot内存使用图中可以计算gd的值:
gd = TEXT_BASE -CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)
(2)bd_t结构体
bd_t在include/asm-arm.u/u-boot.h中定义如下:
-
typedef struct bd_info {
-
-
int bi_baudrate; /* 串口通讯波特率 */
-
-
unsigned long bi_ip_addr; /* IP 地址*/
-
-
struct environment_s *bi_env; /* 环境变量开始地址 */
-
-
ulong bi_arch_number; /* 开发板的机器码 */
-
-
ulong bi_boot_params; /* 内核参数的开始地址 */
-
-
struct /* RAM配置信息 */
-
-
{
-
-
ulong start;
-
-
ulong size;
-
-
}bi_dram[CONFIG_NR_DRAM_BANKS];
-
-
} bd_t;
U-Boot启动内核时要给内核传递参数,这时就要使用gd_t,bd_t结构体中的信息来设置标记列表。
(3)init_sequence数组
U-Boot使用一个数组init_sequence来存储对于大多数开发板都要执行的初始化函数的函数指针。init_sequence数组中有较多的编译选项,去掉编译选项后init_sequence数组如下所示:
-
typedef int (init_fnc_t) (void);
-
-
-
-
init_fnc_t *init_sequence[] = {
-
-
board_init, /*开发板相关的配置--board/samsung/mini2440/mini2440.c */
-
-
timer_init, /* 时钟初始化-- cpu/arm920t/s3c24x0/timer.c */
-
-
env_init, /*初始化环境变量--common/env_flash.c 或common/env_nand.c*/
-
-
init_baudrate, /*初始化波特率-- lib_arm/board.c */
-
-
serial_init, /* 串口初始化-- drivers/serial/serial_s3c24x0.c */
-
-
console_init_f, /* 控制通讯台初始化阶段1-- common/console.c */
-
-
display_banner, /*打印U-Boot版本、编译的时间-- gedit lib_arm/board.c */
-
-
dram_init, /*配置可用的RAM-- board/samsung/mini2440/mini2440.c */
-
-
display_dram_config, /* 显示RAM大小-- lib_arm/board.c */
-
-
NULL,
-
-
};
其中的board_init函数在board/samsung/mini2440/mini2440.c中定义,该函数设置了MPLLCOM,UPLLCON,以及一些GPIO寄存器的值,还设置了U-Boot机器码和内核启动参数地址 :
/* MINI2440开发板的机器码 */
gd->bd->bi_arch_number = MACH_TYPE_MINI2440;
/* 内核启动参数地址 */
gd->bd->bi_boot_params = 0x30000100;
其中的dram_init函数在board/samsung/mini2440/mini2440.c中定义如下:
-
int dram_init (void)
-
-
{
-
-
/* 由于mini2440只有 */
-
-
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
-
-
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
-
-
-
-
return 0;
-
-
}
mini2440使用2片32MB的SDRAM组成了64MB的内存,接在存储控制器的BANK6,地址空间是0x30000000~0x34000000。
在include/configs/mini2440.h中PHYS_SDRAM_1和PHYS_SDRAM_1_SIZE 分别被定义为0x30000000和0x04000000(64M)。
分析完上述的数据结构,下面来分析start_armboot函数:
-
void start_armboot (void)
-
-
{
-
-
init_fnc_t **init_fnc_ptr;
-
-
char *s;
-
-
… …
-
-
/* 计算全局数据结构的地址gd */
-
-
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
-
-
… …
-
-
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;
-
-
-
-
monitor_flash_len = _bss_start - _armboot_start;
-
-
-
-
/* 逐个调用init_sequence数组中的初始化函数 */
-
-
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
-
-
if ((*init_fnc_ptr)() != 0) {
-
-
hang ();
-
-
}
-
-
}
-
-
-
-
/* armboot_start 在cpu/arm920t/start.S 中被初始化为u-boot.lds连接脚本中的_start */
-
-
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
-
-
CONFIG_SYS_MALLOC_LEN);
-
-
-
-
/* NOR Flash初始化 */
-
-
#ifndef CONFIG_SYS_NO_FLASH
-
-
/* configure available FLASH banks */
-
-
display_flash_config (flash_init ());
-
-
#endif /* CONFIG_SYS_NO_FLASH */
-
-
-
-
… …
-
-
/* NAND Flash 初始化*/
-
-
#if defined(CONFIG_CMD_NAND)
-
-
puts ("NAND: ");
-
-
nand_init(); /* go init the NAND */
-
-
#endif
-
-
… …
-
-
/*配置环境变量,重新定位 */
-
-
env_relocate ();
-
-
… …
-
-
/* 从环境变量中获取IP地址 */
-
-
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
-
-
stdio_init (); /* get the devices list going. */
-
-
jumptable_init ();
-
-
… …
-
-
console_init_r (); /* fully init console as a device */
-
-
… …
-
-
/* enable exceptions */
-
-
enable_interrupts ();
-
-
-
-
#ifdef CONFIG_USB_DEVICE
-
-
usb_init_slave();
-
-
#endif
-
-
-
-
/* Initialize from environment */
-
-
if ((s = getenv ("loadaddr")) != NULL) {
-
-
load_addr = simple_strtoul (s, NULL, 16);
-
-
}
-
-
#if defined(CONFIG_CMD_NET)
-
-
if ((s = getenv ("bootfile")) != NULL) {
-
-
copy_filename (BootFile, s, sizeof (BootFile));
-
-
}
-
-
#endif
-
-
… …
-
-
/* 网卡初始化 */
-
-
#if defined(CONFIG_CMD_NET)
-
-
#if defined(CONFIG_NET_MULTI)
-
-
puts ("Net: ");
-
-
#endif
-
-
eth_initialize(gd->bd);
-
-
… …
-
-
#endif
-
-
-
-
/* main_loop() can return to retry autoboot, if so just run it again. */
-
-
for (;;) {
-
-
main_loop ();
-
-
}
-
-
/* NOTREACHED - no way out of command loop except booting */
-
-
}
main_loop函数在common/main.c中定义。一般情况下,进入main_loop函数若干秒内没有
阅读(827) | 评论(0) | 转发(1) |