博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
U-boot给kernel传参数和 kernel读取参数—struct tag
阅读量:2455 次
发布时间:2019-05-10

本文共 6525 字,大约阅读时间需要 21 分钟。

 

 

 

U-boot给kernel传参数和 kernel读取参数—struct tag

        U-boot 会给 Linux Kernel 传递很多 参数,如:串口, RAM videofb 等。而 Linux kernel 也会读取和处理这些参数。两者之间通过 struct tag 来传递参数。 U-boot 把要传递给 kernel 的东西保存在 struct tag 数据结构中,启动 kernel 时,把这个结构体的物理地址传给 kernel Linux kernel 通过这个地址,用 parse_tags 分析出传递过来的参数。

本文主要以 U-boot 传递 RAM Linux kernel 读取 RAM 参数为例进行说明。

1u-bootkernelRAM 参 数

       ./common/cmd_bootm.c 文件中, bootm 命令对应的 do_bootm 函数,当分析 uImage 中信息发现 OS Linux 调用 ./lib_arm/bootm.c 文件中的 do_bootm_linux 函数来启动 Linux kernel

       do_bootm_linux 函数 中:

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

                   ulong addr, ulong *len_ptr, int verify)

{

......

#if defined (CONFIG_SETUP_MEMORY_TAGS) || /

    defined (CONFIG_CMDLINE_TAG) || /

    defined (CONFIG_INITRD_TAG) || /

    defined (CONFIG_SERIAL_TAG) || /

    defined (CONFIG_REVISION_TAG) || /

    defined (CONFIG_LCD) || /

    defined (CONFIG_VFD)

       setup_start_tag (bd);      // 初始化 tag 结构体开始

#ifdef CONFIG_SERIAL_TAG

       setup_serial_tag (&params);

#endif

#ifdef CONFIG_REVISION_TAG

       setup_revision_tag (&params);

#endif

#ifdef CONFIG_SETUP_MEMORY_TAGS

       setup_memory_tags (bd);      // 设置 RAM 参数

#endif

#ifdef CONFIG_CMDLINE_TAG

       setup_commandline_tag (bd, commandline);

#endif

#ifdef CONFIG_INITRD_TAG

       if (initrd_start && initrd_end)

              setup_initrd_tag (bd, initrd_start, initrd_end);

#endif

#if defined (CONFIG_VFD) || defined (CONFIG_LCD)

       setup_videolfb_tag ((gd_t *) gd);

#endif

       setup_end_tag (bd);              // 初始化 tag 结构体结束

#endif

......

......

       theKernel (0, machid, bd->bi_boot_params);

// 传给 Kernel 的参数= (struct tag *) 型的 bd->bi_boot_params

//bd->bi_boot_params board_init 函数中初始化如对于 at91rm9200 ,初始化在 at91rm9200dk.c board_init 中进行: bd->bi_boot_params =PHYS_SDRAM + 0x100;

// 这个地址也是所有 taglist 的首地址,见下面的 setup_start_tag 函数

}

 

       对于 setup_start_tag setup_memory_tags 函数说明如下。

       函数 setup_start_tag 也 在此文件中定义,如下:

static void setup_start_tag (bd_t *bd)

{

       params = (struct tag *) bd->bi_boot_params;

// 初始化 (struct tag *) 型的全局变量 params bd->bi_boot_params 的 地址,之后的 setup tags 相关函数如下面的 setup_memory_tags 就把其它 tag 的数据放在此地址的偏移地址上。

 

       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);

}

      

RAM 相关参数在 bootm.c 中的函数 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[i].start;

              params->u.mem.size = bd->bi_dram[i].size;

              params = tag_next (params);

       }                   // 初始化内存相关 tag

}

 

2Kernel 读 取U-boot 传递的相关参数

对于 Linux Kernel ARM 平台启动时,先执行 arch/arm/kernel/head.S ,此文件会调用 arch/arm/kernel/head-common.S 中的函数,并最后调用 start_kernel

......

b     start_kernel

......

 

init/main.c 中的 start_kernel 函数中会 调用 setup_arch 函数来处理各种平台相关的动作,包括了 u-boot 传递过来参数的分析和保存:

start_kernel()

{

......

       setup_arch(&command_line);

......

}

      

       其中, setup_arch 函数在 arch/arm/kernel/setup.c 文件中实现,如下:

void __init setup_arch(char **cmdline_p)

{

       struct tag *tags = (struct tag *)&init_tags;

       struct machine_desc *mdesc;

       char *from = default_command_line;

       setup_processor();

       mdesc = setup_machine(machine_arch_type);

       machine_name = mdesc->name;

       if (mdesc->soft_reboot)

              reboot_setup("s");

       if (__atags_pointer)             

// 指向各种 tag 起始位置的指针,定义如下:

//unsigned int __atags_pointer  __initdata;

// 此指针指向 __initdata 段,各种 tag 的信息保存在这个段中。

              tags = phys_to_virt(__atags_pointer);

       else if (mdesc->boot_params)

              tags = phys_to_virt(mdesc->boot_params);

       if (tags->hdr.tag != ATAG_CORE)

              convert_to_tag_list(tags);

       if (tags->hdr.tag != ATAG_CORE)

              tags = (struct tag *)&init_tags;

       if (mdesc->fixup)

              mdesc->fixup(mdesc, tags, &from, &meminfo);

       if (tags->hdr.tag == ATAG_CORE) {

              if (meminfo.nr_banks != 0)

                     squash_mem_tags(tags);

              save_atags(tags);

              parse_tags(tags); 

// 处理各种 tags ,其中包括了 RAM 参数的处理。

// 这个函数处理如下 tags

__tagtable(ATAG_MEM, parse_tag_mem32);

__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);

__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);

__tagtable(ATAG_SERIAL, parse_tag_serialnr);

__tagtable(ATAG_REVISION, parse_tag_revision);

__tagtable(ATAG_CMDLINE, parse_tag_cmdline);

       }

       init_mm.start_code = (unsigned long) &_text;

       init_mm.end_code   = (unsigned long) &_etext;

       init_mm.end_data   = (unsigned long) &_edata;

       init_mm.brk       = (unsigned long) &_end;

       memcpy(boot_command_line, from, COMMAND_LINE_SIZE);

       boot_command_line[COMMAND_LINE_SIZE-1] = '/0';

       parse_cmdline(cmdline_p, from);  // 处理编译内核时指定的 cmdline u-boot 传递的 cmdline

       paging_init(&meminfo, mdesc);

       request_standard_resources(&meminfo, mdesc);

#ifdef CONFIG_SMP

       smp_init_cpus();

#endif

       cpu_init();

       init_arch_irq = mdesc->init_irq;

       system_timer = mdesc->timer;

       init_machine = mdesc->init_machine;

#ifdef CONFIG_VT

#if defined(CONFIG_VGA_CONSOLE)

       conswitchp = &vga_con;

#elif defined(CONFIG_DUMMY_CONSOLE)

       conswitchp = &dummy_con;

#endif

#endif

       early_trap_init();

}

 

对于处理 RAM tag ,调用了 parse_tag_mem32 函 数:

static int __init parse_tag_mem32(const struct tag *tag)

{

......

       arm_add_memory(tag->u.mem.start, tag->u.mem.size);

......

}

__tagtable(ATAG_MEM, parse_tag_mem32);

       上述的 arm_add_memory 函 数定义如下:

static void __init arm_add_memory(unsigned long start, unsigned long size)

{

       struct membank *bank;

       size -= start & ~PAGE_MASK;

 

       bank = &meminfo.bank[meminfo.nr_banks++];

       bank->start = PAGE_ALIGN(start);

       bank->size  = size & PAGE_MASK;

       bank->node  = PHYS_TO_NID(start);

}

       如上可见, parse_tag_mem32 函数调用 arm_add_memory 函 数把 RAM start size 等参数保存到了 meminfo 结构的 meminfo 结构体中。最后,在 setup_arch 中执行下面语句:

       paging_init(&meminfo, mdesc);

       对有 MMU 的平台上调用 arch/arm/mm/nommu.c 中的 paging_init ,否则调用 arch/arm/mm/mmu.c 中的 paging_init 函数。这里 暂不分析 mmu.c 中的 paging_init 函数。

 

 

3 、关于U-boot 中 的bdgd

U-boot 中有一个用来保存很多有用信息的全局结构体-- gd_t global data 缩写),其 中包括了 bd 变量,可以说 gd_t 结 构体包括了 u-boot 中所有重要全局变量。最后传递给内核的参数,都是从 gd bd 中来的,如上述的 setup_memory_tags 函数作用就是用 bd 中的 值来初始化 RAM 相应的 tag

对于 ARM 平 台这个结构体的定义大致如下:

include/asm-arm/global_data.h

typedef    struct      global_data {

       bd_t        *bd;

       unsigned long  flags;

       unsigned long  baudrate;

       unsigned long  have_console; /* serial_init() was called */

       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;        /* jump table */

} gd_t;

 

U-boot 中使用 gd 结构之前要用先用宏 DECLARE_GLOBAL_DATA_PTR 来声明。这个宏的定义如下:

include/asm-arm/global_data.h

#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")

从这个宏的定义可以看出, gd 是一个保存在 ARM r8 寄存器中的 gd_t 结 构体的指针。

 

 

转自http://blog.chinaunix.net/u3/90973/showart_1925725.html

 

转载地址:http://kijhb.baihongyu.com/

你可能感兴趣的文章
公众号精选评论点赞_十大和编辑精选:七月评论
查看>>
软齿面减速机抛开图_为了共同的目标而抛开自我
查看>>
维度诅咒_CEO自我的礼物和诅咒
查看>>
如何使用Jenkins运行JMeter
查看>>
angular 初探_初探Google的Science Journal应用
查看>>
关于开源软件研究的英文论文_关于开源公司软件的7个神话
查看>>
非传统营销 text_在传统营销失败的地方,社区推动的营销成功
查看>>
irc ubuntu_IRC入门
查看>>
Phire CMS:功能丰富的轻量级内容管理系统
查看>>
庆祝一下_加入我们,庆祝开放组织的一年
查看>>
dropbox为什么被屏蔽_Python社区和Dropbox为增加多样性而采取的步骤
查看>>
路由器搭建个人网站_PittMesh路由器归个人所有
查看>>
raspberry pi_Picademy:Raspberry Pi基金会的老师的免费专业发展
查看>>
retropie游戏版权_RetroPie的新网站和发行版,针对Linux的三款新游戏以及更多游戏新闻...
查看>>
开源项目贡献者_在现代开源中发展贡献者基础
查看>>
在新手友好的Linux发行版Korora上大吃一惊
查看>>
Raspberry Pi 3推出了更快的CPU,板载Wi-Fi和蓝牙
查看>>
不同管理岗层级的团队影响力_高影响力团队的最高要求
查看>>
j pocket_Wallabag:Pocket的开源替代品
查看>>
cms系统和管理员系统区别_如何成为懒惰的系统管理员
查看>>