Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2279981
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

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的任务完成。

阅读(820) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~