分类: LINUX
2012-02-11 12:10:31
看完初始化函数表,我们在顺着启动流程继续往下看,在来回顾下start_armboot的代码
lib_arm/Board.c:
void start_armboot (void)
{
……
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#ifdef CONFIG_VFD //smdk2410没定义
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD //smdk2410没定义
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = lcd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_LCD */
……
}
我们接着看flash_init:
board/smdk2410/flash.c:
ulong flash_init (void)
{
int i, j;
ulong size = 0;
for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
ulong flashbase = 0;
flash_info[i].flash_id = /*保存flash ID*/
#if defined(CONFIG_AMD_LV400)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
#endif
/*保存每个flash blank的大小,sector数量,起始地址等信息*/
flash_info[i].size = FLASH_BANK_SIZE;
flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
if (i == 0)
flashbase = PHYS_FLASH_1;
else
panic ("configured too many flash banks!/n");
for (j = 0; j < flash_info[i].sector_count; j++) {
/*为每个sector分配不同的大小,作为不同的用途*/
if (j <= 3) {
/* 1st one is 16 KB */
if (j == 0) {
flash_info[i].start[j] =
flashbase + 0;
}
/* 2nd and 3rd are both 8 KB */
if ((j == 1) || (j == 2)) {
flash_info[i].start[j] =
flashbase + 0x4000 + (j -
1) *
0x2000;
}
/* 4th 32 KB */
if (j == 3) {
flash_info[i].start[j] =
flashbase + 0x8000;
}
} else {
flash_info[i].start[j] =
flashbase + (j - 3) * MAIN_SECT_SIZE;
}
}
size += flash_info[i].size;
}
//对flash上保存有RO, RW的地方进行保护,monitor_flash_len = RO + RW的长度
flash_protect (FLAG_PROTECT_SET,
CFG_FLASH_BASE,
CFG_FLASH_BASE + monitor_flash_len - 1,
&flash_info[0]);
//对flash上保存有环境变量的地方进行保护
flash_protect (FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
return size;
}
该函数就是记录下flash的大小,数量,sector的大小数量等,并对flash上重要的数据进行保护。
继续看display_flash_config()
lib_arm/board.c:
static void display_flash_config (ulong size)
{
puts ("Flash: ");
print_size (size, "/n");
}
很简单,打印flash的大小信息。
继续看start_armboot()接下来要初始化的东西:
lib_arm/Board.c:
void start_armboot (void)
{
……
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* go init the NAND */
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
/* IP Address */
/*从环境变量中获取IP地址*/
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
/*从环境变量中获取MAC地址*/
{
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;
}
}
devices_init (); /* get the devices list going. */
jumptable_init ();
console_init_r (); /* fully init console as a device */
……
}
接着看mem_malloc_init()
lib_arm/board.c:
/*
* Begin and End of memory area for malloc(), and current "brk"
*/
static ulong mem_malloc_start = 0;
static ulong mem_malloc_end = 0;
static ulong mem_malloc_brk = 0;
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);
}
这个函数就是保存malloc区域的起始地址,结束地址,并清0这块区域, 这块区域在RAM中的具体位置可查看上面的图。
接着看env_relocate
common/env_common.c:
void env_relocate (void)
{
DECLARE_GLOBAL_DATA_PTR; /*定义一个gd_t对象指向ram中的gd_t区域*/
DEBUGF ("%s[%d] offset = 0x%lx/n", __FUNCTION__,__LINE__,
gd->reloc_off);
#ifdef CONFIG_AMIGAONEG3SE
enable_nvram();
#endif
/*env_ptr指向存放环境变量的区域*/
#ifdef ENV_IS_EMBEDDED
/*
* The environment buffer is embedded with the text segment,
* just relocate the environment pointer
*/
env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
DEBUGF ("%s[%d] embedded ENV at %p/n", __FUNCTION__,__LINE__,env_ptr);
#else
/*
* We must allocate a buffer for the environment
*/
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
DEBUGF ("%s[%d] malloced ENV at %p/n", __FUNCTION__,__LINE__,env_ptr);
#endif
/*
* After relocation to RAM, we can always use the "memory" functions
*/
env_get_char = env_get_char_memory;
/*
* 如果在env_init中没有初始化合适的环境变量则使用默认的环境变量来作为环境变量值
* 否则使用env_init中定义好的环境变量值
*/
if (gd->env_valid == 0) {
#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */
puts ("Using default environment/n/n");
#else
puts ("*** Warning - bad CRC, using default environment/n/n");
SHOW_BOOT_PROGRESS (-1);
#endif
if (sizeof(default_environment) > ENV_SIZE)
{
puts ("*** Error - default environment is too large/n/n");
return;
}
memset (env_ptr, 0, sizeof(env_t));
memcpy (env_ptr->data,
default_environment,
sizeof(default_environment)); /*把默认值存入RAM相应区域*/
#ifdef CFG_REDUNDAND_ENVIRONMENT
env_ptr->flags = 0xFF;
#endif
env_crc_update (); /*更新crc校验值*/
gd->env_valid = 1; /*标记环境变量有效*/
}
else {
env_relocate_spec ();
}
gd->env_addr = (ulong)&(env_ptr->data);
#ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}
该函数重新分配了一块区域用于存放环境变量,并在gd_t区域保存了这个地址值。
接着看devices_init:
common/Devices.c:
int devices_init (void)
{
#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 */
/*创建一个保存device的列表*/
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)
drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD
drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
drv_logbuff_init ();
#endif
drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI
serial_devices_init ();
#endif
#ifdef CONFIG_USB_TTY
drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
drv_nc_init ();
#endif
return (0);
}
这个函数实际上就是根据板子的配置初始化各种设备,并调用device_register()注册到系统中去,这里我们以drv_system_init为例解释一下,其他代码类似。
common/Devices.c:
/**************************************************************************
* SYSTEM DRIVERS
**************************************************************************
*/
static void drv_system_init (void)
{
device_t dev;
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "serial"); /*串口设备*/
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; /*设备属性*/
/*注册设备操作函数集(输入函数,输出函数等)*/
#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
dev.putc = serial_buffered_putc;
dev.puts = serial_buffered_puts;
dev.getc = serial_buffered_getc;
dev.tstc = serial_buffered_tstc;
#else
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
#endif
/*把该设备注册进系统中去,即把dev添加进上面创建的设备列表中去*/
device_register (&dev);
/*注册一个空设备*/
#ifdef CFG_DEVICE_NULLDEV
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "nulldev");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = nulldev_putc;
dev.puts = nulldev_puts;
dev.getc = nulldev_input;
dev.tstc = nulldev_input;
device_register (&dev);
#endif
}
该函数注册了一个串口设备和一个空设备(根据配置而定)。其他的设备初始化函数以此大同小异,主要就是初始化好相关设备的设备信息,并注册到系统中去,详细代码大家可以自己去分析。
接下来看jumptable_init
common/exports.c:
void jumptable_init (void)
{
DECLARE_GLOBAL_DATA_PTR; /*这个还用说吗?*/
int i;
/*分配一块buffer用于存放跳转函数地址*/
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 */
}
可以看出该函数主要就是为不同的功能安装了不同的功能函数。