免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1230 | 回复: 0
打印 上一主题 下一主题

Arm linux启动分析(6) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-30 22:23 |只看该作者 |倒序浏览

2、lib-arm/board.c系统c语言部分初始化分析
/*start_armboot 是 U-Boot 执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。*/
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
#ifndef CFG_NO_FLASH
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif

/* U-boot唯一的全局变量保存了U-boot的所有信息,我们在这分配其空间,它是位于动态缓冲区下面的部分 */
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__(“”: : :“memory”);//内存一致,防止指令执行不一致
memset ((void*)gd, 0, sizeof (gd_t));//对结构体gd进行初始化
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));//分配uboot接口结构体gd->bd,并对其进行初始化
memset (gd->bd, 0, sizeof (bd_t));

monitor_flash_len = _bss_start - _armboot_start;

/*对UBOOT的初始化队列依次进行初始化操作,这些模块是所以cpu所公用的模块,所以放在这进行一起初始化*/
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的基本设置配置中断堆栈*/      
board_init,            /*4020开发板的基本初始化 */
interrupt_init,  /*初始化中断 ,我们在此配置了时钟和中断堆栈*/
env_init,         /*初始化环境变量 */
init_baudrate,/*初始化波特率,获取环境变量中的波特率赋予gd->bd->bi_baudrate */
serial_init,              /*串口通讯初始化,设置4020的串口 */
console_init_f,       /*控制台初始化第一阶段 */
dram_init,              /*配制可用的内存区,设置gd->bd->bi_dram的值*/
display_dram_config,
NULL,
};
*********************************************************/
/* 配置4020的nor flash芯片,并显示flash的配置内容 */
size = flash_init ();
display_flash_config (size);
/* 初始化uboot的动态缓冲区 */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

/* 初始化uboot的nand */
#if defined(CONFIG_CMD_NAND)
puts ("NAND:  ");
nand_init();            /* go init the NAND */
#endif

/* 初始化uboot的环境变量 */
env_relocate ();

/* 获取环境变量中的ip地址,并赋值到gd->bd->bi_ip_addr中 */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

/*获取环境变量中的mac地址,并赋值到gd->bd->bi_enetaddr中 */
{
        int i;
        ulong reg;
        char *s, *e;
        char tmp[64];

        i = getenv_r ("ethaddr", tmp, sizeof (tmp));
        s = (i > 0) ? tmp : NULL;

        for (reg = 0; reg
        gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
        if (s)
               s = (*e) ? e + 1 : e;
        }
devices_init (); /* 获取uboot的设备链,并初始化相应的设备 */
jumptable_init ();/*uboot命令跳转表gd->jt的初始化*/

console_init_r ();    /* fully init console as a device */
/* 使能4020的中断 */
enable_interrupts ();
/* 初始化相应的环境变量 loadaddr , bootfile */
if ((s = getenv ("loadaddr")) != NULL) {
        load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
        copy_filename (BootFile, s, sizeof (BootFile));
}
#endif

#ifdef BOARD_LATE_INIT
board_late_init ();//4020板子初始化的后续操作,我们的网络就是在此初始化的
#endif

/* main_loop() 是uboot的主循环,负责接收uboot的相应命令执行相应操作 */
for (;;) {
        main_loop ();
}

/* NOTREACHED - no way out of command loop except booting */
}

四、U-boot引导Linux镜像分析
1、/common/main.c的main_loop分析
void main_loop (void)
{
        debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");

if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
            # ifdef CONFIG_AUTOBOOT_KEYED
        int prev = disable_ctrlc(1);    /* disable Control C checking */
          # endif

          # ifndef CFG_HUSH_PARSER
        run_command (s, 0);//如果不键入任何健的话就会进入自动启动阶段
          # else
        parse_string_outer(s, FLAG_PARSE_SEMICOLON |
                          FLAG_EXIT_FROM_LOOP);
          # endif
}
}
int run_command (const char *cmd, int flag)
{
        while (*str) {
/* OK - call function to do the command */
/*根据uboot的函数指针执行相应的命令,其中就包含tftp和bootm*/
                if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
               rc = -1;
                }
                         }
}
2、引导函数go指令的实现
int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
ulong      addr, rc;
int     rcode = 0;

if (argc
        printf ("Usage:\n%s\n", cmdtp->usage);
        return 1;
}
addr = simple_strtoul(argv[1], NULL, 16);
printf ("## Starting application at 0x%08lX ...\n", addr);
/*
*尽管go命令可以带变参,实际使用时一般不
用来传递参数。这里通过将一个地址强制转化为一个main函数指针,强制调用一个main函数
*/
rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]);
       if (rc != 0) rcode = 1;

printf ("## Application terminated, rc = 0x%lX\n", rc);
return rcode;
}
3、引导函数bootm指令的实现
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
       #ifdef CONFIG_ZIMAGE_BOOT
          printf(“Boot with zImage\n”);//这个是程杰加的,直接引导我们的4020 zImage
          do_bootm_linux (cmdtp, flag, argc, argv, &images);
       #endif
/* 从镜像的头部中获取镜像的相关内容 */
       os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,&images, &os_data, &os_len);
/* 获取镜像的参数 */
switch (genimg_get_format (os_hdr)) {
case IMAGE_FORMAT_LEGACY:
        type = image_get_type (os_hdr);
        comp = image_get_comp (os_hdr);
        os = image_get_os (os_hdr);
        image_end = image_get_image_end (os_hdr);
        load_start = image_get_load (os_hdr);
        break;
       default:
        puts ("ERROR: unknown image format type!\n");
        return 1;
}
switch (comp) {
case IH_COMP_NONE:
        break;
case IH_COMP_GZIP:
        gunzip ((void *)load_start, unc_len,(uchar *)os_data, &os_len)               
            break;
#ifdef CONFIG_BZIP2
case IH_COMP_BZIP2:
        int i = BZ2_bzBuffToBuffDecompress ((char*)load_start,&unc_len, (char *)os_data, os_len,CFG_MALLOC_LEN
        break;
#endif /* CONFIG_BZIP2 */
default:
        }
debug ("   kernel loaded at 0x%08lx, end = 0x%08lx\n", load_start, load_end);
switch (os) {
default:                  /* handled by (original) Linux case */
case IH_OS_LINUX:
/*引导启动linux镜像的函数*/
    do_bootm_linux (cmdtp, flag, argc, argv, &images);
    break;
      }
}

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],bootm_headers_t *images)
{
/*获取启动linux内核的参数,并保存到commandline */
   char *commandline = getenv ("bootargs");
   if (images->legacy_hdr_valid) {
/*获取uboot加载内核的地址,这个我们在include/configs/UB4020.h中定义为0x30008000*/
        ep = CFG_LOAD_ADDR;
                                            }
  theKernel = (void (*)(int, int, uint))ep;// theKernel 即是启动linux的函数指针
  s = getenv (“machid”);//获取环境变量中的机器号
if (s) {
        machid = simple_strtoul (s, NULL, 16);
                }
/*设置参数表,这个参数表里面包含许多内容,而我们的启动参数也是其中一项*/
setup_start_tag (bd);//这个是设置参数表的起始位置和大小,我们的4020参数列表地址在board_init()函数中设置的,同时它还设置了机器号gd->bd->bi_arch_number = 0xc2;
/*************************uboot的参数列表分析******************************
(1)单个参数项的格式

(2)整个参数列表的格式

*********************************************************/

#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (&params);//设置串口参数
#endif
setup_commandline_tag (bd, commandline);//设置启动参数表项
setup_end_tag (bd);//设置参数列表的结束符

/* we assume that the kernel is in place */
printf ("\nStarting kernel ...\n\n");
theKernel (0, machid, bd->bi_boot_params);  /* 启动linux*/
}
五、U-BOOT的内存镜像分布图(1)
(1)在刚上电时的uboot在nor中的内存镜像



(2)uboot最终运行的内存镜像




本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/99507/showart_2107730.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP