初始化部分代码-board.c
由汇编部分转入C语言后第一个执行这个文件中的start_armboot ()函数。
部分代码分析如下:
typedef int (init_fnc_t) (void); // 定义函数类型
// 下面为初始化函数定义
init_fnc_t *init_sequence[] = {
cpu_init, // cp/pxa/cpu.c文件, 执行CPU相关的初始化.
board_init, // board/psbec270/board.c文件, 执行board相关的初始化.
interrupt_init, // cp/pxa/interrupt.c文件, 中断初始化, 一般不需要使用中断.
env_init, // 环境变量初始化
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,
#if defined(CONFIG_VCMA9)
checkboard,
#endif
NULL,
};
// 在start_armboot()函数中实现如下代码, 用于执行上面定义的初始函数.
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
接下来就是一些系统中用到的环境,变量等初始化,最后进入主循环, 下面是具体分析:
typedef int (init_fnc_t) (void);
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
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,
};
// 全局数据结构信息
typedef struct global_data {
bd_t *bd; // 开发板相关参数
unsigned long flags;
unsigned long baudrate; // 串行口通讯速率
unsigned long have_console; // console_init_f()中使用控制台
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
void **jt; // jumptable_init()初始化
} gd_t;
// 开发板相关的信息
typedef struct bd_info {
int bi_baudrate; // serial通讯接口的速率
unsigned long bi_ip_addr; // 本机IP地址
unsigned char bi_enetaddr[6]; // MAC地址
struct environment_s *bi_env; // 环境变量
ulong bi_arch_number; // 开发板ID
/*
该变量标识每一种开发板相关的ID号, 对于本系统来说:
gd->bd->bi_arch_number = MACH_TYPE_MAINSTONE;
该值将传递给内核, 如果这个参数与内核配置的不相同, 那么内核启动解压缩完成后将出现”Error: a”错误, 提示用户这个是体系结构参数传递的不正确. 由于本开发板内核是从Intel的mainstone开发板内核修改而来, 内部的配置都是使用的MAINSTONE开发板的参数, 故这里将ARCH设置为MACH_TYPE_MAINSTONE.
*/
ulong bi_boot_params; // Uboot传递给linux内核的参数保存地址
/*
该变量在board/psbec270/psbec270.c中的int board_init(void)中赋值, 这个值的定义是:
gd->bd->bi_boot_params = 0xA0000100;
该变量保存了Uboot传递给linux的参数的地址, 在linux的引导过程中,
head.s文件中没有对传递进来的参数进行处理, 在init/main.c文件中的
start_kernel函数中, 进行解析.
*/
struct // RAM configuration
{
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
/*
SDram设置, 可以存在多个bank, 由宏定义
CONFIG_NR_DRAM_BANKS决定.
board/psbec270/psbec270.c文件中dram_init()执行RAM初始化
int dram_init(void)
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
*/
} bd_t;
void start_armboot (void)
{
DECLARE_GLOBAL_DATA_PTR;
// #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
ulong size;
init_fnc_t **init_fnc_ptr;
char *s;
// gd分配内存在空闲区(直接地址引用)
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
// 给gd分配内存, 这里是在uboot使用的前面, 属于空闲内存.
memset ((void*)gd, 0, sizeof (gd_t));
// bd分配内存在空闲区, gd的低端(直接地址引用)
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;// 受监控flash空间大小
// 初始化函数, 见上面定义的函数数组, 其中有几个是开发板相关的.
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 (); // flash初始化
display_flash_config (size);
/* armboot_start is defined in the board-specific linker script */
// malloc使用的内存空间
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
// 如果有nandflash的话就在下面的代码中进行初始化.
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* go init the NAND */
#endif
env_relocate (); // 执行环境初始化
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); // 环境变量中获得本机IP
// 获得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 (); // 设备初始化
jumptable_init (); // 给gd->jt分配内存, 然后加入相关的执行函数
console_init_r (); // fully init console as a device
enable_interrupts ();
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
board_late_init ();
/* 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 */
}
(本文章发表于psbec的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如有任何问题,请留言或者发邮件给psbec,地址)