Bootloader与内核的交互
Bootloader与内核的交互
原创
©著作权归作者所有:来自51CTO博客作者bjyulq的原创作品,请联系作者获取转载授权,否则将追究法律责任
Bootloader与内核的交互是单向的,Bootloader将各类参数传给内核。由于它们不能同时运行,传递办法只有一个:Bootloader将参数放在某个约定的地方之后,再启动内核,内核启动后从这个地方获得参数。
除了约定好参数存放的地址外,还要规定参数的结构。Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。标记,就是一种数据结构;标记列表,就是挨着存放的多个标记。标记列表以标记ATAG_CORE 开始,以标记ATAG_NONE 结束。标记的数据结构为tag,它由一个tag_header结构和一个联合(union)组成。tag_header结构表示标记的类型及长度,比如是表示内存还是表示命令行参数等。对于不同类型的标记使用不同的联合(union),比如表示内存时使用tag_mem32,表示命令行时使用tag_cmdline。数据结构tag和tag_header定义在Linux内核源码的arch/arm/include/asm/setup.h头文件中:
struct tag_header {
u32 size;
u32 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;
/*
* Acorn specific
*/
struct tag_acorn acorn;
/*
* DC21285 specific
*/
struct tag_memclk memclk;
} u;
};
下面以设置内存标记、命令行标记为例说明参数的传递:
(1)设置标记 ATAG_CORE。
标记列表以标记 ATAG_CORE开始,假设Bootloader与内核约定的参数存放地址为0x30000100,则可以以如下代码设置标记 ATAG_CORE:
params = (struct tag *) 0x30000100;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesiz = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
其中,tag_next定义如下,它指向当前标记的末尾:
#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
(2)设置内存标记。
假设开发板使用的内存起始地址为0x3000,0000,大小为0x0400,0000,则内存标记可以如下设置:
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = 0x30000000;
params->u.mem.size = 0x4000000;
params = tag_next (params);
(3)设置命令行标记。
命令行就是一个字符串,它被用来控制内核的一些行为。比如“root=/dev/mtdblock2 init=/linuxrc console=ttySAC0”表示根文件系统在MTD2分区上,系统启动后执行的第一个程序为/linuxrc,控制台为ttySAC0,即第一个串口。
命令行可以在Bootloader中通过命令设置好,然后如下构造标记传给内核:
char *p = "root=/dev/mtdblock2 init=/linuxrc console=ttySAC0";
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
(4)设置标记ATAG_NONE。
标记列表以标记ATAG_NONE结束,如下设置:
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
对于ARM架构的CPU,都是通过lib_arm/bootm.c中的do_bootm_linux函数来启动内核。这个函数中,设置标记列表,最后通过“theKernel (0, bd->bi_arch_number, bd->bi_boot_params)”调用内核。其中,theKernel指向内核存放的地址(对于ARM架构的CPU,通常是0x30008000),bd->bi_arch_number就是前面board_init函数设置的机器类型ID,而bd->bi_boot_params就是标记列表的开始地址。
命令行标记、内存标记由U-Boot中的setup_memory_tags、setup_commandline_tag函数实现,它们都是在lib_arm/bootm.c中定义。一般而言,设置这两个标记就可以了,在配置文件include/configs/smdk2410.h中增加如下两个配置项即可:
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_CMDLINE_TAG 1
注:
对于 linux 2.4版本,使用struct param_struct传递内核参数,见linux源码中arch/arm/kernel/compat.c。2.6版本目前也支持这种格式。
/*
* Usage:
* - do not go blindly adding fields, add them at the end
* - when adding fields, don't rely on the address until
* a patch from me has been released
* - unused fields should be zero (for future expansion)
* - this structure is relatively short-lived - only
* guaranteed to contain useful data in setup_arch()
*
* This is the old deprecated way to pass parameters to the kernel
*/
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 8
unsigned 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];
};
上一篇:在u-boot中添加命令
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
使用python的原始模块与网站交互数据 代码块 网络测试
-
读出nand flash中的内核、bootloader、文件系统
把开发板上nand flash中的bootloadr、内核、文件系统读取出来的方法
嵌入式 内核 kernel C程序 nand flash -
BootLoader和内核image的关系
昨晚听舍友说起编译linux内核这个事情,作为计算机专业毕业的人,对这个东西完全不了解,太郁闷了。经过多方了解,总
嵌入式系统 加载 ios 串口 目标机