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

本文详细介绍了U-Boot如何向Linux Kernel传递参数,特别是RAM相关信息的传递过程。通过U-Boot的struct tag结构体及Kernel的解析函数,实现了硬件配置的无缝对接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

 

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值