浅谈ARM下U-boot给Kernel传参数

来源:本站
导读:目前正在解读《浅谈ARM下U-boot给Kernel传参数》的相关信息,《浅谈ARM下U-boot给Kernel传参数》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《浅谈ARM下U-boot给Kernel传参数》的详细说明。
简介:本文章介绍ARM下U-boot给Kernel传参数。

我们可能都知道:U-boot会给Linux Kernel传递很多参数,如:串口波特率,RAM Size,videofb、MAC Address等,而且Linux kernel也会读取和处理这些参数。

两者之间通过struct tag来传递参数。U-boot把要传递给kernel的东西保存在struct tag数据结构中,启动kernel时,把这个结构体的物理地址传给kernel;

Linux kernel通过这个地址,用parse_tags分析出传递过来的参数。

大家也知道在ARM架构上,u-boot向Linux内核传递参数利用了R0,R1和R2三个寄存器,并采用如下约定:

R0

暂时不用,缺省放0

R1

机器号,标识计算机系统的型号,

内核支持的所有使用ARM处理器的设备ID号定义在arch/arm/tools/mach-types文件中,

编译内核过程中会被转换为一个头文件include/asm-arm/mach-types.h供其他文件包含使用。

R2

R2寄存器传递的是一个地址,也就是指针的概念,这个指针指向一个TAG区域.

UBOOT和Linux内核之间正是通过这个扩展了的TAG区域来进行复杂参数的传递,

如 command line,文件系统信息等等,用户也可以扩展这个TAG来进行更多参数的传递。

下面就一下AM335X SDK6.0的Code进行分析:

我们先了解这些参数是如何组织、如何传

先看U-boot阶段的存储的划分

浅谈ARM下U-boot给Kernel传参数

要传递的参数上图中的SDRAM区域的什么位置?从上面的名字可以知道可定是GD区域,当然是怎么放,如何组织该这些数据,肯定要有一个相应的struct来保存,

这就是GD struct GD struct的主要成员如下:

在U-Boot的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是没有MMU,这都了解,而且U-boot有重载机制,可能肯定要对GD数据Modify,这就需要记住该地址,

uboot为了方便要访问GD,特点给提供一个存储寄存器

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

DECLARE_GLOBAL_DATA_PTR定义一个gd_t全局数据结构的指针,这个指针存放在指定的寄存器r8中。

这个声明也避免编译器把r8分配给其它的变量。任何想要访问全局数据区的代码,

只要代码开头加入“DECLARE_GLOBAL_DATA_PTR”一行代码,然后就可以使用gd指针来访问全局数据区了。

根据U-Boot内存使用图中可以计算gd的值:

gd = TEXT_BASE -CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)

这样uboot阶段Code都可以找到GD并Modify里面的内容

那现在就看uboot如何把组织的Data给Kernel Uboot load kernel到memory中,

最长用的command是bootm bootm是Uboot启动内核的指令,它用来加载内核镜像,和go命令类似,但是支持r0,r1,r2和bootargs传递参数

bootm就是最终看到的函数是:

bootm的实现位于common/cmd_bootm.c中do_bootm函数

do_bootm的函数第一部分很简单,它首先查看环境变量"verify",如果不为"n",那么将对镜像进行Checksum的校验。

do_bootm可以接受一个可选参数,即镜像文件在内存中的地址。

如果没有指明addr,那么将使用默认的load_addr,它在早些时候被赋值为CFG_LOAD_ADDR。

再这里牵扯到Load地址,实际要加一个小插曲,就是我们Load的Kernel都是包含了一个Head,说白都是经过mkimage包装的,

当然AM335X的u-boot也是包装,因为他是两级Bootload,这不多说,就讲一下mkimage参数:

mkimage -n "Kernel 3.2.0" -A arm -O linux -T kernel -C none -a 80007fc0 -e 80008000 -d XXX.bin uImage 实际我吗只要只要-e这个参数就可以,

这个就是do_bootm()中的load地址 继续追踪,只要do_bootm()load的是一个有Head的Image,

当然要解析这个Image,到底是那个类型,335X要要注意,应该U-boot是mkiamge包过的原因,

如果是Kernel Image,根据类型判断,就要到目标了,

实际就是do_bootm_linux()函数 这个函数重要的原因就我们刚开始讲的U-boot和Kernel直接是通过TAG传递参数,

但是TAG实际是属于GD的,怎么样去设置TAG的参数去就这下面的参数里面写的很清楚了,重点看函数:

setup_start_tag (bd);setup_serial_tag (¶ms);setup_revision_tag (¶ms);setup_end_tag (bd);void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],     ulong addr, ulong *len_ptr, int verify){........kernel_entry = (void (*)(int, int, uint))images->ep;........r2 = gd->bd->bi_boot_params;........kernel_entry(0, machid, r2);}
其中要注意gd->bd->bi_boot_params 这个地址是在board_init()函数里面赋值的,
就是和你的Board以及很紧密,一般都在XXXXX.h中定义 一个值得注意的参数是theKernel,
它有三个参数,并且用它来指向系统镜像的入口地址,到现在总算把参数给放到制定的位置了,也是按照ARM的规范放到了
Kernel如何取参数和解析参数
Kernel取参数,我们就仅仅说明如何去取,就不讲如何解析这些参数了arch/arm/boot/compressed/head.S中的start入口(kernel code)
start:.type   start,#function.rept   8mov     r0, r0.endr......1:mov     r7, r1                  @ save architecture ID  mov     r8, r2                  @ save atags pointer到现在总算找到参数的地址了,下面就看按照约定好的套路去解析就可以了整个解析的过程,我们仅仅说明函数的流程:对于 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 文件中实现parse_cmdline(cmdline_p, from);  // 处理编译内核时指定的 cmdline 或 u-boot 传递的 cmdline到目前位置可以说已经OK了,就不多说了解析过程中主要是TAG,下面补充一下TAG的东西,就是对TAG的分类:/* The list ends with an ATAG_NONE node. */#define ATAG_NONE0x00000000/* The list must start with an ATAG_CORE node */#define ATAG_CORE0x54410001/* it is allowed to have multiple ATAG_MEM nodes */#define ATAG_MEM0x54410002/* VGA text type displays */#define ATAG_VIDEOTEXT0x54410003/* describes how the ramdisk will be used in kernel */#define ATAG_RAMDISK0x54410004/* * this one accidentally used virtual addresses - as such, * it's deprecated. */#define ATAG_INITRD0x54410005/* describes where the compressed ramdisk image lives (physical address) */#define ATAG_INITRD20x54420005/* board serial number. "64 bits should be enough for everybody" */#define ATAG_SERIAL0x54410006/* board revision */#define ATAG_REVISION0x54410007/* initial values for vesafb-type framebuffers. see struct screen_info * in include/linux/tty.h */#define ATAG_VIDEOLFB0x54410008/* command line:  terminated string */#define ATAG_CMDLINE0x54410009/* acorn RiscPC specific information */#define ATAG_ACORN0x41000101/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */#define ATAG_MEMCLK0x41000402

提醒:《浅谈ARM下U-boot给Kernel传参数》最后刷新时间 2024-03-14 00:56:12,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《浅谈ARM下U-boot给Kernel传参数》该内容的真实性请自行鉴别。