uboot的bootcmd bootargs参数详解

合集下载

《uboot环境变量:详谈bootcmd和bootargs》

《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 那样的⽂件系统。

Bootargs参数解析

Bootargs参数解析

Bootargs参数解析mournjust因为该文章不是讲内核的C代码启动过程,所以并没有从start_kernel函数开始,首先从setup_arch 函数(/arch/unicore-linux/kernel/setup.c)函数开始,setup_arch是start_kernel内调的一个子函数:(A)在uboot中已经相应的查找了machine类型,这儿仍然是调用setup_machine函数获得machine类型。

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;这儿的_text等等是在编译的时候生成的,我们可以通过system.map来查看相应的值。

注意此时这些变量存放的是虚拟地址。

(B)内核不像用户空间,每一个用户进程都有独立的用户空间,但是内核空间是共享,这儿为内核建立mm_struct结构体,也就是init_mm。

这个全局变量在内核代码中被用的很多。

(C)memcpy(boot_command_line, from, COMMAND_LINE_SIZE);将bootargs参数表从from地址拷贝到boot_command_line地址上,然后调用parse_cmdline进行参数解析。

注意:static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; char *from = default_command_line;其中CONFIG_CMDLINE可以在.config的隐藏文件中找到相应的值。

(D)parse_cmdline用于解析参数,这时候处理的参数只有initrd 和mem两种。

uboot启动参数设置分类及方法

uboot启动参数设置分类及方法

uboot启动参数设置分类及方法2010-11-17 14:46:54| 分类:默认分类 | 标签:|字号大中小订阅一、nfs启动内核与根文件系统,内核与根文件系统都在nfs上bootargs=noinitrd root=/dev/nfs rw nfsroot=192.168.0.1:/home/tekkaman/working/nfs/rootfs ip=192.168.0.2:192.168.0.1::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64Mbootcmd=nfs 0x30008000 192.168.0.1:/home/tekkaman/working/nfs/zImage.img;bootm二、ramdisk启动根文件系统,读取nandflash 中的内核与根文件系统到ram中执行bootargs= initrd=0x32000000,0x200000 root=/dev/ram rw console=ttySAC0 mem=64Mbootcmd= nand write 0x31000000 0x100000 0x400000\; nand write 0x320000000x700000 0x200000 \; bootm 0x310000000x32000000 根文件系统ramdisk.gz拷贝到内存中的位置0x31000000 内核被考到内存中的位置0x100000 内核在NANDFLASH中的位置0x400000 内核的大小0x700000 根文件系统在NANDFLASH中的位置0x200000 根文件系统的大小三、tftp启动内核(uboot要支持网卡)bootcmd= "tftp 0x32000000 uImage; bootm 0x32000000" bootargs="noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0"四、mmc上装载内核并启动(uboot要支持sd卡)bootcmd="mmc init\; fatload mmc 1 0x30008000 zImage.img\;bootmsd卡初始化后五、usb设备上装载内核并启动(uboot要支持u盘)bootcmd="usb start \; fatload usb 0:4 0x30008000 zImage\;bootm。

UBoot操作和常用命令

UBoot操作和常用命令

UBoot常用命令
• usb start: 起动usb 功能 • usb info: 列出设备 • usb scan: 扫描usb storage(u 盘)设备 • f的at文ls:件列出DOS FAT文件系统, 如:fatls usb 0列出第一块U盘中 • fatload: 读入FAT中的一个文件,如:fatload usb 0 0x30000000
• 通常,Boot Loader 是严重地依赖于硬件而实现的, 特别是在嵌入式世界。因此,在嵌入式世界里建 立一个通用的Boot Loader 几乎是不可能的。尽管 如此,我们仍然可以对Boot Loader 归纳出一些通 用的概念来,以指导用户特定的Boot Loader 设计 与实现。
UBoot来源
• nand write [内存地址] [NAND地址] [大小]
– 将SDRAM中地址0x31000000中大小为0x00200000的内容写入NAND Flash的0x100000地址。
– nand write 0x31000000 0x00100000 0x00200000 – NAND write: device 0 offset 1048576, size 2097152 ... 2097152 bytes
Creating 5 MTD partitions on "NAND 256MiB 3,3V 8-bit": 0x000000000000-0x000000040000 : "supervivi" ftl_cs: FTL header not found. 0x000000040000-0x000000060000 : "param" uncorrectable error : 0x000000060000-0x000000560000 : "Kernel" ftl_cs: FTL header not found. 0x000000560000-0x000040560000 : "root" mtd: partition "root" extends beyond the end of device "NAND 256MiB 3,3V 8-bit" -- size truncated to 0xfaa0000 ftl_cs: FTL header not found. 0x000000000000-0x000040000000 : "nand" mtd: partition "nand" extends beyond the end of device "NAND 256MiB 3,3V 8-bit" -- size truncated to 0x10000000

uboot 启动参数

uboot 启动参数

uboot 启动参数UBOOT是一种常用的启动程序,它能够运行在各种不同的硬件平台上,并且可以通过修改启动参数来适配不同的硬件环境。

下面将分步骤介绍UBOOT启动参数的相关内容。

第一步:获取UBOOT源码首先,需要在官方网站上下载UBOOT源码。

下载完成后,需要解压缩源码包,并通过命令行进入到UBOOT文件夹中。

第二步:配置启动参数配置启动参数需要修改UBOOT的配置文件。

在UBOOT源码目录下,有一个名为“config”的文件夹,其中包含了多个不同的配置文件。

每个配置文件对应着一个不同的硬件平台,可以选择对应的配置文件来进行修改。

打开对应的配置文件,找到“CONFIG_BOOTARGS”这个选项。

这个选项控制了UBOOT的启动参数,包括了启动时使用的内核命令参数、系统启动模式、显示分辨率、硬件时钟等等内容。

根据硬件的不同,需要根据实际情况来进行修改。

如果是嵌入式系统,需要将内核命令参数设置为启动时需要加载的模块和驱动程序;如果是开发板,需要指定启动模式为SD卡或者串口下载模式。

第三步:保存配置文件完成启动参数的修改后,需要保存配置文件。

保存后,可以通过编译UBOOT并将其烧录到目标硬件中。

第四步:运行UBOOT运行UBOOT的方式与平台有关。

在某些开发板上,可以通过在串口终端中运行“boot”命令来启动系统。

在嵌入式系统中,可以通过修改启动顺序来选择从NOR Flash或者SD卡中加载UBOOT。

总结通过上述步骤,可以修改UBOOT的启动参数,并实现对不同硬件平台的适配。

通过正确配置启动参数,可以使系统运行更加稳定,并且更加符合实际需求。

因此,UBOOT启动参数的修改是嵌入式开发中不可忽视的一部分。

Uboot传递参数与kernel解析参数

Uboot传递参数与kernel解析参数

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 (&params)setup_revision_tag (&params)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 的数据放在此地址的偏移地址上。

uboot命令使用教程(uboot参数设置)

uboot命令使用教程(uboot参数设置)

uboot命令使⽤教程(uboot参数设置)1. Printenv 打印环境变量。

uboot> printenvbaudrate=115200ipaddr=192.168.0.111ethaddr=32:34:46:78:9A:DCserverip=192.168.0.100Environment size: 80/8188 bytes2. Setenv 设置新的变量如:uboot> setenv myboard AT91RM9200DKuboot> saveenvuboot> printenvbaudrate=115200ipaddr=192.168.0.111ethaddr=32:34:46:78:9A:DCserverip=192.168.0.100myboard=AT91RM9200DKEnvironment size: 102/8188 bytes⼜如想重置启动参数bootargs:uboot> setenv bootargs 'noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0'uboot> saveenv3. saveenv 保存变量命令将当前定义的所有的变量及其值存⼊ flash 中。

⽤来存储变量及其值的空间只有 8k 字节,应不要超过。

(如上例,每次与setenv配合使⽤)4. loadb 通过串⼝ Kermit 协议下载⼆进制数据。

5. tftp 通过⽹络下载程序,需要先设置好⽹络配置简单配置:uboot> setenv ethaddr 32:34:46:78:9A:DCuboot> setenv ipaddr 192.168.0.111uboot> setenv serverip 192.168.0.100//下载 bin ⽂件到地址 0x20000000 处。

U-boot命令详解

U-boot命令详解

常用的U-boot命令详解帮助与环境变量U-boot发展到现在,他的命令行模式已经非常接近Linux下的shell了,在我编译的U-boot-2009.11中的命令行模式模式下支持“Tab”键的命令补全和命令的历史记录功能。

而且如果你输入的命令的前几个字符和别的命令不重复,那么你就只需要打这几个字符即可,比如我想看这个U-boot的版本号,命令就是“ version”,但是在所有的命令中没有其他任何一个的命令是由“v”开头的,所以只需要输入“v”即可。

TX-2440A> versionU-Boot 1.1.6 (Jan 18 2010 - 10:05:35)TX-2440A> vU-Boot 1.1.6 (Jan 18 2010 - 10:05:35)TX-2440A> baseBase Address: 0x00000000TX-2440A> baBase Address: 0x00000000由于U-boot支持的命令实在太多,一个一个细讲不现实,也没有必要。

所以下面我挑一些烧写和引导常用命令介绍一下,其他的命令大家就举一反三,或者“help”吧!(1)获取帮助命令:help 或?功能:查看当前U-boot版本中支持的所有命令。

T X-2440A>h e l p?-a l i a s f o r'h e l p'a u t o s c r-r u n s c r i p t f r o m m e m o r yb a s e-p r i n t o r s e t a d d r e s s o f f s e tb d i n f o-p r i n t B o a r d I n f o s t r uc t u r eb o o t-b o o t d e f a u l t,i.e.,r u n'b o o tc m d'b o o t_n o o s-b o o t U s e r P r o g r a mb o o t_z I m a g e-b o o t L i n u x's z I m a g eb o o t d-b o o t d e f a u l t,i.e.,r u n'b o o tc m d'b o o t e l f-B o o t f r o m a n E L F i m a g e i n m e m o r yb o o t m-b o o t a p p l ic a t i o n i m a g e f r o m m e m o r yb o o t p-b o o t i m a g e v i a n e t w o r k u s i n g B o o t P/T F T P p r o t oc o lb o o t v x-B o o t v x W o r k s f r o m a n E L F i m a g ec h p a r t-c h a n g e a c t i v e p a r t i t i o nc m p-m e m o r y c o m p a r ec o n i n f o-p r i n t c o n s o l ede v i c e s a n d i nf o r m a t i o nc p-m e m o r y c o p yc r c32-c h e c k s u m c a l c u l a t i o nd a t e-ge t/s e t/r e s e t d a t e&t i m ed c a c h e-e n a b l e o r d i s a b l e d a t a c a c h ee c h o-e c h o a r g s t o c o n s o l ee r a s e-e r a s e F L A S H m e m o r yf l i n f o-p r i n t F L A S H m e m o r y i n f o r m a t i o nf s i n f o-p r i n t i n f o r m a t i o n a b o u t f i l e s y s t e m sf s l o a d-l o a d b i n a r y f i l e f r o m a f i l e s y s t e m i m ag eg o-s t a r t a p p l i c a t i o n a t a d d r e s s'a d d r'h e l p-p r i n t o n l i n e h e l pi c a c h e-e n a b l e o r d i s a b l e i n s t r u c t i o n c a c h ei m i n f o-p r i n t h e a d e r i n f o r m a t i o n f o r a p p l i c a t i o n i m a g ei t e s t-r e t u r n t r u e/f a l s e o n i n t e g e r c o m p a r el o a d b-l o a d b i n a r y f i l e o v e r s e r i a l l i n e(k e r m i t m o d e) l o a d s-l o a d S-R e c o r d f i l e o v e r s e r i a l l i n el o a d x-l o a d b i n a r y f i l e o v e r s e r i a l l i n e(x m o d e m m o d e)l o a d y-l o a d b i n a r y f i l e o v e r s e r i a l l i n e(y m o d e m m o d e) l o o p-i n f i n i t e l o o p o n a d d r e s s r a n g el s-l i s t f i l e s i n a d i r e c t o r y(d e f a u l t/)m d-m e m o r y d i s p l a ym e n u-d i s p l a y a m e n u,t o s e l e c t t h e i t e m s t o d o s o m e t h i n g m m-m e m o r y m o d i f y(a u t o-i n c r e m e n t i n g)m t d p a r t s-d e f i n e f l a s h/n a n d p a r t i t i o n sm t e s t-s i m p l e R A M t e s tm w-m e m o r y w r i t e(f i l l)n a n d-N A N D s u b-s y s t e mn b o o t-b o o t f r o m N A N D d e v i c en m-m e m o r y m o d i f y(c o n s t a n t a d d r e s s)p i n g-s e n d I C M P E C H O_R E Q U E S T t o n e t w o r k h o s tp r i n t e n v-p r i n t e n v i r o n m e n t v a r i a b l e sp r o t e c t-e n a b l e o r d i s a b l e F L A S H w r i t e p r o t e c t i o nr a r p b o o t-b o o t i m a g e v i a n e t w o r k u s i n g R A R P/T F T P p r o t o c o l r e s e t-P e r f o r m R E S E T o f t h e C P Ur u n-r u n c o m m a n d s i n a n e n v i r o n m e n t v a r i a b l es a v e e n v-s a v e e n v i r o n m e n t v a r i a b l e s t o p e r s i s t e n t s t o r a g e s e t e n v-s e t e n v i r o n m e n t v a r i a b l e ss l e e p-d e l a y e x e c u t i o n f o r s o m e t i m et f t p b o o t-b o o t i m a g e v i a n e t w o r k u s i n g T F T P p r o t o c o lu s b s l a v e-g e t f i l e f r o m h o s t(P C)v e r s i o n-p r i n t m o n i t o r v e r s i o n如果你想获取某条命令的更详细的帮助,可以使用:help <你想要查的指令>或者?<你想要查的指令>,甚至h <你想要查的指令缩写>。

常用的uboot的bootargs设置

常用的uboot的bootargs设置

常用的uboot的bootargs设置说完常见的几种bootargs,那么我们来讨论平常我经常使用的几种组合:1). 假设文件系统是ramdisk,且直接就在内存中,bootargs的设置应该如下:setenv bootargs ‘initrd=0x32000000,0xa00000 root=/dev/ram0 console=ttySAC0 mem=64M init=/linuxrc’2). 假设文件系统是ramdisk,且在flash中,bootargs的设置应该如下:setenv bootargs ‘mem=32M console=ttyS0,115200 root=/dev/ram rw init=/linuxrc’注意这种情况下你应该要在bootm命令中指定ramdisk在flash 中的地址,如bootm kernel_addr ramdisk_addr (fdt_addr)3). 假设文件系统是jffs2类型的,且在flash中,bootargs的设置应该如下setenv bootargs ‘mem=32M console=ttyS0,115200 noinitrd root=/dev/mtdblock2 rw rootfstype=jffs2 init=/linuxrc’4). 假设文件系统是基于nfs的,bootargs的设置应该如下setenv bootargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5:192.168.0.3:192.168.0.3:255.255.255.0::eth0:off’或者setenv bootargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5’上面就是我们经常使用的几种bootargs的组合,老实说,bootargs非常非常的灵活,所以设置的方法有很多中形式,具体的还应该根据你的平台具体的情况来设置。

bootcmd及bootargs命令

bootcmd及bootargs命令

U-boot的环境变量值得注意的有两个:bootcmd 和bootargs。

u-bootcmdbootcmd是自动启动时默认执行的一些命令,因此可以在当前环境中定义各种不同配置,不同环境的参数设置,然后设置bootcmd为经常使用的那种参数。

u-bootargsbootargs是环境变量中的重中之重,甚至可以说整个环境变量都是围绕着bootargs来设置的。

A. root用来指定rootfs的位置,常见的情况有:root=/dev/ram rwroot=/dev/mtdx rwroot=/dev/mtdblockx rwroot=/dev/mtdblock/x rwroot=31:0x上面的这几个在一定情况下是通用的,当然这要看你当前的系统是否支持,不过mtd是字符设备,而mtdblock是块设备,有时候你的挨个的试到底当前的系统支持上面那种情况下,不过root=/dev/mtdblockx rw比较通用。

此外,如果直接指定设备名可以的话,那么使用此设备的设备号也是可以的。

root=/dev/nfs在文件系统为基于nfs的文件系统的时候使用。

当然指定root=/dev/nfs之后,还需要指定nfsroot=serverip:nfs_dir,即指明文件系统存在那个主机的那个目录下面。

B. rootfstype这个选项需要跟root一起配合使用,一般如果根文件系统是ext2的话,有没有这个选项是无所谓的,但是如果是jffs2,squashfs等文件系统的话,就需要rootfstype指明文件系统的类型,不然会无法挂载根分区.C. consoleconsole=tty 使用虚拟串口终端设备.console=ttyS[,options] 使用特定的串口,options可以是这样的形式bbbbpnx,这里bbbb是指串口的波特率,p是奇偶位(从来没有看过使用过),n是指的bits。

D. memmem=xxM 指定内存的大小,不是必须的E. ramdisk_sizeramdisk_size=xxxxx 推荐上面这两个都可以告诉ramdisk 驱动,创建的ramdisk的size,默认情况下是4m(s390默认8M),你可以查看Documentation/ramdisk.txt找到相关的描述。

uboot启动参数,机器码,环境变量

uboot启动参数,机器码,环境变量

uboot启动参数,机器码,环境变量uboot启动参数,机器码,环境变量分类: linux应用 2011-07-05 09:12 217人阅读评论(0) 收藏举报这些都是以前的帖子,现在移动到这里来了,,嘻嘻!!注意的问题总结:1.内核参数传递内核中的参数是内核提供的,在配置内核时指定,而u-boot提供的则在u-boot启动时传递到内核取代内核提供的。

u-boot的参数传递利用了三个通用寄存器R0,R1,R2。

u-boot在启动的过程中把参数放到3个寄存器中,到内核启动时再把寄存器中的参数取出。

一般我们需要通过u-boot/tools/目录下的mkimage制作uImage,使用bootm命令进行加载,注意go命令是不传递内核参数的。

mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image选项:-A:set architecture to 'arch' //用于指定CPU类型,比如ARM-O:set operating system to 'os' //用于指定操作系统,比如Linux-T:set image type to 'type' //用于指定image类型,比如Kernel-C:set compression type 'comp' //指定压缩类型-a:set load address to 'addr' (hex) //指定image的载入地址-e:set entry point to 'ep' (hex) //内核的入口地址,一般为image的载入地址+0x40(信息头的大小)-n:set image name to 'name' //image在头结构中的命名-d:use image data from 'datafile' //无头信息的image文件名-x:set XIP (execute in place) //设置执行位置例如:mkimage -n 'linux-2.6.30.4' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage uImage.img 注意内核的加载地址是内存的起始地址+0x8000,0x40是64k的头部,是mkimage加上去的,0x30008040是内核第一条指令所在的地址。

从bootm看u-boot引导内核的过程

从bootm看u-boot引导内核的过程

我们知道,在u-boot中可以使用bootm这个命令来引导uclinux内核,那么其具体的过程是怎样的呢?1.1.1bootm的命令参数通过help bootm命令可以知道bootm所带的参数,以下内容来自于u-boot /common/cmd-bootm.c:U_BOOT_CMD(bootm, CFG_MAXARGS, 1, do_bootm,"bootm - boot application image from memory\n","[addr [arg ...]]\n - boot application image stored in memory\n""\tpassing arguments &apos;arg ...&apos;; when booting a Linux kernel,\n""\t&apos;arg&apos; can be the address of an initrd image\n");从这里可以知道,bootm后面可以带两个参数,一个是内核所在的地址,这个地址就是通过tftp或者loadx指令下载内核时的存放地址,另一个可以指明initrd所处的位置。

1.1.2do_bootm在u-boot检测到bootm命令后,它将调用do_bootm这个函数进行内核引导:int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ulong iflag;ulong addr;ulong data, len, checksum;ulong *len_ptr;uint unc_len = CFG_BOOTM_LEN;int i, verify;char*name, *s;int(*appl)(int, char *[]);image_header_t *hdr = &header;/*1、提取命令行中的地址参数。

uboot启动阶段修改启动参数方法及分析

uboot启动阶段修改启动参数方法及分析

uboot启动阶段修改启动参数⽅法及分析作者:围补本来启动⽅式这节不是什么复杂的事⼉,不过想简单的说清楚明⽩,还真是不知道怎么组织。

毕竟⽂字跟有声语⾔表达有别。

但愿简单的东西别让我讲的太复杂!Arm板系统⽂件⼀般有三个——bootloader(uboot)、kernel(uImage)及根⽂件系统(rootfs)。

在arm板上电后,按uboot->kernel->rootfs的顺序依次启动。

由于开发板上有多种存储介质,三个⽂件可以放在任何可以存储的介质上,因此也就导致⽂件的多种启动⽅式。

本⽂就来讨论,以上三个⽂件对应不通存放位置的不同启动配置。

⼀般开发板上会有flash(Nor or NAND),mmc,emmc,sd卡等。

系统⽂件可以烧写在其中的任意⼀种上,因此也就对应不通的启动。

在开发过程中,有时经常需要改动内核,或者修改应⽤程序,如果每次都修改后都重新烧写到板上的存储介质,会⽐较⿇烦。

因此,为⽅便调试,uImage和rootfs还可以从⽹络启动,即nfs启动。

但uboot只能从板上介质启动。

启动过程其实是先将要启动的⽂件从存储位置拷贝到内存空间,再在内存中运⾏。

因此所谓不同位置启动,也就是从不同位置拷贝⽽已。

下⾯我们以开发板启动为例,分别介绍三个⽂件从不同位置启动的过程⽅法。

我使⽤的开发板上有emmc和两个sd卡。

我们按照启动顺序,依次介绍。

⾸先是uboot启动。

Uboot是三个系统⽂件中第⼀个启动的,对它的拷贝⼯作由cpu中的固件决定。

固件中⽀持从⼏个位置拷贝uboot,它就能存放在⼏个位置上。

⾄于每次启动具体从其中的哪⾥开始,硬件拨码开关决定,对应拨码在开发板⼿册上能查到。

启动之前,先将uboot的⼆进制⽂件拷贝到对应介质。

有两种不同⽅法烧写,如下:1. uboot⼆进制⽂件拷贝到emmc,是通过芯⽚供应商的下载⼯具软件烧写完成;2. 拷贝到sd卡是在linux下,通过dd命令完成的。

uboot传递内核参数全解析

uboot传递内核参数全解析

uboot传递内核参数全解析一:启动参数的传递过程启动参数是包装在数据结构里的,在linux kernel启动的时候,bootloader把这个数据结构拷贝到某个地址,在改动PC跳向内核接口的同时,通过通用寄存器R2来传递这个地址的值,下面这句话就是uboot跳向linuxkernel的代码(bootm命令)theKernel (0, bd->bi_arch_number, bd->bi_boot_params);thekernel其实不是个函数,而是指向内核入口地址的指针,把它强行转化为带三个参数的函数指针,会把三个参数保存到通用寄存器中,实现了向kernel传递信息的功能,在这个例子里,会把R0赋值为0,R1赋值为机器号R2赋值为启动参数数据结构的首地址因此,要向内核传递参数很简单,只要把启动参数封装在linux预定好的数据结构里,拷贝到某个地址(一般约定俗成是内存首地址+100dex)二:启动参数的数据结构启动参数可保存在两种数据结构中,param_struct和tag,前者是2.4内核用的,后者是2.6以后的内核更期望用的但是,到目前为止,2.6的内核也可以兼容前一种结构,两种数据结构具体定义如下(arm cpu):struct param_struct {union {struct {unsigned long page_size; /* 0 */unsigned long nr_pages; /* 4 */unsigned long ramdisk_size; /* 8 */unsigned long flags; /* 12 */#define FLAG_READONLY 1#define FLAG_RDLOAD 4#define FLAG_RDPROMPT 8unsigned long rootdev; /* 16 */unsigned long video_num_cols; /* 20 */unsigned long video_num_rows; /* 24 */unsigned long video_x; /* 28 */unsigned long video_y; /* 32 */unsigned long memc_control_reg; /* 36 */unsigned char sounddefault; /* 40 */unsigned char adfsdrives; /* 41 */unsigned char bytes_per_char_h; /* 42 */unsigned char bytes_per_char_v; /* 43 */unsigned long pages_in_bank[4]; /* 44 */unsigned long pages_in_vram; /* 60 */unsigned long initrd_start; /* 64 */unsigned long initrd_size; /* 68 */unsigned long rd_start; /* 72 */unsigned long system_rev; /* 76 */unsigned long system_serial_low; /* 80 */unsigned long system_serial_high; /* 84 */unsigned long mem_fclk_21285; /* 88 */} s;char unused[256];} u1;union {char paths[8][128];struct {unsigned long magic;char n[1024 - sizeof(unsigned long)];} s;} u2;char commandline[COMMAND_LINE_SIZE];};param_struct只需要设置cmmandline,u1.s.page_size,u1.s.nr_pages三个域,具体使用可参见下面的例子对于tag来说,在实际使用中是一个struct tag组成的列表,在tag->tag_header中,一项是u32 tag(重名,注意类型)其值用宏ATAG_CORE,ATAG_MEM,ATAG_CMDLINE,ATAG_NONE等等来表示,此时下面union就会使用与之相关的数据结构同时,规定tag列表中第一项必须是ATAG_CORE,最后一项必须是ATAG_NONE,比如在linux代码中,找到启动参数之后首先看tag列表中的第一项的tag->hdr.tag是否为ATAG_CORE,如果不是,就会认为启动参数不是tag 结构而是param_struct结构,然后调用函数来转换.在tag->tag_header中,另一项是u32 size,表示tag的大小,tag组成列表的方式就是指针+size,实际使用中用tag_next (params).tag的具体使用见三中的例子struct tag {struct tag_header hdr;union {struct tag_core core;struct tag_mem32 mem;struct tag_videotext videotext;struct tag_ramdisk ramdisk;struct tag_initrd initrd;struct tag_serialnr serialnr;struct tag_revision revision;struct tag_videolfb videolfb;struct tag_cmdline cmdline;struct tag_acorn acorn; //Acorn specificstruct tag_omap omap; //OMAP specificstruct tag_memclk memclk; //DC21285 specific} u;};需要注意的是,这两个数据结构在uboot中和linux中分别有定义,这个定义必须一直才能正常传递参数如果实际使用中不一致的话就不能正常传递,可以自行修改三:通过两种数据结构传递参数的具体例子1:例子一:通过param_struct让uboot中的go命令可以传递参数分析:go的代码在common/cmd_boot.c中,里面并没有拷贝启动参数的代码,转向内核的时候也没有传送启动参数所在的地址,因此添加如下代码用于拷贝参数,可以看到,对于param_struct只需要设置cmmandlineu1.s.page_size,u1.s.nr_pages三个域char *commandline = getenv("bootargs");struct param_struct *lxy_params=(struct param_struct *)0x80000100;printf("setup linux parameters at 0x80000100\n");memset(lxy_params,0,sizeof(struct param_struct));lxy_params->u1.s.page_size=(0x1<<12); //4K 这个是必须有的,否则无法启动lxy_params->u1.s.nr_pages=(0x4000000)>>12; //64M 这个是必须有的,否则无法启动memcpy(lxy_params->commandline,commandline,strlen(commandline)+1);printf("linux command line is: \"%s\"\n",lxy_params->commandline);然后还要向内核传递参数地址,将下面一行代码修改:rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]); //需要被修改的代码rc = ((ulong(*)(int,int,uint))addr) (0, gd->bd->bi_arch_number,gd->bd->bi_boot_params);//修改之后的代码2:例子二:bootm命令中通过拷贝tag传递参数为方便阅读,进行了少许修改,但功能不变,该函数参数为存放启动参数的地址static void setup_linux_tag(ulong param_base){struct tag *params = (struct tag *)param_base;char *linux_cmd;char *p;memset(params, 0, sizeof(struct tag));/* step1: setup start tag */params->hdr.tag = ATAG_CORE;params->hdr.size = tag_size(tag_core);params->u.core.flags = 0;params->u.core.pagesize = LINUX_PAGE_SIZE;params->u.core.rootdev = 0;params = tag_next(params);/* step2: setup cmdline tag */params->hdr.tag = ATAG_CMDLINE;linux_cmd = getenv("bootargs");/* eat leading white space */for (p=linux_cmd; *p==' '; p++) {/* do nothing */;}params->hdr.size = (sizeof(struct tag_header)+strlen(linux_cmd)+1+4) >> 2;memcpy(params->u.cmdline.cmdline, linux_cmd, strlen(linux_cmd)+1);params = tag_next(params);/* step3: setup end tag */params->hdr.tag = ATAG_NONE;params->hdr.size = 0;}四:其他在uboot中,进行设置tag的函数都在lib_arm/armlinux.c中,在这些函数前面是有ifdef的#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)因此,如果你的bootm命令不能传递内核参数,就应该是在你的board的config文件里没有对上述的宏进行设置,定义一下即可。

Uboot命令详解

Uboot命令详解

U-Boot命令详解U-Boot还提供了更加周详的命令帮助,通过help命令还能够查看每个命令的参数说明。

由于研发过程的需要,有必要先把U-Boot命令的用法弄清楚。

接下来,根据每一条命令的帮助信息,解释一下这些命令的功能和参数。

1、bootmbootm [addr [arg ...]]- boot application image stored in memorypassing arguments ’arg ...’; when booting a Linux kernel,’arg’ can be the address of an initrd imagebootm命令能够引导启动存储在内存中的程式映像。

这些内存包括RAM和能够永久保存的Flash。

第1个参数addr是程式映像的地址,这个程式映像必须转换成U-Boot的格式。

第2个参数对于引导Linux内核有用,通常作为U-Boot格式的RAMDISK映像存储地址;也能够是传递给Linux内核的参数(缺省情况下传递bootargs环境变量给内核)。

2、bootpbootp [loadAddress] [bootfilename]bootp命令通过bootp请求,需要DHCP服务器分配IP地址,然后通过TFTP协议下载指定的文档到内存。

第1个参数是下载文档存放的内存地址。

第2个参数是要下载的文档名称,这个文档应该在研发主机上准备好。

3、cmpcmp [.b, .w, .l] addr1 addr2 count- compare memorycmp命令能够比较2块内存中的内容。

.b以字节为单位;.w以字为单位;.l以长字为单位。

注意:cmp.b中间不能保留空格,需要连续敲入命令。

第1个参数addr1是第一块内存的起始地址。

第2个参数addr2是第二块内存的起始地址。

第3个参数count是要比较的数目,单位按照字节、字或长字。

4、cpcp [.b, .w, .l] source target count- copy memorycp命令能够在内存中复制数据块,包括对Flash的读写操作。

uboot启动代码详解

uboot启动代码详解

·1 引言在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越流行;一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次:1. 引导加载程序;固化在固件firmware中的 boot 代码,也就是 Boot Loader,它的启动通常分为两个阶段;内核;特定于嵌入式板子的定制内核以及内核的启动参数;3.文件系统;包括根文件系统和建立于 Flash 内存设备之上文件系统,root fs;4.用户应用程序;特定于用户的应用程序;有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面;常用的嵌入式 GUI 有:MicroWindows 和 MiniGUI 等;引导加载程序是系统加电后运行的第一段软件代码;回忆一下 PC 的体系结构我们可以知道,PC 机中的引导加载程序由 BIOS其本质就是一段固件程序和位于硬盘 MBR 中的OS Boot Loader比如,LILO 和 GRUB 等一起组成;BIOS 在完成硬件检测和资源分配后,将硬盘 MBR 中的 Boot Loader 读到系统的 RAM 中,然后将控制权交给 OS BootLoader;Boot Loader 的主要运行任务就是将内核映象从硬盘上读到 RAM 中,然后跳转到内核的入口点去运行,也即开始启动操作系统;而在嵌入式系统中,通常并没有像 BIOS 那样的固件程序注,有的嵌入式 CPU 也会内嵌一段短小的启动程序,因此整个系统的加载启动任务就完全由 Boot Loader 来完成;比如在一个基于 ARM7TDMI core 的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000 处开始执行,而在这个地址处安排的通常就是系统的 Boot Loader 程序;·2 bootloader简介简单地说,Boot Loader 引导加载程序就是在操作系统内核运行之前运行的一段小程序,它的作用就是加载操作系统,它是系统加电后运行的第一段软件代码;通过这段代码实现硬件的初始化,建立内存空间的映射图,为操作系统内核准备好硬件环境并引导内核的启动;如上图所示的那样在设备的启动过程中bootloader位于最底层,首先被运行来引导操作系统运行,很容易可以看出 bootloader是底层程序所以它的实现严重地依赖于硬件,特别是在嵌入式世界;因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的;尽管如此,一些功能强大、支持硬件环境较多的BootLoader也被广大的使用者和爱好者所支持,从而形成了一些被广泛认可的、较为通用的的bootloader实现;Boot Loader 所支持的 CPU 和嵌入式板每种不同的 CPU 体系结构都有不同的 Boot Loader;有些 Boot Loader 也支持多种体系结构的 CPU,比如 U-Boot 就同时支持 ARM 体系结构和MIPS 体系结构;除了依赖于 CPU 的体系结构外,Boot Loader 实际上也依赖于具体的嵌入式板级设备的配置;这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种 CPU 而构建的,要想让运行在一块板子上的 Boot Loader 程序也能运行在另一块板子上,通常也都需要修改 Boot Loader 的源程序;Boot Loader 的安装媒介Installation Medium系统加电或复位后,所有的 CPU 通常都从某个由 CPU 制造商预先安排的地址上取指令;比如,基于 ARM7TDMI core 的 CPU 在复位时通常都从地址 0x00000000 取它的第一条指令;而基于 CPU 构建的嵌入式系统通常都有某种类型的固态存储设备比如:ROM、EEPROM 或 FLASH 等被映射到这个预先安排的地址上;因此在系统加电后,CPU 将首先执行 Boot Loader 程序;下图1就是一个同时装有 Boot Loader、内核的启动参数、内核映像和根文件系统映像的固态存储设备的典型空间分配结构图:图1 固态存储设备的典型空间分配结构Boot Loader 的启动过程:单阶段Single Stage/多阶段Multi-Stage通常多阶段的 Boot Loader 能提供更为复杂的功能,以及更好的可移植性;从固态存储设备上启动的 Boot Loader 大多都是 2 阶段的启动过程,也即启动过程可以分为 stage 1 和 stage 2 两部分;而至于在 stage 1 和 stage 2 具体完成哪些任务将在下面讨论;Boot Loader 的操作模式 Operation Mode大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义;但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别;启动加载Boot loading模式:这种模式也称为"自主"Autonomous模式;也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入;这种模式是 Boot Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下;下载Downloading模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机Host下载文件,比如:下载内核映像和根文件系统映像等;从主机下载的文件通常首先被 Boot Loader 保存到目标机的 RAM 中,然后再被 Boot Loader 写到目标机上的FLASH 类固态存储设备中;Boot Loader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot Loader 的这种工作模式;工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的菜单界面或命令行接口来接收要执行的操作;像 Blob 或 U-Boot 等这样功能强大的 Boot Loader 通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换;比如,Blob 在启动时处于正常的启动加载模式,但是它会延时 10 秒等待终端用户按下任意键而将 blob 切换到下载模式;如果在10 秒内没有用户按键,则 blob 继续启动 Linux 内核;常见的Boot LoaderU-BOOT:U-Boot是Das U-Boot的简称,其含义是Universal Boot Loader,是遵循GPL条款的开放源码项目;uboot是一个庞大的公开源码的软件;它支持一些系列的arm体系,包含常见的外设的驱动,是一个功能强大的板极支持包;vivi:vivi是韩国mizi 公司开发的bootloader, 适用于ARM9处理器; Vivi也有两种工作模式:启动加载模式和下载模式;启动加载模式可以在一段时间后这个时间可更改自行启动linux内核,这是vivi的默认模式;如果修改或更新需要进入下载模式,在下载模式下,vivi为用户提供一个命令行接口通过接口可以使用vivi提供的一些命令,来实现flash 的烧写、管理、操作mtd分区信息、启动系统等功能;U-BOOT的目录结构·3 Boot Loader 的主要任务与典型结构框架从操作系统的角度看,Boot Loader 的总目标就是正确地调用内核来执行;另外,由于Boot Loader 的实现依赖于 CPU 的体系结构,因此大多数 Boot Loader 都分为 stage1 和stage2 两大部分;依赖于 CPU 体系结构的代码,比如设备初始化代码等,通常都放在stage1 中,而且通常都用汇编语言来实现,以达到短小精悍的目的;而 stage2 则通常用C 语言来实现,这样可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性;以u-boot为例,它启动过程的两个阶段stage 如下:·第一阶段stage 1 cpu/arm920t/依赖于CPU体系结构的代码如设备初始化代码等,一般用汇编语言来实现;主要进行以下方面的设置:设置ARM进入SVC模式、禁止IRQ和FIQ、关闭看门狗、屏蔽所有中断;设置时钟FCLK,HCLK,PCLK、清空I/D cache、清空TLB、禁止MMU和cache、配置内存控制器、为搬运代码做准备、搬移uboot映像到RAM中使用copy_loop实现、分配堆栈、清空bss 段使用clbss_l实现;最后通过ldr pc, _start_armboot跳转到第二阶段;·第二阶段stage 2 lib_arm/该阶段主要都是用C语言来实现;start_armboot进行一系列初始化cpu, 板卡,中断,串口,控制台等,开启I/D cache;初始化FLASH,根据系统配置执行其他初始化操作;打印LOG,使能中断,获取环境变量,初始化网卡;最后进入main_loop函数;综上所述,可简单的归纳两个阶段的功能如下:·第一阶段的功能:硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口·第二阶段的功能:初始化本阶段使用的硬件设备检测系统内存映射将内核从Flash读取到RAM中为内核设置启动参数调用内核U-Boot启动第一阶段流程如下:u-boot 的 stage1详细分析uboot的第一阶段设计的非常巧妙,几乎都是用汇编语言实现的;首先我们来看一下它的链接脚本u-boot-1.1.6\board\smdk2410\,通过它我们可以知道它整个程序的各个段是怎么存放的;它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置;/ 指定输出可执行文件是elf 格式,32 位ARM 指令,小端 /OUTPUT_FORMAT"elf32-littlearm", "elf32-littlearm", "elf32-littlearm"/ 指定输出可执行文件的平台架构为ARM架构 /OUTPUT_ARCHarm/ 指定输出可执行文件的起始代码段为_start /ENTRY_startSECTIONS{. = 0x00000000;= ALIGN4;ext :extext= ALIGN4; 表示当前值.rodata : { .rodata }= ALIGN4;.data : { .data }= ALIGN4;.got : { .got }= .;__u_boot_cmd_start = .;_boot_cmd : { .u_boot_cmd }= ALIGN4;__bss_start = .;ss : { .bss }_end = .;3.1.1lobl 和.global 相同;lobl _start / u-boot启动入口 /_start: b reset / 复位/ldr pc, _undefined_instruction / 未定义指令向量 /ldr pc, _software_interrupt / 软件中断向量 /ldr pc, _prefetch_abort / 预取指令异常向量 /ldr pc, _data_abort / 数据操作异常向量 /ldr pc, _not_used / 未使用 /ldr pc, _irq / irq中断向量 /ldr pc, _fiq / fiq中断向量 // 中断向量表入口地址 /ong 和.int 作用与之相同;_undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort_data_abort: .word data_abort_not_used: .word not_used_irq: .word irq_fiq: .word fiq.balignl 16,0xdeadbeef以上代码设置了ARM异常向量表,各个异常向量介绍如下:在cpu/arm920t/中还有这些异常对应的异常处理程序;当一个异常产生时,CPU根据异常号在异常向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU就跳转到对应的异常处理程序执行;其中复位异常向量的指令“b reset”决定了U-Boot启动后将自动跳转到标号reset 处执行;许多人都认为_start的值是0x00000000,为什么是这个地址呢因为连接脚本上指定了;真的是这样吗我们来看看我们编译好之后,在u-boot目录下有个,这里面有各个变量的值,其中会告诉你,_start的值为:0x33f80000;注意,这里有两个地址:编译地址和运行地址;什么是编译地址什么是运行地址32 位的处理器,它的每一条指令是4个字节,以4个字节存储顺序,进行顺序执行,CPU 是顺序执行的,只要没发生什么跳转,它会顺序进行执行,编译器会对每一条指令分配一个编译地址,这是编译器分配的,在编译过程中分配的地址,我们称之为编译地址;运行地址是指,程序指令真正运行的地址,是由用户指定的,用户将运行地址烧录到哪里,哪里就是运行的地址;编译地址和运行地址如何来算呢假如有两个编译地址a=0x10,b=0x7,b的运行地址是0x300 ,那么a的运行地址就是b的运行地址加上两者编译地址的差值,a-b=0x10-0x7=0x3,a的运行地址就是0x300+0x3=0x303;2CPU进入SVC模式start_code:/set the cpu to SVC32 mode/mrs r0, cpsrbic r0, r0, 0x1f /工作模式位清零 /orr r0, r0, 0xd3 /工作模式位设置为“10011”管理模式,并将中断禁止位和快中断禁止位置1 /msr cpsr, r0以上代码将CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止位置一,从而屏蔽了IRQ和FIQ中断;3设置控制寄存器地址if definedCONFIG_S3C2400define pWTCON 0xdefine INTMSK 0xdefine CLKDIVN 0xelse / s3c2410与s3c2440下面4个寄存器地址相同 /define pWTCON 0x / WATCHDOG控制寄存器地址/define INTMSK 0x4A000008 / INTMSK寄存器地址 /define INTSUBMSK 0x4A00001C / INTSUBMSK寄存器地址 /define CLKDIVN 0x4C000014 / CLKDIVN寄存器地址 /endif对于s3c2440开发板,以上代码完成了WATCHDOG,INTMSK,INTSUBMSK,CLKDIVN四个寄存器的地址的设置;4关闭看门狗ldr r0, =pWTCONmov r1, 0x0str r1, r0 / 看门狗控制器的最低位为0时,看门狗不输出复位信号 /以上代码向看门狗控制寄存器写入0,关闭看门狗;为什么需要关闭看门狗呢这里有个喂狗的过程,所谓的喂狗是每隔一段时间给某个寄存器置位而已,在实际中会专门启动一个线程或进程会专门喂狗,当上层软件出现故障时就会停止喂狗,停止喂狗之后,cpu会自动复位,一般都在外部专门有一个看门狗,做一个外部的电路,不在cpu内部使用看门狗,否则在U-Boot启动过程中,CPU将不断重启;5屏蔽中断/mask all IRQs by setting all bits in the INTMR - default/mov r1, 0xffffffff / 某位被置1则对应的中断被屏蔽 /ldr r0, =INTMSKstr r1, r0INTMSK是主中断屏蔽寄存器,每一位对应SRCPND中断源引脚寄存器中的一位,表明SRCPND相应位代表的中断请求是否被CPU所处理;INTMSK寄存器是一个32位的寄存器,每位对应一个中断,向其中写入0xffffffff就将INTMSK寄存器全部位置1,从而屏蔽对应的中断;为什么要关闭中断呢中断处理ldr pc ..是将代码的编译地址放在了指针上,而这段时间内还没有搬移代码,所以不能进行跳转;if definedCONFIG_S3C2440ldr r1, =0x7fffldr r0, =INTSUBMSKstr r1, r0endifINTSUBMSK每一位对应SUBSRCPND中的一位,表明SUBSRCPND相应位代表的中断请求是否被CPU所处理;INTSUBMSK寄存器是一个32位的寄存器,但是只使用了低15位;向其中写入0x7fff就是将INTSUBMSK寄存器全部有效位低15位置1,从而屏蔽对应的中断;6设置MPLLCON,UPLLCON, CLKDIVNif definedCONFIG_S3C2440define MPLLCON 0x4C000004define UPLLCON 0x4C000008ldr r0, =CLKDIVNmov r1, 5str r1, r0ldr r0, =MPLLCONldr r1, =0x7F021str r1, r0ldr r0, =UPLLCONldr r1, =0x38022str r1, r0else/ FCLK:HCLK:PCLK = 1:2:4 // default FCLK is 120 MHz /ldr r0, =CLKDIVNmov r1, 3str r1, r0endifCPU上电几毫秒后,晶振输出稳定,FCLK=Fin晶振频率,CPU开始执行指令;但实际上,FCLK可以高于Fin,为了提高系统时钟,需要用软件来启用PLL;这就需要设置CLKDIVN,MPLLCON,UPLLCON这3个寄存器;CLKDIVN寄存器用于设置FCLK,HCLK,PCLK三者间的比例如下:设置CLKDIVN 为5,就将HDIVN 设置为二进制的10,由于CAMDIVN9没有被改变过,取默认值0,因此HCLK = FCLK/4;PDIVN 被设置为1,因此PCLK= HCLK/2;因此分频比FCLK:HCLK:PCLK = 1:4:8 ;MPLLCON 寄存器用于设置FCLK 与Fin 的倍数;MPLLCON 的位19:12称为MDIV,位9:4称为PDIV,位1:0称为SDIV;对于S3C2440,FCLK 与Fin 的关系如下面公式:MPLLCON 与UPLLCON 通常设置如下:当s3c2440系统主频设置为405MHZ,USB时钟频率设置为48MHZ时,系统可以稳定运行,因此设置MPLLCON与UPLLCON为:MPLLCON=0x7f<<12 | 0x02<<4 | 0x01 = 0x7f021UPLLCON=0x38<<12 | 0x02<<4 | 0x02 = 0x380227关闭MMU,cache接着往下看:ifndef CONFIG_SKIP_LOWLEVEL_INITbl cpu_init_critendifcpu_init_crit这段代码在U-Boot正常启动时才需要执行,若将U-Boot从RAM中启动则应该注释掉这段代码;下面分析一下cpu_init_crit到底做了什么:ifndef CONFIG_SKIP_LOWLEVEL_INITcpu_init_crit:/使数据cache与指令cache无效 //mcr p15, 0, r0, c7, c7, 0 / 向c7写入0将使ICache与DCache无效/ mcr p15, 0, r0, c8, c7, 0 / 向c8写入0将使TLB失效 //disable MMU stuff and caches/mrc p15, 0, r0, c1, c0, 0 / 读出控制寄存器到r0中 /bic r0, r0, 0x00002300 clear bits 13, 9:8 --V- --RSbic r0, r0, 0x00000087 clear bits 7, 2:0 B--- -CAMorr r0, r0, 0x00000002 set bit 2 A Alignorr r0, r0, 0x00001000 set bit 12 I I-Cachemcr p15, 0, r0, c1, c0, 0 / 保存r0到控制寄存器 //before relocating, we have to setup RAM timingbecause memory timing is board-dependend, you willfind a in your board directory./mov ip, lrbl lowlevel_initmov pc, lrendif / CONFIG_SKIP_LOWLEVEL_INIT /代码中的c0,c1,c7,c8都是ARM920T的协处理器CP15的寄存器;其中c7是cache控制寄存器,c8是TLB控制寄存器;将0写入c7、c8,使Cache,TLB内容无效;通过修改CP15的c1寄存器来关闭了MMU;为什么要关闭catch 和MMU 呢catch 和MMU 是做什么用的catch 是cpu内部的一个2级缓存,她的作用是将常用的数据和指令放在cpu内部,MMU 是用来做虚实地址转换用的,我们的目的是设置控制的寄存器,寄存器都是实地址,如果既要开启MMU又要做虚实地址转换的话,中间还多一步,先要把实地址转换成虚地址,然后再做设置,但对uboot 而言就是起到一个简单的初始化的作用和引导操作系统,如果开启MMU 的话,很麻烦,也没必要,所以关闭MMU.说到catch 就必须提到一个关键字Volatile,以后在设置寄存器时会经常遇到,他的本质是告诉编译器不要对我的代码进行优化,优化的过程是将常用的代码取出来放到catch 中,它没有从实际的物理地址去取,它直接从cpu的缓存中去取,但常用的代码就是为了感知一些常用变量的变化,所以在这种情况下要用Volatile关键字告诉编译器不要做优化,每次从实际的物理地址中去取指令;8初始化RAM控制寄存器其中的bl lowlevel_init用于初始化各个bank,完成了内存初始化的工作,由于内存初始化是依赖于开发板的,因此lowlevel_init的代码一般放在board下面相应的目录中;对于s3c2440,lowlevel_init在board/smdk2440/中定义如下:define BWSCON 0x / 13个存储控制器的开始地址 /… …_TEXT_BASE:.word TEXT_BASE.globl lowlevel_initlowlevel_init:/ memory control configuration // make r0 relative the current location so that it // reads SMRDATA out of FLASH rather than memory /ldr r0, =SMRDATAldr r1, _TEXT_BASEsub r0, r0, r1 / SMRDATA减 _TEXT_BASE就是13个寄存器的偏移地址 / ldr r1, =BWSCON / Bus Width Status Controller /add r2, r0, 1340:ldr r3, r0, 4 /将13个寄存器的值逐一赋值给对应的寄存器/str r3, r1, 4cmp r2, r0bne 0b/ everything is fine now /mov pc, lr.ltorg/ the literal pools origin /SMRDATA: / 下面是13个寄存器的值 /.word … ….word … …… …lowlevel_init的作用就是将SMRDATA开始的13个值复制给开始地址BWSCON的13个寄存器,从而完成了存储控制器的设置;9复制U-Boot第二阶段代码到RAMrelocate:adr r0, _start / r0 <- current position of code /ldr r1, _TEXT_BASE / test if we run from flash or RAM // 判断U-Boot是否是下载到RAM中运行,若是,则不用再复制到RAM中了,这种情况通常在调试U-Boot时才发生 /cmp r0, r1 /_start等于_TEXT_BASE说明是下载到RAM中运行 /beq stack_setupldr r2, _armboot_startldr r3, _bss_startsub r2, r3, r2 / r2 <- size of armboot /add r2, r0, r2 / r2 <- source end address // 搬运U-Boot自身到RAM中/copy_loop:ldmia r0,{r3-r10}/ 从地址为r0的NOR Flash中读入8个字的数据 /stmia r1,{r3-r10}/ 将r3至r10寄存器的数据复制给地址为r1的内存 /cmp r0, r2 / until source end addreee r2 /ble copy_loop终于到重点部分了:代码重定向拷贝stage2到RAM中,拷贝时要确定两点:1 stage2的可执行映象在固态存储设备的存放起始地址和终止地址;2 RAM空间的起始地址;下面我们来看看它到底是怎么重定向的:adr r0,_startadr伪指令,汇编器会将执行到_start时PC的值放到r0中;所以此时r0中保存的不是编译地址,而是运行地址;假如U-boot 是从RAM 开始运行,则从adr,r0,_start 得到的地址信息为r0=_start=_TEXT_BASE=TEXT_BASE=0x33f80000;假如U-boot 从Flash 开始运行,即从处理器对应的地址运行,则r0=0x00000000;而这里r0=0;ldr r1,_TEXT_BASE这条汇编指令的意思是把_TEXT_BASE的值作为地址,把这个地址的内容赋给r1,从下面可以知道:_TEXT_BASE里面存储的内容是TEXT_BASE,我们通过查看board/smdk2410/发现TEXT_BASE的值为0x33f80000,所以r1的值就是0x33f80000cmp r0,r1将r0和r1做比较,此时r0 = 0x00000000,r1 = 0x33f80000,显然不相等,那么执行的就是下面的汇编指令:ldr r2, _armboot_start由此可以知道r2的值是_start,通过ldr将标号的编译地址放到r2中,也就是0x33f80000,即代码段的起始地址;ldr r3, _bss_start有此可知,r3就是__bss_start的值;由的链接脚本可以知道,r3的值是整个代码得结尾.sub r2,r3,r2这条指令的意思是r2 = r3 -r2,即r2 = 代码结束 - 代码开始,这样得到的是r2 = 整个代码的大小;add r2,r0,r2这条指令的意思是r2 = r0 + r2,即 r2 = 代码开始 + 代码大小,这样得到的是r2 = falsh 里面代码的结尾,此时我们得到r0 = flash 代码的起始位置,r1 = 0x33f80000sdram :0x0 ~ 0x将flash里面的代码拷贝到sdram里面了;10设置堆栈/ 设置堆栈 /stack_setup:ldr r0, _TEXT_BASE / upper 128 KiB: relocated uboot /sub r0, r0, CONFIG_SYS_MALLOC_LEN / malloc area /sub r0, r0, CONFIG_SYS_GBL_DATA_SIZE / 跳过全局数据区 /ifdef CONFIG_USE_IRQsub r0, r0, CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQendifsub sp, r0, 12 / leave 3 words for abort-stack /只要将sp指针指向一段没有被使用的内存就完成栈的设置了;U-Boot内存使用情况如下图所示:11清除BSS段clear_bss:ldr r0, _bss_start / BSS段开始地址,在中指定/ldr r1, _bss_end / BSS段结束地址,在中指定/mov r2, 0x00000000clbss_l:str r2, r0 / 将bss段清零/add r0, r0, 4cmp r0, r1ble clbss_l初始值为0,无初始值的全局变量,静态变量将自动被放在BSS段;应该将这些变量的初始值赋为0,否则这些变量的初始值将是一个随机的值,若有些程序直接使用这些没有初始化的变量将引起未知的后果;12跳转到第二阶段代码入口ldr pc, _start_armboot_start_armboot: .word start_armboot跳转到第二阶段代码入口start_armboot处;Boot Loader 的 stage2详细分析start_armboot函数在lib_arm/中定义,是U-Boot第二阶段代码的入口;U-Boot启动第二阶段流程如下:正如前面所说,stage2 的代码通常用 C 语言来实现,以便于实现更复杂的功能和取得更好的代码可读性和可移植性;在分析start_armboot函数前先来看看一些重要的数据结构:1gd_t结构体U-Boot使用了一个结构体gd_t来存储全局数据区的数据,这个结构体在include/asm-arm/中定义如下:typedef struct global_data{bd_t bd; / 与板子相关的结构体,见下面 /unsigned long flags; / 选项 /unsigned long baudrate; / 波特率 /unsigned long have_console; / serial_init was called /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来记录全局数据区的地址: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 - sizeofgd_t2bd_t结构体bd_t在include/中定义如下:typedef struct bd_info{int bi_baudrate; / 串口通讯波特率 /unsigned long bi_ip_addr; / IP 地址/struct environment_s bi_env; / 环境变量开始地址 /ulong bi_arch_number; / 开发板的机器码 /ulong bi_boot_params; / 内核参数的开始地址 /struct / RAM配置信息 /{ulong start; / 起始地址 /ulong size; / 长度 /}bi_dramCONFIG_NR_DRAM_BANKS;}bd_t;U-Boot启动内核时要给内核传递参数,这时就要使用gd_t,bd_t结构体中的信息来设置标记列表;3init_sequence数组U-Boot使用一个数组init_sequence在lib_arm/中来存储对于大多数开发板都要执行的初始化函数的函数指针;init_sequence数组中有较多的编译选项,去掉编译选项后init_sequence数组如下所示:typedef int init_fnc_t void; / 这是使用typedef定义一个init_fnc_t为函数类型,该函数返回int型,无参数 /init_fnc_t init_sequence = { / 定义一个init_fnc_t指针类型的数组;简单的说就是定义了个函数指针数组,指向一系列cpu初始化函数 /cpu_init, / basic cpu dependent setup CPU的相关配置,如初始化IRQ/FIQ 模式的栈cpu/arm920t/ /board_init, / basic board dependent setup开发板相关配置,是对板子的初始化,设置MPLL,改变系统时钟,以及一些GPIO寄存器的值,还设置了U-Boot机器码和内核启动参数地址,它是开发板相关的函数,比如2410是在:board/smdk2410/中实现 /interrupt_init, / set up exceptions 初始化中断,在cpu/arm920t/s3c24x0/实现/env_init, / initialize environment 初始化环境变量,检查flash上的环境变量是否有效common/ 或common/ /init_baudrate, / initialze baudrate settings 初始化波特率lib_arm/ /serial_init, / serial communications setup串口初始化串口初始化后我们就可以打印信息了cpu/arm920t/s3c24x0/ /console_init_f, / stage 1 init of console 控制台初始化第一阶段common/ /display_banner, / say that we are here通知代码已经运行到该处,打印U-Boot 版本、编译的时间-- lib_arm/ /if definedCONFIG_DISPLAY_CPUINFOprint_cpuinfo, / display cpu info and speed /endifif definedCONFIG_DISPLAY_BOARDINFOcheckboard, / display board info /endifdram_init, / configure available RAM banks 配置可用的内存区,检测系统内存映射,设置内存的起始地址和大小board/smdk2410/ /display_dram_config,NULL,};可以看出这里定义了一个指针数组,它的每一个元素都是指针变量,这些指针变量指向的类型为init_fnc_t,在C语言中函数的入口地址就是函数名,所以这里使用一系列函数名来初始化这个数组;现在来看看到底做了哪些初始化工作:·cpu_init函数:cpu/arm920t/int cpu_init void{ifdef CONFIG_USE_IRQIRQ_STACK_START =_armboot_start-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE-4;FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;endifreturn 0;}其实这个函数没有做任何工作,因为CONFIG_USE_IRQ这个宏没有定义;实际上就是把IRQ_STACK_START、 FIQ_STACK_START指到RAM中的IRQ stuff区域;·board_init函数:board/smdk2410/int board_init void{/ 获取power和clock及GPIO方面的寄存器地址,稍后的操作会对这些寄存器操作,需要注意的是,像S3C24X0_CLOCK_POWER里面的field对象都是按照实际寄存器的地址来安排的 /S3C24X0_CLOCK_POWER const clk_power = S3C24X0_GetBase_CLOCK_POWER;S3C24X0_GPIO const gpio = S3C24X0_GetBase_GPIO;/ to reduce PLL lock time, adjust the LOCKTIME register降低PLL的lock time 的值/clk_power->LOCKTIME = 0xFFFFFF;/ configure MPLL配置MPLL /clk_power->MPLLCON = M_MDIV << 12 + M_PDIV << 4 + M_SDIV;/ some delay between MPLL and UPLL延时 /delay 4000;/ configure UPLL配置UPLL /clk_power->UPLLCON = U_M_MDIV << 12 + U_M_PDIV << 4 + U_M_SDIV;/ some delay between MPLL and UPLL延时 /delay 8000;/ 配置每个GPIO的功能,输入输出,等参数 /gpio->GPACON = 0x007FFFFF;gpio->GPBCON = 0x00044555;gpio->GPBUP = 0x000007FF;gpio->GPCCON = 0xAAAAAAAA;gpio->GPCUP = 0x0000FFFF;gpio->GPDCON = 0xAAAAAAAA;gpio->GPDUP = 0x0000FFFF;gpio->GPECON = 0xAAAAAAAA;gpio->GPEUP = 0x0000FFFF;gpio->GPFCON = 0x000055AA;gpio->GPFUP = 0x000000FF;gpio->GPGCON = 0xFF95FFBA;gpio->GPGUP = 0x0000FFFF;gpio->GPHCON = 0x002AFAAA;gpio->GPHUP = 0x000007FF;/ SMDK2410开发板的机器码 /gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;/ adress of boot parameters内核启动参数地址,运行时在linux内核之下 / gd->bd->bi_boot_params = 0x;/ 使能指令cache和数据cache /icache_enable;dcache_enable;return 0;}函数icache_enable和dcache_enable,定义在cpu/arm920t/中,这两个函数是通过修改CP15的c1寄存器来实现的,使能cache很简单,只要把协处理器15的相关位打开就行了,这里来是将c1的I、C位置1,来开启Icache、DCaches;我这里只分析icache_enable,dcache_enable类似;icache_enable具体实现如下:void icache_enable void{ulong reg;reg = read_p15_c1 ; / get control reg. 获取CP15的c1寄存器值存到reg中/cp_delay ;write_p15_c1 reg | C1_IC; /这里将C1寄存器的I、C位置1,来开启Icache、Dcaches/}这里须要理解的是read_p15_c1与write_p15_c1函数,它们分别在cpu/arm920t/中定义如下:static unsigned long read_p15_c1 void{unsigned long value;__asm__ __volatile__"mrc p15, 0, %0, c1, c0, 0 read control reg\n" / %0是参数传递时R0寄存器,其功能是读取CP15的c1寄存器值放到r0中/: "=r" value:: "memory";ifdef MMU_DEBUGprintf "p15/c1 is = %08lx\n", value;endifreturn value; 返回读取CP15的c1寄存器的值}/ write to co-processor 15, register 1 control register /static void write_p15_c1 unsigned long value{ifdef MMU_DEBUGprintf "write %08lx to p15/c1\n", value;endif__asm__ __volatile__"mcr p15, 0, %0, c1, c0, 0 write it back\n" 保存r0的值到控制寄存器CP15的c1寄存器中,因为函数参数传递时,第一个参数都是放在r0寄存器中的;:: "r" value: "memory";read_p15_c1 ;}·interrupt_init函数:cpu/arm920t/s3c24x0/int timer_load_val = 0;static ulong timestamp;static ulong lastdec;int interrupt_init void / 初始化timer4相关寄存器,用于产生10ms定时中断信号 /{/ 返回定时器配置寄存器地址0x,即TCFG0寄存器地址 /S3C24X0_TIMERS const timers = S3C24X0_GetBase_TIMERS;/ 这里使用定时器4,定时器4有只有一个内部定器没有输出管脚 // prescaler for Timer 4 is 16 /timers->TCFG0 = 0x0f00;if timer_load_val == 0{timer_load_val = get_PCLK/2 16 100; / get_PCLK返回PCLK频率 /}/ load value for 10 ms timeout /lastdec = timers->TCNTB4 = timer_load_val; / 设置计数缓存寄存器初始值 // 设置定时器4手动更新,自动加载模式,并关闭定时器4 /timers->TCON = timers->TCON & ~0x0700000 | 0x600000;/ auto load, 启动Timer 4 /timers->TCON = timers->TCON & ~0x0700000 | 0x500000;timestamp = 0;return 0;}对着datasheet来看这个函数, 实际上这个函数使用timer 4来作为系统clock, 即时钟滴答, 10ms一次,到点就产生一个中断,但由于此时中断还没打开所以这个中断不会响应;·env_init函数: 由于我们在inculde/configs/下定义了CFG_ENV_IS_IN_FLASH因此该函数位于common/下int env_initvoid{ifdef CONFIG_OMAP2420H4int flash_probevoid;ifflash_probe == 0goto bad_flash;endifif crc320, env_ptr->data, ENV_SIZE == env_ptr->crc {gd->env_addr = ulong&env_ptr->data;gd->env_valid = 1; / 使用include/configs/配置的环境变量则设置环境变量可用标志 /return0;}/ env_ptr在前面定义为env_t env_ptr = env_t CFG_ENV_ADDR;而CFG_ENV_ADDR被定义在include/configs/中了,这里判断如果校验正确即CFG_ENV_ADDR被定义了则环境变量的存放地址使用中定义的,否则使用后面的默认的环境变量值default_environment数组/ifdef CONFIG_OMAP2420H4bad_flash:endifgd->env_addr = ulong&default_environment0;gd->env_valid = 0; 使用默认的环境配置变量则设置环境变量不可用标志return 0;}这个函数主要是在gd里保存环境变量的存放地址;一般使用默认的环境变量值即default_environment数组,它在common/中定义如下:。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
或者
setenv bootargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5’
上面就是我们经常使用的几种bootargs的组合,老实说,bootargs非常非常的灵活,所以设置的方法有很多中形式,具体的还应该根据你的平台具体的情况来设置。
mtdparts的格式如下:
mtdparts=[;
:= :[,]
:= [@offset][][ro]
:= unique id used in mapping driver/device
:= standard linux memsize OR "-" to denote all remaining space
3). 假设文件系统是jffs2类型的,且在flash中,bootargs的设置应该如下
setenv bootargs ‘mem=32M console=ttyS0,115200 noinitrd root=/dev/mtdblock2 rw rootfstype=jffs2 init=/linuxrc’
这两种方法可以用,不过很明显第二种要详细很多,请注意第二种中which netcard 是指开发板上的网卡,而不是主机上的网卡。
说完常见的几种bootargs,那么我们来讨论平常我经常使用的几种组合:
1). 假设文件系统是ramdisk,且直接就在内存中,bootargs的设置应该如下:
setenv bootargs ‘initrd=0x32000000,0xa00000 root=/dev/ram0 console=ttySAC0 mem=64M init=/linuxrc’
举例:
假设flash 的mtd-id是sa1100,那么你可以使用下面的方式来设置:
mtdparts=sa1100:- → 只有一个分区
mtdparts=sa1100:256k(ARMboot)ro,-(root) → 有两个分区
可以查看rs/mtd/cmdlinepart.c中的注释找到相关描述。
4). 假设文件系统是基于nfs的,bootargs的设置应该如下
setenv bootargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5:192.168.0.3:192.168.0.3:255.255.255.0::eth0:off’
I. ip
指定系统启动之后网卡的ip地址,如果你使用基于nfs的文件系统,那么必须要有这个参数,其他的情况下就看你自己的喜好了。设置ip有两种方法:
ip = ip addr
ip=ip addr:server ip addr:gateway:netmask::which netcard:off
看你当前的环境,有时用ttyS,有时用ttySAC,网上有人说,这是跟内核的版本有关,2.4用ttyS,2.6用ttySAC,但实际情况是官方文档中也是使用ttyS,所以应该是跟内核版本没有关联的。可以查看Documentation/serial-console.txt找到相关描述。
D. mem
root=/dev/mtdblockx rw
root=/dev/mtdblock/x rw
root=31:0x
上面的这几个在一定情况下是通用的,当然这要看你当前的系统是否支持,不过mtd是字符设备,而mtdblock是块设备,有时候你的挨个的试到底当前的系统支持上面那种情况下,不过root=/dev/mtdblockx rw比较通用。此外,如果直接指定设备名可以的话,那么使用此设备的设备号也是可以的。
请注意上面的这两种设置情况是通用的,我做过测试甚至root=/dev/ram1 rw和root=/dev/ram2 rw也是可以的,网上有人说在某些情况下是不通用的,即必须设置成ram或者ram0,但是目前还没有遇到,还需要进一步确认,遇到不行的时候可以逐一尝试。
root=/dev/mtdx rw
root=/dev/nfs
在文件系统为基于nfs的文件系统的时候使用。当然指定root=/dev/nfs之后,还需要指定nfsroot=serverip:nfs_dir,即指明文件系统存在那个主机的那个目录下面。
B. rootfstype (根文件系统类型)
这个选项需要跟root一起配合使用,一般如果根文件系统是ext2的话,有没有这个选项是无所谓的,但是如果是jffs2,squashfs等文件系统的话,就需要rootfstype指明文件系统的类型,不然会无法挂载根分区.
mem=xxM 指定内存的大小,不是必须的
E. ramdisk_size
ramdisk=xxxxx 不推荐
ramdisk_size=xxxxx 推荐
上面这两个都可以告诉ramdisk 驱动,创建的ramdisk的size,默认情况下是4m(s390默认8M),你可以查看Documentation/ramdisk.txt找到相关的描述,不过ramdisk=xxxxx在新版的内核都已经没有提了,不推荐使用。
C. console
console=tty 使用虚拟串口终端设备 .
console=ttyS[,options] 使用特定的串口,options可以是这样的形式bbbbpnx,这里bbbb是指串口的波特率,p是奇偶位(从来没有看过使用过),n是指的bits。
console=ttySAC[,options] 同上面。
F. initrd, noinitrd
当你没有使用ramdisk启动系统的时候,你需要使用noinitrd这个参数,但是如果使用了的话,就需要指定initrd=r_addr,size, r_addr表示initrd在内存中的位置,size表示initrd的大小。
G. init
init指定的是内核启起来后,进入系统中运行的第一个脚本,一般init=/linuxrc, 或者init=/etc/preinit,preinit的内容一般是创建console,null设备节点,运行init程序,挂载一些文件系统等等操作。请注意,很多初学者以为init=/linuxrc是固定写法,其实不然,/linuxrc指的是/目录下面的linuxrc脚本,一般是一个连接罢了。
H. mtdparts
mtdparts=fc000000.nor_flash:1920k(linux),128k(fdt),20M(ramdisk),4M(jffs2),38272k(user),256k(env),384k(uboot)
要想这个参数起作用,内核中的mtd驱动必须要支持,即内核配置时需要选上Device Drivers ---> Memory Technology Device (MTD) support ---> Command line partition table parsing
2). 假设文件系统是ramdisk,且在flash中,bootargs的设置应该如下:
setenv bootargs ‘mem=32M console=ttyS0,115200 root=/dev/ram rw init=/linuxrc’
注意这种情况下你应该要在bootm命令中指定ramdisk在flash中的地址,如bootm kernel_addr ramdisk_addr (fdt_addr)
bootargs是环境变量中的重中之重,甚至可以说整个环境变量都是围绕着bootargs来设置的。bootargs的种类非常非常的多,我们平常只是使用了几种而已,感兴趣的可以看看这篇文章说的很全:/u2/79570/showart_1675071.html。bootargs非常的灵活,内核和文件系统的不同搭配就会有不同的设置方法,甚至你也可以不设置bootargs,而直接将其写到内核中去(在配置内核的选项中可以进行这样的设置),正是这些原因导致了bootargs使用上的困难。
U-boot的环境变量值得注意的有两个: bootcmd 和bootargs。
u-bootcmd
前面有说过bootcmd是自动启动时默认执行的一些命令,因此你可以在当前环境中定义各种不同配置,不同环境的参数设置,然后设置bootcmd为你经常使用的那种参数。
u-bootargs
下面介绍一下bootargs常用参数,bootargs的种类非常的多,而且随着kernel的发展会出现一些新的参数,使得设置会更加灵活多样。
A. root
用来指定rootfs的位置, 常见的情况有:
root=/dev/ram rw
root=/dev/ram0 rw
:= (NAME)
因此你在使用的时候需要按照下面的格式来设置:
mtdparts=mtd-id:@(),@()
这里面有几个必须要注意的:
a. mtd-id 必须要跟你当前平台的flash的mtd-id一致,不然整个mtdparts会失效
b. size在设置的时候可以为实际的size(xxM,xxk,xx),也可以为'-'这表示剩余的所有空间。
相关文档
最新文档