0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

U-boot传递RAM和Linux kernel读取RAM参数的解析

Q4MP_gh_c472c21 2018-02-06 08:24 次阅读

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参数为例进行说明。

1、u-boot给kernel传RAM参数

./common/cmd_bootm.c文件中(指Uboot的根目录),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 (¶ms);

#endif

#ifdef CONFIG_REVISION_TAG

setup_revision_tag (¶ms);

#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

}

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

对于Linux Kernel,ARM平台启动时,先执行arch/arm/kernel/head.S,此文件会调用arch/arm/kernel/head-common.S和arch/arm/mm/proc-arm920.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中的bd和gd

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结构体的指针。

本文的版本为U-boot-1.3.4、Linux-2.6.28,平台是ARM。

U-boot传递RAM和Linux kernel读取RAM参数的解析

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • RAM
    RAM
    +关注

    关注

    8

    文章

    1367

    浏览量

    114517
  • Linux
    +关注

    关注

    87

    文章

    11219

    浏览量

    208872
  • u-boot
    +关注

    关注

    0

    文章

    120

    浏览量

    38195
  • Kernel
    +关注

    关注

    0

    文章

    48

    浏览量

    11136

原文标题:Uboot与Linux之间的参数传递详解

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    U-Boot介绍

    在移植 Linux之前我们需要先移植一个 bootloader 代码,这个 bootloader 代码用于启动 Linux 内核, bootloader有很多,常用的就是 U-Boot
    的头像 发表于 10-08 10:50 3935次阅读

    U-boot的基本介绍

    从本文开始,将陆续推送“手把手教你移植U-boot”系列文章,目标是由浅入深地讲解U-boot的工作流程、原理、配置方法和移植方法,手把手教你完成U-boot的移植工作,默认硬件开发平台为ARM,操作系统为
    发表于 07-14 16:52 2759次阅读
    <b class='flag-5'>U-boot</b>的基本介绍

    u-bootlinux kernel在RK3399上是如何部署的

    mainline 的 u-bootlinux kernel可能很多玩 Linux 的同学都听过 mainline 或者 upstream 这两个词,但是又搞不清他们到底指的是什么
    发表于 05-07 12:04

    u-boot的Makefile分析

    u-boot的Makefile分析 U-BOOT是一个LINUX下的工程,在编译之前必须已经安装对应体系结构的交叉编译环境,这里只针对ARM,编译器系列软件为arm-linux-*。
    发表于 05-17 09:16 2056次阅读

    u-boot简介

    演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是根据相应的Linux内核源程序进行简化而形成的,尤其是一些设备的驱动程序,这从U-Boot源码的注
    发表于 10-14 11:17 3538次阅读

    DENX U-BootLinux 使用手册

    DENX U-BootLinux 使用手册
    发表于 10-30 09:59 5次下载
    DENX <b class='flag-5'>U-Boot</b>及<b class='flag-5'>Linux</b> 使用手册

    详解U-Boot引导内核分析

    bootm命令是用来引导经过U-Boot的工具mkimage打包后的kernel image的。U-Boot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。
    的头像 发表于 04-13 15:22 5229次阅读
    详解<b class='flag-5'>U-Boot</b>引导内核分析

    你了解u-bootlinux内核间的参数传递过程?

    U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb、MAC地
    发表于 05-13 10:00 1707次阅读
    你了解<b class='flag-5'>u-boot</b>与<b class='flag-5'>linux</b>内核间的<b class='flag-5'>参数</b><b class='flag-5'>传递</b>过程?

    Linux下获取虚拟地址对应的物理地址的方式

    U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等。而
    发表于 05-15 15:59 4250次阅读

    Linux:使用 QEMU 测试 U-BOOT的步骤

    Linux:使用 QEMU 测试 U-BOOT的步骤
    的头像 发表于 06-23 09:42 3347次阅读
    <b class='flag-5'>Linux</b>:使用 QEMU 测试 <b class='flag-5'>U-BOOT</b>的步骤

    设备树的传递kernel 对设备树的解析

    U-Boot 将设备树加载到内存指定位置后,ARM 内核的 SoC 以通用寄存器 r2 来传递 dtb 在内存中的地址。kernel 获取到该地址后对 dtb 文件做进一步的处理。 设备树的
    的头像 发表于 07-29 11:19 2366次阅读
    设备树的<b class='flag-5'>传递</b>及<b class='flag-5'>kernel</b> 对设备树的<b class='flag-5'>解析</b>

    深度解析U-Boot网络实现

    对于U-Boot而言,并没有完整的实现上述模型,u-boot需要控制固件的尺寸,所以根据需要做了一些简化,其拓扑框架如下图所示:
    发表于 02-07 11:53 2次下载
    深度<b class='flag-5'>解析</b><b class='flag-5'>U-Boot</b>网络实现

    U-Boot架构浅析

    导读:嵌入式Linux系统搭建,bootloader是必不可少的一环,而U-Boot已成嵌入式Linux事实标准。所以较为深入的分析U-Boot的设计,对于更...
    发表于 02-07 11:56 7次下载
    <b class='flag-5'>U-Boot</b>架构浅析

    Linux U-Boot开发指南

    介绍 U-Boot 的编译打包、基本配置、常用命令的使用、基本调试方法等, 为 U-BOOT 的移植及应用开发提供了基础。
    的头像 发表于 03-06 10:28 1260次阅读
    <b class='flag-5'>Linux</b> <b class='flag-5'>U-Boot</b>开发指南

    如何在U-BOOTboot.scr中加载bit文件

    在2020.1版本之后,u-boot阶段会执行boot.scr来加载后续的kernel和rootfs
    的头像 发表于 07-12 15:43 2138次阅读
    如何在<b class='flag-5'>U-BOOT</b>的<b class='flag-5'>boot</b>.scr中加载bit文件