9662|4

854

帖子

0

TA的资源

五彩晶圆(中级)

楼主
 

uboot是如何传递内存等参数给linux内核的 [复制链接]

1.1.3             U-Boot启动Linux过程
       U-Boot使用标记列表(tagged list)的方式向Linux传递参数。标记的数据结构式是tag,在U-Boot源代码目录include/asm-arm/setup.h中定义如下:
struct tag_header {
       u32 size;       /* 表示tag数据结构的联合u实质存放的数据的大小*/
       u32 tag;        /* 表示标记的类型 */
};
struct tag {
       struct tag_header hdr;
       union {
              struct tag_core           core;
              struct tag_mem32      mem;
              struct tag_videotext   videotext;
              struct tag_ramdisk     ramdisk;
              struct tag_initrd  initrd;
              struct tag_serialnr       serialnr;
              struct tag_revision      revision;
              struct tag_videolfb     videolfb;
              struct tag_cmdline     cmdline;
              /*
               * Acorn specific
               */
              struct tag_acorn  acorn;
              /*
               * DC21285 specific
               */
              struct tag_memclk      memclk;
       } u;
};
       U-Boot使用命令bootm来启动已经加载到内存中的内核。而bootm命令实际上调用的是do_bootm函数。对于Linux内核,do_bootm函数会调用do_bootm_linux函数来设置标记列表和启动内核。do_bootm_linux函数在lib_arm/bootm.c 中定义如下:
59   int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
60   {
61       bd_t       *bd = gd->bd;
62       char       *s;
63       int   machid = bd->bi_arch_number;
64       void       (*theKernel)(int zero, int arch, uint params);
65  
66   #ifdef CONFIG_CMDLINE_TAG
67       char *commandline = getenv ("bootargs");   /* U-Boot环境变量bootargs */
68   #endif
       … …
73       theKernel = (void (*)(int, int, uint))images->ep; /* 获取内核入口地址 */
       … …
86   #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
87       defined (CONFIG_CMDLINE_TAG) || \
88       defined (CONFIG_INITRD_TAG) || \
89       defined (CONFIG_SERIAL_TAG) || \
90       defined (CONFIG_REVISION_TAG) || \
91       defined (CONFIG_LCD) || \
92       defined (CONFIG_VFD)
93       setup_start_tag (bd);                                     /* 设置ATAG_CORE标志 */
       … …
100  #ifdef CONFIG_SETUP_MEMORY_TAGS
101      setup_memory_tags (bd);                             /* 设置内存标记 */
102  #endif
103  #ifdef CONFIG_CMDLINE_TAG
104      setup_commandline_tag (bd, commandline);      /* 设置命令行标记 */
105  #endif
       … …
113      setup_end_tag (bd);                               /* 设置ATAG_NONE标志*/         
114  #endif
115
116      /* we assume that the kernel is in place */
117      printf ("\nStarting kernel ...\n\n");
       … …
126      cleanup_before_linux ();          /* 启动内核前对CPU作最后的设置 */
127
128      theKernel (0, machid, bd->bi_boot_params);      /* 调用内核 */
129      /* does not return */
130
131      return 1;
132  }
       其中的setup_start_tag,setup_memory_tags,setup_end_tag函数在lib_arm/bootm.c中定义如下:
       (1)setup_start_tag函数
static void setup_start_tag (bd_t *bd)
{
       params = (struct tag *) bd->bi_boot_params;  /* 内核的参数的开始地址 */
       params->hdr.tag = ATAG_CORE;
       params->hdr.size = tag_size (tag_core);
       params->u.core.flags = 0;
       params->u.core.pagesize = 0;
       params->u.core.rootdev = 0;
       params = tag_next (params);
}
       标记列表必须以ATAG_CORE开始,setup_start_tag函数在内核的参数的开始地址设置了一个ATAG_CORE标记。
       (2)setup_memory_tags函数
static void setup_memory_tags (bd_t *bd)
{
       int i;
/*设置一个内存标记 */
       for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {   
              params->hdr.tag = ATAG_MEM;
              params->hdr.size = tag_size (tag_mem32);
              params->u.mem.start = bd->bi_dram.start;
              params->u.mem.size = bd->bi_dram.size;
              params = tag_next (params);
       }
}
       setup_memory_tags函数设置了一个ATAG_MEM标记,该标记包含内存起始地址,内存大小这两个参数。
       (3)setup_end_tag函数
static void setup_end_tag (bd_t *bd)
{
       params->hdr.tag = ATAG_NONE;
       params->hdr.size = 0;
}
       标记列表必须以标记ATAG_NONE结束,setup_end_tag函数设置了一个ATAG_NONE标记,表示标记列表的结束。
       U-Boot设置好标记列表后就要调用内核了。但调用内核前,CPU必须满足下面的条件:
(1)    CPU寄存器的设置
?  r0=0
?  r1=机器码
?  r2=内核参数标记列表在RAM中的起始地址
(2)    CPU工作模式
?  禁止IRQ与FIQ中断
?  CPU为SVC模式
(3)    使数据Cache与指令Cache失效
       do_bootm_linux中调用的cleanup_before_linux函数完成了禁止中断和使Cache失效的功能。cleanup_before_linux函数在cpu/arm920t/cpu.中定义:
int cleanup_before_linux (void)
{
       /*
        * this is called just before we call linux
        * it prepares the processor for linux
        *
        * we turn off caches etc ...
        */
       disable_interrupts ();         /* 禁止FIQ/IRQ中断 */
       /* turn off I/D-cache */
       icache_disable();               /* 使指令Cache失效 */
       dcache_disable();              /* 使数据Cache失效 */
       /* flush I/D-cache */
       cache_flush();                    /* 刷新Cache */
       return 0;
}
       由于U-Boot启动以来就一直工作在SVC模式,因此CPU的工作模式就无需设置了。
do_bootm_linux中:
64       void       (*theKernel)(int zero, int arch, uint params);
… …
73       theKernel = (void (*)(int, int, uint))images->ep;
… …
128      theKernel (0, machid, bd->bi_boot_params);
       第73行代码将内核的入口地址“images->ep”强制类型转换为函数指针。根据ATPCS规则,函数的参数个数不超过4个时,使用r0~r3这4个寄存器来传递参数。因此第128行的函数调用则会将0放入r0,机器码machid放入r1,内核参数地址bd->bi_boot_params放入r2,从而完成了寄存器的设置,最后转到内核的入口地址。
       到这里,U-Boot的工作就结束了,系统跳转到Linux内核代码执行。
点赞 关注
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460

回复
举报

854

帖子

0

TA的资源

五彩晶圆(中级)

沙发
 

#ifdef CONFIG_SETUP_MEMORY_TAGS
static void setup_memory_tags (bd_t *bd)
{
        int i;

        for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
                params->hdr.tag = ATAG_MEM;
                params->hdr.size = tag_size (tag_mem32);

                params->u.mem.start = bd->bi_dram.start;
                params->u.mem.size = bd->bi_dram.size;

                params = tag_next (params);
        }
}
#endif /* CONFIG_SETUP_MEMORY_TAGS */

uboot这玩意还是很强大的
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

板凳
 
/*
* WARNING: this code looks "cleaner" than the PowerPC version, but
* has the disadvantage that you either get nothing, or everything.
* On PowerPC, you might see "DRAM: " before the system hangs - which
* gives a simple yet clear indication which part of the
* initialization if failing.
*/
static int display_dram_config (void)
{
        int i;

#ifdef DEBUG
        puts ("RAM Configuration:\n");

        for(i=0; i                 printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram.start);
                print_size (gd->bd->bi_dram.size, "\n");
        }
#else
        ulong size = 0;

        for (i=0; i                 size += gd->bd->bi_dram.size;
        }

        puts("DRAM:    ");
        print_size(size, "\n");
#endif

        return (0);
}
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

4
 
http://wenku.baidu.com/view/42df4fc52cc58bd63186bdb2.html
这篇文章更加详细,值得学习,我今晚下来存储着。
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

5
 
int dram_init(void)
{
        DECLARE_GLOBAL_DATA_PTR;

        gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
        gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

#if defined(PHYS_SDRAM_2)
        gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
        gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
#endif

#if defined(PHYS_SDRAM_3)
        gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
        gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
#endif

        return 0;
}
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表