Uboot传递参数与kernel解析参数
uboot代码完全解析

目录
u-boot-1.1.6 之 cpu/arm920t........................................................................2 u-boot 中.lds 连接脚本文件的分析 ...................................................................................................12 分享一篇我总结的 uboot 学习笔记(转) .....................................................................................15 U-BOOT 内存布局及启动过程浅析 ...................................................................................................22 u-boot 中的命令实现 ..........................................................................................................................25 U-BOOT 环境变量实现 ........................................................................................................................28
《uboot环境变量:详谈bootcmd和bootargs》

《uboot环境变量:详谈bootcmd和bootargs》1.uboot中的环境变量bootdelay:执⾏⾃动启动的等候秒数baudrate:串⼝控制台的波特率netmask:以太⽹接⼝的掩码ethaddr:以太⽹卡的⽹卡物理地址bootfile:缺省的下载⽂件bootargs:传递给内核的启动参数bootcmd:⾃动启动时执⾏的命令serverip:服务器端的ip地址ipaddr:本地ip 地址stdin:标准输⼊设备stdout:标准输出设备stderr:标准出错设备 以上是⼀些基本的环境变量。
uboot中⼀般会有⼀些缺省的环境变量。
在启动uboot后会将参数放在特定的FLASH区域,之后由kernel去获取解析。
还有另⼀种⽅法设置环境变量就是在uboot启动后进⼊命令⾏模式,设置环境变量,然后执⾏saveenv后,会将设置的环境变量保存到特定区域的FLASH中,由kernel去获取解析。
其中bootargs和bootcmd相对⽐较重要。
2.bootargs解析root: ⽬前很多新的开发板都是使⽤FLASH作为存储。
因为很多都直接使⽤MTD驱动程序。
MTD 驱动程序的主要优点在于 MTD 驱动程序是专门为基于闪存的设备所设计的,所以它们通常有更好的⽀持、更好的管理和基于扇区的擦除和读写操作的更好的接⼝。
Linux 下的 MTD驱动程序接⼝被划分为两类模块:⽤户模块和硬件模块。
有两个流⾏的⽤户模块可启⽤对闪存的访问: MTD_CHAR 和 MTD_BLOCK 。
MTD_CHAR 提供对闪存的原始字符访问,⽽ MTD_BLOCK 将闪存设计为可以在上⾯创建⽂件系统的常规块设备(象 IDE 磁盘)。
与MTD_CHAR 关联的设备是 /dev/mtd0、mtd1、mtd2(等等),⽽与 MTD_BLOCK 关联的设备是 /dev/mtdblock0、mtdblock1(等等)。
由于 MTD_BLOCK 设备提供象块设备那样的模拟,通常更可取的是在这个模拟基础上创建象 FTL 和 JFFS2 那样的⽂件系统。
uboot命令

uboot命令U-boot基础现在为Linux开放源代码Bootloader有很多,blob、redboot 及U-BOOT等,其中U-BOOT是目前用来开发嵌入式系统引导代码使用最为广泛的Bootloader。
它支持POWERPC、ARM、MIPS和 X86等处理器,支持嵌入式操作系统有Linux、Vxworks及NetBSD等。
2.1 U-boot源代码目录结构|-- board 平台依赖,存放电路板相关的目录文件|-- common 通用多功能函数的实现|-- cpu 平台依赖,存放cpu相关的目录文件|-- disk 通用。
硬盘接口程序|-- doc 文档|-- drivers 通用的设备驱动程序,如以太网接口驱动|-- dtt|-- examples 应用例子|-- fs 通用存放文件系统的程序|-- include 头文件和开发板配置文件,所有开发板配置文件放在其configs 里|-- lib_arm 平台依赖,存放arm架构通用文件|-- lib_generic 通用的库函数|-- lib_i386 平台依赖,存放x86架构通用文件|-- lib_m68k 平台依赖|-- lib_microblaze 平台依赖|-- lib_mips 平台依赖|-- lib_nios 平台依赖|-- lib_ppc平台依赖,存放ppc架构通用文件|-- net 存放网络的程序|-- post 存放上电自检程序|-- rtc rtc的驱动程序`-- tools 工具详细实例:board:开发板相关的源码,不同的板子对应一个子目录,内部放着主板相关代码。
Board/at91rm9200dk/at91rm9200.c, config.mk, Makefile, flash.c ,u-boot.lds等都和具体开发板的硬件和地址分配有关。
common:与体系结构无关的代码文件,实现了u-boot所有命令,其中内置了一个shell脚本解释器(hush.c, a prototype Bourne shell grammar parser), busybox中也使用了它。
烧写ARM开发板系统教程-----uboot、内核以及文件系统

烧写ARM开发板系统教程-----uboot、内核以及⽂件系统⼀、sd启动将u-boot镜像写⼊SD卡,将SD卡通过读卡器接上电脑(或直接插⼊笔记本卡槽),通过"cat /proc/partitions"找出SD卡对应的设备,我的设备节点是/dev/sdb.(内存卡的节点)。
当有多个交叉编译器是,不⽅便设置环境变量时,可以在编译命令中指定交叉编译器,具体如下:在源码中操作以下步骤:make distcleanmake ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- mrpropermake ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- tiny210_configmake ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- all spl编译出tiny210-uboot.bin,注意交叉编译⼯具路径执⾏下⾯的命令$sudo dd iflag=dsync oflag=dsync if=tiny210-uboot.bin of=/dev/sdb seek=1把内存卡插⼊开发板,使⽤串⼝⼯具设置环境变量:setenv gatewayip 192.168.1.1(电脑⽹关)setenv ipaddr 192.168.1.102(开发板ip,不要与虚拟机和电脑ip冲突)setenv netmask 255.255.255.0setenv serverip 192.168.1.10(虚拟机ip)saveenv⼆、nand启动烧写Uboot:通过SD卡启动的u-boot for tiny210 将u-boot镜像写⼊nandflash在虚拟机下重启tftp sudo service tftpd-hpa restart开发板终端下执⾏下⾯的命令:[FriendlyLEG-TINY210]# tftp 21000000 tiny210-uboot.bin[FriendlyLEG-TINY210]# nand erase.chip[FriendlyLEG-TINY210]# nand write 21000000 0 3c1f4 (写⼊长度)内核的烧写位置是0x600000开始的区域,⽂件系统烧写位置为0xe00000开始的区域。
uboot启动参数设置

nand erase 40000 1c0000 nand erase offset size
nand write 30800000 40000 1c0000 存放内存30800000位置上的uImge,烧写到nandflash的40000位置上
=========================================================================================
例如如下:
FS2410# setenv serverip 192.168.7.x (其中X是虚拟机中IP的最后的数字[用ifconfig可以获取])
farsight_N中的N用座位号来表示,比如座位4即为farsight_4 //设置uboot传给内核的参数
saveenv
自定义参数版本:
4.设置UBOOT参数
确保一下FS2410的核心班上的JP1跳线帽短接了,给板子上电,
查看板子启动信息,如果板子启动信息中,有U-Boot 1.3.1(Oct 25 2008 - 15:45:21)或者更新的版本,则直接设置下面的参数,否则根据文档烧录 u-boot131-for-farsight-shenzhen-advanced-drivers.bin(请参考文档"farsight-实验前的准备步骤-v2.3.doc")
setenv bootargs console=ttySAC0,115200 init=/linuxrc root=/dev/nfs nfsroot=192.168.7.113:/opt/filesystem ip=192.168.7.173:192.168.7.113:192.168.7.1:255.255.255.0:farsight_13:eth0:off //或者console=ttySAC0,115200 root=1f02 rootfstype=jffs2 rw init=/linuxrc mem=64M
uboot向内核模块传递参数的方法

uboot向内核模块传递参数的⽅法1 模块参数定义模块参数1、module_param(name, type, perm); 定义⼀个模块参数,name 变量名type 数据类型bool:布尔型invbool:⼀个布尔型( true 或者 false)值(相关的变量应当是 int 类型).invbool 类型颠倒了值,所以真值变成 false,反之亦然.charp :⼀个字符指针值. 内存为⽤户提供的字串分配, 指针因此设置.int:整形long:长整形short:短整形uint:⽆符号整形ulong:⽆符号长整形ushort:⽆符号短整形perm 访问权限#define S_IRWXU 00700#define S_IRUSR 00400#define S_IWUSR 00200#define S_IXUSR 00100#define S_IRWXG 00070#define S_IRGRP 00040#define S_IWGRP 00020#define S_IXGRP 00010#define S_IRWXO 00007#define S_IROTH 00004#define S_IWOTH 00002#define S_IXOTH 00001#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) //可以被所有⽤户访问不能改写2、module_param_array(name, type, nump, perm); 定义模块参数数组nump 数组元素的个数⽰例:static int test=0;module_param(test, int, S_IRUGO);在uboot 的启动参数中传递参数例如:setenv bootargs console=ttyS0,115200n8 root=${mmcroot} rootfstype=ext4 rootflags=data=writeback quiet testmodule.test=1testmodule模块名称(也就是.o⽂件或者.ko⽂件的名称) test 模块参数名称如果设置了上⾯的启动参数,在驱动中就可以看到test的值为1 2 直接⽤启动参数传递驱动中定义static int test=0;static int __init Get_test(char *str){test = simple_strtoul(str, NULL, 0);return1;}__setup("mode_test=", Get_test);static char *test_name;static int __init Get_testname(char *str){test_name = str;return1;}__setup("mode_testname=", Get_testname);在启动参数中setenv bootargs console=ttyS0,115200n8 root=${mmcroot} rootfstype=ext4 rootflags=data=writeback quiet test=1 test_name=name 按上⾯的设置,在驱动可以得到test的值为1,test_name为“name”。
U-Boot启动过程--详细版的完全分析

(一)U-Boot启动过程--详细版的完全分析我们知道,bootloader是系统上电后最初加载运行的代码。
它提供了处理器上电复位后最开始需要执行的初始化代码。
在PC机上引导程序一般由BIOS开始执行,然后读取硬盘中位于MBR(Main Boot Record,主引导记录)中的Bootloader(例如LILO或GRUB),并进一步引导操作系统的启动。
然而在嵌入式系统中通常没有像BIOS那样的固件程序,因此整个系统的加载启动就完全由bootloader来完成。
它主要的功能是加载与引导内核映像一个嵌入式的存储设备通过通常包括四个分区:第一分区:存放的当然是u-boot第二个分区:存放着u-boot要传给系统内核的参数第三个分区:是系统内核(kernel)第四个分区:则是根文件系统如下图所示:u-boot是一种普遍用于嵌入式系统中的Bootloader。
Bootloader介绍Bootloader是进行嵌入式开发必然会接触的一个概念,它是嵌入式学院<嵌入式工程师职业培训班>二期课程中嵌入式linux系统开发方面的重要内容。
本篇文章主要讲解Bootloader 的基本概念以及内部原理,这部分内容的掌握将对嵌入式linux系统开发的学习非常有帮助!Bootloader的定义:Bootloader是在操作系统运行之前执行的一小段程序,通过这一小段程序,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。
意思就是说如果我们要想让一个操作系统在我们的板子上运转起来,我们就必须首先对我们的板子进行一些基本配置和初始化,然后才可以将操作系统引导进来运行。
具体在Bootloader中完成了哪些操作我们会在后面分析到,这里我们先来回忆一下PC的体系结构:PC机中的引导加载程序是由BIOS和位于硬盘MBR中的OS Boot Loader(比如LILO和GRUB等)一起组成的,BIOS在完成硬件检测和资源分配后,将硬盘MBR中的Boot Loader读到系统的RAM中,然后将控制权交给OS Boot Loader。
openwrt分区

openwrt分区下⾯以ar9344 16M flash为例⼦:uboot启动时传递给内核的参数为:bootargs=console=ttyS0,115200 root=31:02 rootfstype=jffs2 init=/sbin/init mtdparts=ath-nor0:256k(u-boot),64k(u-boot-env),14528k(rootfs),1408k(uImage),64k(mib0),64k(ART)其中我们要关注的项为:mtdparts=ath-nor0:256k(u-boot),64k(u-boot-env),14528k(rootfs),1408k(uImage),64k(mib0),64k(ART)升级完后查看分区:# cat /proc/mtddev: size erasesize namemtd0: 00040000 00010000 "u-boot" // 256k(u-boot)mtd1: 00010000 00010000 "u-boot-env" // 64k (u-boot-env)mtd2: 00630000 00010000 "rootfs" // 14528k (rootfs)mtd3: 00400000 00010000 "rootfs_data"mtd4: 00160000 00010000 "kernel" // 1408k (uImage)mtd5: 00010000 00010000 "nvram" // 64k (mib0)mtd6: 00010000 00010000 "art" // 64k (art)当我们将所有的数据加起来时,发现⼤⼩已经超过了8M的容量。
所以肯定有些部分是相互包含在⼀起的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Uboot传递参数与kernel解析参数U-boot 会给linux Kernel 传递很多参数,例如:串口、RAM、commandline (bootargs)等。
而linux kernel 也会读取和处理这些参数。
它们两者之间通过ATAG方式来传递参数。
U-boot 把要传递给kernel 的数据保存在struct tag 数据结构中,启动内核时,把这个结构体的物理地址传给内核,然后内核通过这个地址,用parse_tags 分析出传递过来的参数。
这里以U-boot 传递RAM 参数和Linux kernel 读取RAM 参数为例进行介绍。
1、u-boot 向kernel 传递RAM 参数./common/cmd_bootm.c 文件调用./uboot/arch/arm/lib/bootm.c 文件中的do_nand_boot 函数来启动Linux kernel。
在do_nand_boot 函数中:int do_nand_boot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])DECLARE_GLOBAL_DATA_PTRint retd_t *bd = gd->bdulong addr, data, len, initrd_start, initrd_endvoid (*theKernel)(int zero, int arch, uint params)int strlechar *commandline = getenv ("bootargs")setup_start_tag (bd); // 初始化第一个kernel tag结构体setup_serial_tag (¶ms)setup_revision_tag (¶ms)setup_memory_tags (bd)theKernel (0, bd->bi_arch_number, bd->bi_boot_params);其中:thekernel其实不是个函数,而是指向内核入口地址的指针,把它强行转化为带三个参数的函数指针,会把三个参数保存到通用寄存器中,实现了向kernel传递信息的功能参数保存到通用寄存器中,实现了向kernel传递信息的功能bd->bi_boot_params :传给Kernel 的参数=(struct tag *) 型的setup_start_tag 和setup_memory_tags 函数说明如下:static void setup_start_tag (bd_t *bd)params = (struct tag *) bd->bi_boot_param/* 初始化(struct tag *) 型的全局变量params 为bd->bi_boot_params 的地址,* 之后的setup tags 相关函数如下面的setup_memory_tag* 就把其它tag 的数据放在此地址的偏移地址上。
*/params->hdr.tag = ATAG_COREparams->hdr.size = tag_size (tag_core)params->u.core.flags = 0params->u.core.pagesize = 0params->u.core.rootdev = 0params = tag_next (params)RAM 相关参数在函数setup_memory_tags 中初始化:static void setup_memory_tags (bd_t *bd)int ifor (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {params->hdr.tag = ATAG_MEMparams->hdr.size = tag_size (tag_mem32)params->u.mem.start = bd->bi_dram[i].startparams->u.mem.size = bd->bi_dram[i].sizeparams = tag_next (params)} // 初始化内存相关tag2、Kernel 读取U-boot 传递的ATAG参数对于Linux Kernel,ARM 平台启动时,先执行arch/arm/kernel/head.S ,此文件会调用arch/arm/kernel/head-common.S 中的函数,并最后调用start_kernel :......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_tagstruct machine_desc *mdescchar *from = default_command_linesetup_processor()mdesc = setup_machine(machine_arch_type)machine_name = mdesc->nameif (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_tagif (mdesc->fixup)mdesc->fixup(mdesc, tags, &from, &meminfo)if (tags->hdr.tag == ATAG_CORE) {if (meminfo.nr_banks != 0)quash_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) &_textinit_mm.end_code = (unsigned long) &_etextinit_mm.end_data = (unsigned long) &_edatainit_mm.brk = (unsigned long) &_endmemcpy(boot_command_line, from, COMMAND_LINE_SIZE)boot_command_line[COMMAND_LINE_SIZE-1] = '/0'parse_cmdline(cmdline_p, from); // 处理编译内核时指定的cmdline 或u-boot 传递的cmdlinepaging_init(&meminfo, mdesc)request_standard_resources(&meminfo, mdesc)#ifdef CONFIG_SMPmp_init_cpus()#endif……对于处理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 *banksize -= start & ~PAGE_MASKbank = &meminfo.bank[meminfo.nr_banks++]bank->start = PAGE_ALIGN(start)bank->size = size & PAGE_MASKbank->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 函数。