Uboot传递参数与kernel解析参数
- 格式:pdf
- 大小:207.02 KB
- 文档页数:6
《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命令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、内核以及⽂件系统⼀、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向内核模块传递参数的⽅法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启动过程--详细版的完全分析我们知道,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分区下⾯以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的容量。
所以肯定有些部分是相互包含在⼀起的。
作者: 哈泉新一、内核参数的传递U-Boot向Linux驱动传递参数的方式有两种,一为在系统启动的时候由bootloader传入,还有一种是将驱动编译成模块,将参数作为模块加载的参数传入。
内核通过setup接口接受Bootloader传入的参数。
方式如下:static int __init param_mac_setup(char *str){……}__setup(“mac=”, param_mac_setup);这样,当在Bootloader中指定“mac=00:2E:79:38:6D:4E”,系统在加载这个模块的时候,就会执行相应的param_mac_setup()函数,而传入给它的参数就是等号后面的物理地址“00:2E:79:38:6D:4E”。
这样,该函数就可以对它进行相应的处理。
在U-Boot中,默认设置mac地址的参数为ethaddr,我们可以用过setenv ethaddr Mac地址来设置开发板的mac地址。
二、bootm传递参数的方式在bootm执行的流程图中,可以看到会调用do_bootm_linux()在执行Linux内核,内核的起始地址如下:void (*theKernel)(int zero, int arch, uint params);image_header_t *hdr = &header;theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);header是uImage的头部,通过头部,得到内核映像起始的执行地址,标识为theKernel。
从中也可以看到,内核接受三个参数,第一个为0,第二个为系统的ID号,第三个是传入内核的参数。
在do_bootm_linux()的最后,会跳到内核去执行:theKernel (0, bd->bi_arch_number, bd->bi_boot_params);最后两个参数在board/smdk2410/smdk2410.c的board_init()中被初始化:/* arch number of SMDK2410-Board */gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* 193 *//* adress of boot parameters */gd->bd->bi_boot_params = 0×30000100;可以看到,U-Boot传给内核的参数表存放在内存中起始偏移0×100的位置,这里只是指定了“指针”的位置,但还没初始化其中的值,这是在do_bootm_linux()中跳到内核前去完成的。
linux grub 参数Linux Grub是一个开源的引导加载程序,用于在计算机启动时加载操作系统。
Grub的参数是在启动时传递给Grub引导程序的一系列选项和设置。
这些参数可以用于配置和调整系统的各种功能和行为。
本文将介绍几个常用的Grub参数,并详细解释它们的作用和用法。
1. root:指定系统根目录的设备或分区。
这个参数告诉Grub操作系统的根文件系统在哪里。
例如,root=/dev/sda1表示根文件系统位于第一个硬盘的第一个分区上。
2. kernel:指定要加载的操作系统内核文件。
这个参数告诉Grub 要加载哪个操作系统的内核。
例如,kernel /vmlinuz-5.4.0-42-generic表示要加载名为vmlinuz-5.4.0-42-generic的内核文件。
3. initrd:指定用于引导过程中的初始内存文件系统镜像。
这个参数告诉Grub在引导过程中使用哪个内存文件系统镜像。
例如,initrd /initrd.img-5.4.0-42-generic表示使用名为initrd.img-5.4.0-42-generic的镜像。
4. quiet:禁用内核启动信息的输出。
这个参数告诉Grub在启动过程中不显示任何启动信息。
这在需要静默启动系统时非常有用。
5. splash:显示启动画面。
这个参数告诉Grub在启动过程中显示一个启动画面,提供更好的用户体验。
6. single:以单用户模式启动系统。
这个参数告诉Grub在启动时进入单用户模式,只启动基本的系统服务。
这在需要进行系统维护或故障排除时非常有用。
7. nomodeset:禁用显卡的核心模式设置。
这个参数告诉Grub在启动过程中不使用显卡的核心模式设置,避免可能的显卡兼容性问题。
8. acpi=off:禁用高级配置和电源接口。
这个参数告诉Grub在启动过程中禁用高级配置和电源接口,可以解决一些与电源管理相关的问题。
9. noapic:禁用高级可编程中断控制器。
U B o o t中M A C地址设置及往内核中传递集团标准化小组:[VVOPPT-JOPP28-JPPTL98-LOPPNN]一、内核参数的传递U-Boot向Linux驱动传递参数的方式有两种,一为在系统启动的时候由bootloader传入,还有一种是将驱动编译成模块,将参数作为模块加载的参数传入。
内核通过setup接口接受Bootloader传入的参数。
方式如下:staticint__initparam_mac_setup(char*str){……}__setup(“mac=”,param_mac_setup);这样,当在Bootloader中指定“mac=00:2E:79:38:6D:4E”,系统在加载这个模块的时候,就会执行相应的param_mac_setup()函数,而传入给它的参数就是等号后面的物理地址“00:2E:79:38:6D:4E”。
这样,该函数就可以对它进行相应的处理。
在U-Boot中,默认设置mac地址的参数为ethaddr,我们可以用过setenvethaddrMac地址来设置开发板的mac地址。
二、bootm传递参数的方式在bootm执行的流程图中,可以看到会调用do_bootm_linux()在执行Linux内核,内核的起始地址如下:void(*theKernel)(intzero,intarch,uintparams);image_header_t*hdr=&header;theKernel=(void(*)(int,int,uint))ntohl(hdr->ih_ep);header是uImage的头部,通过头部,得到内核映像起始的执行地址,标识为theKernel。
从中也可以看到,内核接受三个参数,第一个为0,第二个为系统的ID号,第三个是传入内核的参数。
在do_bootm_linux()的最后,会跳到内核去执行:theKernel(0,bd->bi_arch_number,bd->bi_boot_params);最后两个参数在board/smdk2410/smdk2410.c的board_init()中被初始化:/*archnumberofSMDK2410-Board*/gd->bd->bi_arch_number=MACH_TYPE_SMDK2410;/*193*//*adressofbootparameters*/可以看到,U-Boot传给内核的参数表存放在内存中起始偏移0×100的位置,这里只是指定了“指针”的位置,但还没初始化其中的值,这是在do_bootm_linux()中跳到内核前去完成的。
u-boot向linux内核传递启动参数(详细)U-BOOT 在启动内核时,会向内核传递一些参数.BootLoader 可以通过两种方法传递参数给内核,一种是旧的参数结构方式(parameter_struct),主要是2.6 之前的内核使用的方式。
另外一种就是现在的2.6内核在用的参数链表(tagged list) 方式。
这些参数主要包括,系统的根设备标志,页面大小,内存的起始地址和大小,RAMDISK的起始地址和大小,压缩的RAMDISK根文件系统的起始地址和大小,当前内核命令参数等而这些参数是通过struct tag来传递的。
U-boot 把要传递给kernel 的东西保存在struct tag 数据结构中,启动kernel 时,把这个结构体的物理地址传给kernel;Linux kernel 通过这个地址分析出u-boot传递的参数。
大家都知道U-Boot启动的时候会将启动参数的地址放入R2中,然后再启动内核。
首先看两个重要的数据结构:第一个是global_data,定义在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 */#ifdef CONFIG_VFDunsigned char vfd_type; /* display type */#endif#if 0unsigned long cpu_clk; /* CPU clock in Hz! */unsigned long bus_clk;unsigned long ram_size; /* RAM size */unsigned long reset_status; /* reset status register at boot */#endifvoid **jt; /* jump table */} gd_t;在同一个文件中有如下定义:#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")在需要使用gd指针的时候,只需要加入DECLARE_GLOBAL_DATA_PTR这句话就可以了。
U-Boot提供了更加详细的命令帮助,通过help命令还可以查看每个命令的参数说明。
由于开发过程的需要,有必要先把U-Boot命令的用法弄清楚。
接下来,根据每一条命令的帮助信息,解释一下这些命令的功能和参数。
1、bootmdKNLinux联盟bootm [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环境变量给内核)。
dKNLinux联盟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是第二块内存的起始地址。
Linux启动bootargs参数分析这几天刚好在看linux c语言启动,现在就顺便把内核在启动时解析bootargs这一块单独拎出来讲解下,内核对于bootargs的解析分为几块:1.setup_arch(&command_line);综述:在这个函数中,系统会获得bootargs参数,并对其做简单的初步分析。
并将bootargs的参数保存在command_line这个地址中。
详解:A.先获得bootargs的地址,uboot传进来的参数是放在30000100的地方的//一般默认为0x30000100位置//boot_params 如果为0则表示bootloader 没有传参数if (mdesc->boot_params)tags = phys_to_virt(mdesc->boot_params);B.是通过标签ATAG来辨别的,uboot中有相应的标签字,将相应的uboot 参数放置到相应的全局变量中。
if (tags->hdr.tag == ATAG_CORE) {//已经被fixup函数修改,则将atag中的mem段置为noneif (meminfo.nr_banks != 0)squash_mem_tags(tags);//继续把atag的参数传递结束,通过参数的类型(比如ATAG_CMDLINE,ATAG_MEM诸如此类的参数)将bootargs参数全部分析完毕。
parse_tags(tags);{extern struct tagtable __tagtable_begin, __tagtable_end;struct tagtable *t;//我们的参数是放在__tagtable_begin到__tagtable_end区间内,各个类型的通过__tagtable的宏定义在编译的时候就将其定位在这个区间,我们的每一个参数只需要和每个宏比较,并调用其对用的parse函数。
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引导Linux内核及向内核传递参数的⽅式 ⼀直以来没有想过有什么好的办法通过寄存器向内核传递参数,直到今天读UBOOT的实现⽅式。
在UBOOT中,引导内核最常⽤的⽅法是bootm命令,bootm命令可以引导“UBOOT格式”的内核。
先花点时间了解⼀下什么是“UBOOT格式”的内核吧:⽤UBOOT⾃带的mkimage命令⽣成的内核称为"UBOOT"格式的内核。
以下⾯这条命令为例: mkimage -n "Kernel 2.4.18" -A arm -O linux -T kernel -C none -a30007fc0 -e 30008000 -d 4020.bin vmlinux-2.4.18.img 其中与内核引导最密切的是-e 30008000,也就是内核的⼊⼝地址。
其它参数可以参考帮助信息。
其它UBOOT格式的内核与原来相⽐,只是进⾏(可选)了压缩,并在前⾯加了⼀个0x40⼤⼩的头。
这个头⾥放了内核的位置(0x30007fc0)和⼊⼝地址(0x30008000)和其它信息。
bootm命令执⾏时,先对头部信息等进⾏校验,然后把头信息放到⼀个结构⾥⾯。
最后根据内核类型调⽤相应的启动函数。
对于Linux⽽⾔就是do_bootm_linux,在启动函数⾥⾯,有这么⼀个操作:theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);,这是最关键的⼀个操作,将内核的⼊⼝地址0x30008000赋给了theKernel,在启动函数的最后,使⽤theKernel (0, bd->bi_arch_number, bd->bi_boot_params);启动内核。
根据传参规范,三个变量分别⽤r0,r1,r2传给内核,这样就巧妙地利⽤了函数指针进⾏了参数传递,实在是精妙!上⾯讲完了内核的引导及传参,需要引起注意的就是在使⽤mkimage命令⽣成内核时,-e后⾯的地址要⽐-a后⾯的地址偏移0x40,原因很简单,就不在细说了。
标题:kernel 读取配置参数的方法一、介绍在操作系统中,kernel(内核)是操作系统的核心组成部分,负责管理系统资源、提供系统调用接口以及控制整个系统的运行。
在实际的应用中,有时候需要通过kernel来读取配置参数,以便对系统进行必要的配置、调整和优化。
本文将介绍一些常见的方法来实现kernel读取配置参数的过程。
二、通过初始化参数列表读取在Linux内核中,可以通过初始化参数列表(initrd)来传递参数给kernel,而kernel可以通过解析这些参数来读取相关的配置信息。
这种方法通常用于引导时的内核参数配置,比如开机启动时的参数配置、内存分配等。
通过修改initrd中的参数列表,可以实现kernel在启动时读取相关的配置信息。
三、通过/proc文件系统读取在Linux内核中,/proc文件系统是一个虚拟的文件系统,可以动态地显示系统的各种信息和状态。
而对于kernel来说,也可以通过/proc文件系统来读取一些配置参数。
在/proc/sys目录下,可以找到一些kernel参数的配置文件,通过读取这些文件可以获取相应的配置信息。
四、通过内核模块参数读取在Linux内核中,可以通过内核模块传递参数给kernel。
可以通过编写相应的内核模块,然后将参数传递给kernel,在初始化时读取这些参数。
这种方法通常用于特定模块的配置参数,比如网络设备驱动、磁盘驱动等。
通过编写对应的模块,并通过传递参数的方式,可以实现kernel在运行时读取相关的配置信息。
五、通过/sys文件系统读取在Linux内核中,/sys文件系统是用来管理内核中各种设备、驱动程序和参数的接口。
而对于kernel来说,也可以通过/sys文件系统来读取一些配置参数。
在/sys/module目录下,可以找到加载的内核模块的相关信息,包括参数配置。
通过读取这些信息,也可以获取kernel的相关配置参数。
六、总结通过以上介绍,我们可以了解到,在Linux内核中,有多种方法可以实现kernel读取配置参数的过程。
Android系统启动过程-uBoot+Kernel+Android摘要:本⽂是参考⼤量⽹上资源在结合⾃⼰查看源代码总结出来的,让⾃⼰同时也让⼤家加深对Android系统启动过程有⼀个更加深⼊的了解!再次强调,本⽂的⼤多数功劳应归功于那些原创者们,同时⼀些必要的参考链接我会⼀⼀附上。
注:由于本⼈采⽤Exynos4412开发板学习,所以本⽂⼤部分资料都是基于此处理器的简介:对于整个Android系统的启动总的来说分为三个阶段: BootLoader引导即uBoot.bin linux内核启动即zImage Android系统启动即ramdisk.img与system.img 以上四个⽂件都是经过⾃⼰编译后⽣成的且通过烧写测试,接下来开始说这三⼤部分的启动过程。
⽬录:⼀、BootLoader的启动 1.汇编部分 2.c部分 ⼆、Kernel的启动 1.zImage解压缩 2.kernel的汇编启动阶段 3.kernel的c启动阶段 三、Android的启动 1.init进程 2.init启动的各种服务 3.android启动图⽰第⼀部分:BootLoader的启动流程 uBoot的第⼀条指令从cpu/arm920t/start.S⽂件开始 1. 设置CPU进⼊SVC模式(系统管理模式),cpsr[4:0]=0xd3。
1 #include <common.h>2 #include <config.h>34/*5 *************************************************************************6 *7 * Jump vector table as in table 3.1 in [1]8 *9 *************************************************************************10*/111213 .globl _start14 _start: b start_code15 ldr pc, _undefined_instruction16 ldr pc, _software_interrupt17 ldr pc, _prefetch_abort18 ldr pc, _data_abort19 ldr pc, _not_used20 ldr pc, _irq21 ldr pc, _fiq2223 _undefined_instruction: .word undefined_instruction24 _software_interrupt: .word software_interrupt25 _prefetch_abort: .word prefetch_abort26 _data_abort: .word data_abort27 _not_used: .word not_used28 _irq: .word irq29 _fiq: .word fiq3031 .balignl 16,0xdeadbeef 接着进⼊Start_code中:设置CPU进⼊SVC模式。
Linux Kernel Cmdline的用法Linux kernel cmdline的用法主要涉及到其配置和传递方式。
在Linux系统中,cmdline是由bootloader(如uboot)传给kernel的,用于将需要传给kernel的参数做成一个tags链表放在RAM中,并将首地址传给kernel,kernel 解析tags来获取cmdline等信息。
具体来说,cmdline的配置可以通过几种方式实现:通过u-boot的bootargs进行配置。
这是最常用的方式之一。
直接在内核cmdline参数中进行配置。
这通常涉及到修改内核源码中的某些配置项。
例如,可以在make config里修改“General Setup”子菜单中的“Default kernel command string”选项,通过修改这个选项来修改include/linux/autoconf.h 文件中的CONFIG_CMDLINE宏。
另外,有时为了省去make menuconfig的时间,并且内核命令也是固定的,可以直接在内核源码的arch/arm/setup.c文件中修改default_command_line 变量,这个变量本来是初始化为CONFIG_CMDLINE的。
还有一种方法是将内核命令写入内核参数表中,然后通过start_kernel()->setup_arch()->parse_tags()的过程进行解析和使用。
值得注意的是,有时可能需要强制内核使用自配置的cmdline,而不是使用bootloader传递过来的cmdline。
这可以通过在内核配置中设置“Kernel command line type”为“Always use the default kernel command string”来实现。
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 函数。