全部博文(668)
分类:
2008-05-31 08:44:23
vivi第二阶段相关的代码如下,里面加有自己的部分注释:
同一般的c语言程序一样,
第一步:vivi从main()函数开始执行,该函数在/init/main.c中,总共可以分为8个步骤,函数开始通过putstr (vivi_bannner)打印出vivi的版本。vivi_banner在/init/version.c中定义。reset_handler函数将内存清零,在/lib/reset_handle.c文件中定义。
putstr("\r\n");
putstr(vivi_banner);
reset_handler();
第二步:对开发板进行定义(board_init),这个函数是与开发板紧密相关的,在/arch/../smdk里面。主要完成两个功能时钟初始化(init_time)和通用I/O口设置(set_gpios):
ret = board_init();
GPFDAT = 0x20;
if (ret) {
putstr("Failed a board_init() procedure\r\n");
error();
board_init函数:
int board_init(void)
{
init_time();
set_gpios();
return 0;
}
init_time函数:
void init_time(void)
{
TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));
}
set_gpios函数:
void set_gpios(void)
{
GPACON = vGPACON;
GPBCON = vGPBCON;
GPBUP = vGPBUP;
GPCCON = vGPCCON;
GPCUP = vGPCUP;
GPDCON = vGPDCON;
GPDUP = vGPDUP;
GPECON = vGPECON;
GPEUP = vGPEUP;
GPFCON = vGPFCON;
GPFUP = vGPFUP;
GPGCON = vGPGCON;
GPGUP = vGPGUP;
GPHCON = vGPHCON;
GPHUP = vGPHUP;
EXTINT0 = vEXTINT0;
EXTINT1 = vEXTINT1;
EXTINT2 = vEXTINT2;
}
第三步:进行内存映射初始化和内存管理单元的初始化工作。
mem_map_init();
mmu_init();
mem_map_init函数:
void mem_map_init(void)
{
#ifdef CONFIG_S3C2440_NAND_BOOT
mem_map_nand_boot(); //若配置vivi时使用了NAND作为启动设备,则执行
#else
mem_map_nor(); //否则执行此处
#endif
cache_clean_invalidate();
tlb_invalidate();
}
mmu_init函数:
void mmu_init(void)
{
arm920_setup();
}
注意:使用nor启动,则必须先把vivi代码复制到RAM中。这个过程是通过copy_vivi_to_ram函数搞定的。VIVI_RAM_BASE,VIVI_ROM_BASE, VIVI_RAM_SIZE。。这些值可以在smdk2410.h查到。在移植vivi的时候这个需要根据不同的开发板进行修改。。
copy_vivi_to_ram函数:
static void copy_vivi_to_ram(void)
{
putstr_hex("Evacuating 1MB of Flash to DRAM at 0x", VIVI_RAM_BASE);
memcpy((void *)VIVI_RAM_BASE, (void *)VIVI_ROM_BASE, VIVI_RAM_SIZE);
}
arm920_setup函数:由于不同处理器的寄存器不同。所以这段代码也不是通用的。该函数是针对arm920T核的处理器。里面有原作者的注释:
static inline void arm920_setup(void)
{
unsigned long ttb = MMU_TABLE_BASE;
__asm__(
/* Invalidate caches */
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c7, 0\n" /* invalidate I,D caches on v4 */
"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */
"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate I,D TLBs on v4 */
/* Load page table pointer */
"mov r4, %0\n"
"mcr p15, 0, r4, c2, c0, 0\n" /* load page table pointer */
/* Write domain id (cp15_r3) */
"mvn r0, #0\n" /* Domains 0, 1 = client */
"mcr p15, 0, r0, c3, c0, 0\n" /* load domain access register */
/* Set control register v4 */
"mrc p15, 0, r0, c1, c0, 0\n" /* get control register v4 */
/* Clear out 'unwanted' bits (then put them in if we need them) */
/* .RVI ..RS B... .CAM */
"bic r0, r0, #0x3000\n" /* ..11 .... .... .... */
"bic r0, r0, #0x0300\n" /* .... ..11 .... .... */
"bic r0, r0, #0x0087\n" /* .... .... 1... .111 */
/* Turn on what we want */
/* Fault checking enabled */
"orr r0, r0, #0x0002\n" /* .... .... .... ..1. */
#ifdef CONFIG_CPU_D_CACHE_ON
"orr r0, r0, #0x0004\n" /* .... .... .... .1.. */
#endif
#ifdef CONFIG_CPU_I_CACHE_ON
"orr r0, r0, #0x1000\n" /* ...1 .... .... .... */
#endif
/* MMU enabled */
"orr r0, r0, #0x0001\n" /* .... .... .... ...1 */
"mcr p15, 0, r0, c1, c0, 0\n" /* write control register */
: /* no outputs */
: "r" (ttb) );
}
第四步:初始化堆,然后内存会发生变化。
ret = heap_init();
if (ret) {
putstr("Failed initailizing heap region\r\n");
error();
}
heap_init函数:
int heap_init(void)
{
return mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);
}
mmalloc_init函数:
static inline int mmalloc_init(unsigned char *heap, unsigned long size)
{
if (gHeapBase != NULL) return -1;
DPRINTK("malloc_init(): initialize heap area at 0x%08lx, size = 0x%08lx\n",
heap, size);
gHeapBase = (blockhead *)(heap);
gHeapBase->allocated=FALSE;
gHeapBase->signature=BLOCKHEAD_SIGNATURE;
gHeapBase->next=NULL;
gHeapBase->prev=NULL;
gHeapBase->size = size - sizeof(blockhead);
return 0;
}
第五步:初始化mtd设备,
ret = mtd_dev_init();
mtd_dev_init函数:
int mtd_dev_init(void)
{
int ret = 0;
#ifdef CONFIG_DEBUG
printk("Initialize MTD device\n");
#endif
ret = mtd_init();
add_command(&flash_cmd);
return ret;
}
第六步:参数处理,init_priv_data函数。它将启动内核的命令参数取出并存放在指定的内存中。这些参数包括vivi的默认参数核用户存放在NANDFlash上的参数。init_priv_data首先读取默认参数,存放在 VIVI_PRIV_RAM_BASE开始的内存上;然后读取用户参数,如果读取成功则原来的默认参数被用户参数覆盖,执行完此函数后,内存也将发生变化。
init_priv_data函数:
int init_priv_data(void)
{
int ret_def;
#ifdef CONFIG_PARSE_PRIV_DATA
int ret_saved;
#endif
ret_def = get_default_priv_data();
#ifdef CONFIG_PARSE_PRIV_DATA
ret_saved = load_saved_priv_data();
if (ret_def && ret_saved) {
printk("Could not found vivi parameters.\n");
return -1;
} else if (ret_saved && !ret_def) {
printk("Could not found stored vivi parameters.");
printk(" Use default vivi parameters.\n");
} else {
printk("Found saved vivi parameters.\n");
}
#else
if (ret_def) {
printk("Could not found vivi parameters\n");
return -1;
} else {
printk("Found default vivi parameters\n");
}
#endif
#ifdef CONFIG_DEBUG_VIVI_PRIV
display_param_tlb();
display_mtd_partition();
#endif
return 0;
}
第七步:初涉化内置命令,init_builtin_cmds(),通过add_command函数,加载vivi内置的几个命令。
misc();
init_builtin_cmds();
misc函数:
int misc(void)
{
add_command(&cpu_cmd);
return 0;
}
add_command函数:
void add_command(user_command_t *cmd)
{
if (head_cmd == NULL) {
head_cmd = tail_cmd = cmd;
} else {
tail_cmd->next_cmd = cmd;
tail_cmd = cmd;
}
/*printk("Registered '%s' command\n", cmd->name);*/
}
init_builtin_cmds函数:
/* Register basic user commands */
int init_builtin_cmds(void)
{
#ifdef CONFIG_DEBUG
printk("init built-in commands\n");
#endif
#ifdef CONFIG_CMD_AMD_FLASH
add_command(&amd_cmd);
#endif
#ifdef CONFIG_TEST
add_command(&test_cmd);
#endif
#ifdef CONFIG_CMD_PROMPT
add_command(&prompt_cmd);
#endif
#ifdef CONFIG_CMD_SLEEP
add_command(&sleep_cmd);
#endif
#ifdef CONFIG_CMD_BONFS
add_command(&bon_cmd);
#endif
add_command(&reset_cmd);
#ifdef CONFIG_CMD_PARAM
add_command(¶m_cmd);
#endif
#ifdef CONFIG_CMD_PART
add_command(&part_cmd);
#endif
#ifdef CONFIG_CMD_MEM
add_command(&mem_cmd);
#endif
add_command(&load_cmd);
add_command(&go_cmd);
add_command(&dump_cmd);
add_command(&call_cmd);
add_command(&boot_cmd);
add_command(&help_cmd);
return 0;
}
第八步:进入bootloader的两种模式之一:人机接口或直接引导内核,boot_or_vivi
boot_or_vivi函数:
void boot_or_vivi(void)
{
char c;
int ret;
ulong boot_delay;
#if 0
boot_delay = get_param_value("boot_delay", &ret);
if (ret) boot_delay = DEFAULT_BOOT_DELAY;
#else
boot_delay = DEFAULT_BOOT_DELAY;
#endif
/* If a value of boot_delay is zero,
* unconditionally call vivi shell */
if (boot_delay == 0) vivi_shell();
/*
* wait for a keystroke (or a button press if you want.)
*/
printk("Press Return to start the LINUX now, any other key for vivi\n");
c = awaitkey(boot_delay, NULL);
if (((c != '\r') && (c != '\n') && (c != '\0'))) {
printk("type \"help\" for help.\n");
vivi_shell();
}
run_autoboot();
return;
}
启动成功后,将通过vivi_shell启动一个shell(如果配置了CONFIG_SERIAL_TERM),此时vivi的任务完成。