Lib_arm/board.c
当第一阶段的汇编部分执行完,跳到stage2时,开始执行c函数start_armboot
开头首先声明一个全局指针变量DECLARE_GLOBAL_DATA_PTR;这个宏定义在头文件include/asm-arm/global_data.h中
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
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 = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
这行是对指针的初始化。
接下来通过一个循环,执行初始化序列中的一些函数
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
初始化序列的定义如下:
init_fnc_t *init_sequence[] = {
cpu_init, //初始化cpu,主要是设置FIQ和IRQ的堆栈起始地址
board_init, //开发板初始化,设置电源、时钟、I/O端口及全能I/DCache
interrupt_init, //中断初始化,设置PWM时钟
env_init, //环境变量初始化,检测环境变量是否有效,并初始化相全局变量
init_baudrate, //初始化波特率,设置板子通信时的波特率
serial_init, //初始化串口,设置串口和通信时数据结构,包括起始/停止位等
console_init_f, //控制台初始化,将控制台设置为silent模式
display_banner,//打印板子相关信息
dram_init, //内存初始化,设置内存的起始地址和大小
display_dram_config, //显示内存配置信息
#if defined(CONFIG_VCMA9)
checkboard,
#endif
NULL,
};
这些初始化都完成后开始初始化flash
unsigned long flash_init (void)
{
unsigned long size_b0;
int i;
/* Init: no FLASHes known */
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
}
/* Static FLASH Bank configuration here - FIXME XXX */
#if 1
debug ("/n## Get flash bank 1 size @ 0x%08x/n",CFG_FLASH_BASE);
#endif
//根据flash的基地址CFG_FLASH_BASE,获得flash的大小,
size_b0 = flash_get_size((vu_short *)CFG_FLASH_BASE, &flash_info[0]);
if (flash_info[0].flash_id == FLASH_UNKNOWN) {
printf ("## Unknown FLASH on Bank 0: "
"ID 0x%lx, Size = 0x%08lx = %ld MB/n",
flash_info[0].flash_id,
size_b0, size_b0<<20);
}
//获得并保存flash各块的起始地址
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
//保存flash的大小
flash_info[0].size = size_b0;
//下面是根据配置,对flash中相应块进行保护,以免数据丢失。
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
/* monitor protection ON by default */
flash_protect(FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE+monitor_flash_len-1,
&flash_info[0]);
#endif
#ifdef CFG_ENV_IS_IN_FLASH
/* ENV protection ON by default */
flash_protect(FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1,
&flash_info[0]);
#endif
return size_b0;
}
然后是初始内存堆
static
void mem_malloc_init (ulong dest_addr)
{
mem_malloc_start = dest_addr;
mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
mem_malloc_brk = mem_malloc_start;
memset ((void *) mem_malloc_start, 0,
mem_malloc_end - mem_malloc_start);
}
之后要进行环境变量重定位,把环境变量放到内存当中
env_relocate ();
还要设置网卡的ip地址和mac地址
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
uchar tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
}
设备初始化
int devices_init (void)
{
char *s;
#ifndef CONFIG_ARM /* already relocated for current ARM implementation */
DECLARE_GLOBAL_DATA_PTR;
ulong relocation_offset = gd->reloc_off;
int i;
/* relocate device name pointers */
for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
relocation_offset);
}
#endif
/* Initialize the list */
devlist = ListCreate (sizeof (device_t));
if (devlist == NULL) {
eputs ("Cannot initialize the list of devices!/n");
return -1;
}
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD
drv_lcd_init ();
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
if ((s = getenv ("sm501mode")) != NULL)
{
sm501mode = simple_strtoul (s, NULL, 10);
if(!(sm501mode >= 1 && sm501mode <= 13))
{
printf("sm501 mode error, set sm501 mode to 1!/n");
sm501mode = 1;
}
}
if ((s = getenv ("sm501bpp")) != NULL)
{
sm501bpp = simple_strtoul (s, NULL, 10);
if(sm501mode != 16)
{
printf("sm501 bpp error, only 16bpp valid, set sm501 bpp to 16!/n");
sm501bpp = 16;
}
}
drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD
//drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
drv_logbuff_init ();
#endif
drv_system_init ();
return (0);
}
这里要创建一个设备列表,把一些设备放入这个表中,初始化i2c总线,设置sm501显卡,初始化视频设备,初始化并注册个别系统设备。
void jumptable_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
int i;
gd->jt = (void **) malloc (XF_MAX * sizeof (void *));
for (i = 0; i < XF_MAX; i++)
gd->jt[i] = (void *) dummy;
gd->jt[XF_get_version] = (void *) get_version;
gd->jt[XF_malloc] = (void *) malloc;
gd->jt[XF_free] = (void *) free;
gd->jt[XF_get_timer] = (void *)get_timer;
gd->jt[XF_udelay] = (void *)udelay;
#if defined(CONFIG_I386) || defined(CONFIG_PPC)
gd->jt[XF_install_hdlr] = (void *) irq_install_handler;
gd->jt[XF_free_hdlr] = (void *) irq_free_handler;
#endif /* I386 || PPC */
#if (CONFIG_COMMANDS & CFG_CMD_I2C)
gd->jt[XF_i2c_write] = (void *) i2c_write;
gd->jt[XF_i2c_read] = (void *) i2c_read;
#endif /* CFG_CMD_I2C */
}
初始化跳转表,主要是保存了一些系统函数的指针。便于以后引用
然后对控制台进行全面的初始化
console_init_r (); /* fully init console as a device */
主要是初始化控制台输入输出设备
接下来开中断
/* enable exceptions */
enable_interrupts ();
初始化网卡设备等
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_DM9000
DM9000_get_enetaddr (gd->bd->bi_enetaddr);
#endif
最后进入主循环
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
在这个循环中,将检测是自动启动还是命令行起动。起动后,uboot的stage2也就结束了