Stage II过程分析
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long reloc_off; /* Relocation Offset */
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_VFD
unsigned char vfd_type; /* display type */
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
unsigned long ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */
#endif
void **jt; /* jump table */
} gd_t;
gd_t数据结构在include/asm-arm/global_data.h中定义,它用来存储全局数据区的数据。
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
U-Boot中使用了一个存储在寄存器中的指针gd来记录全局数据区的地址。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)。
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
unsigned char bi_enetaddr[6]; /* Ethernet adress */
struct environment_s *bi_env;
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];
#ifdef CONFIG_HAS_ETH1
/* second onboard ethernet port */
unsigned char bi_enet1addr[6];
#endif
} bd_t;
db_t数据结构在include/asm-arm/u-boot.h中定义。U-Boot启动内核时要给内核传递参数,这时就要使用gd_t,db_t结构体中的信息来设置标记列表。
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup 基本的处理器相关配置 --cpu/arm920t/cpu.c */
board_init, /* basic board dependent setup 基本的板级相关配置 --board/smdk2410/smdk2410.c */
interrupt_init, /* set up exceptions 初始化中断处理 --cpu/arm920t/s3c24x0/interrupts.c */
env_init, /* initialize environment 初始化环境变量 --common/env_flash.c */
init_baudrate, /* initialze baudrate settings 初始化波特率设置 --lib_arm/board.c */
serial_init, /* serial communications setup 串口通讯设置 --cpu/arm920t/serial.c */
console_init_f, /* stage 1 init of console 控制台初始化阶段1 -- common/console.c */
display_banner, /* say that we are here 打印U-Boot版本、编译的时间 --lib_arm/board.c */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
dram_init, /* configure available RAM banks 配置可用的RAM --board/smdk2410/smdk2410.c */
/*
* 在这里开始进行配置SDRAM信息,用到结构体 bd->bi_dram[BANK_NR].start bd->bi_dram[BANK_NR].size bd->bi_dram[BANK_NR].size
*/
display_dram_config, /* 显示SDRAM的配置信息 --lib_arm/board.c */
NULL,
};
U-Boot使用一个数组init_sequence来存储对于大多数开发板都要执行的函数指针。
int cpu_init (void)
{
/*
* setup up stacks if necessary
*/
#ifdef CONFIG_USE_IRQ
IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
return 0;
}
其中的cpu_init函数在cpu/arm920t/cpu.c中定义。
int board_init (void)
{
..............
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* SMDK2410开发板的机器码(板子ID) */
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100; /* 内核启动参数地址(绝对地址) */
.............
}
board_init设置了U-Boot机器码和内核启动参数地址。
/* 初始化内存RAM的信息,其实就是给gd->bd中内存信息表赋值而已 */
int dram_init (void)
{
/* 设置板级数据中的SDRAM开始地址和大小 */
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
return 0;
}
分析完上述数据结构,下面接着来分析Stage II入口函数start_armboot(实现在lib-arm/board.c中):