设置内核的启动参数
应该说,在将内核映像和根文件系统映像拷贝到 RAM 空间中后,就可以准备启动 Linux
内核了。但是在调用内核之前,应该作一步准备工作,即:设置 Linux 内核的启动参数。
Linux 2.4.x 以后的内核都期望以标记列表(tagged list)的形式来传递启动参数。启动参
数标记列表以标记 ATAG_CORE 开始,以标记 ATAG_NONE 结束。每个标记由标识被传递参
数的 tag_header 结构以及随后的参数值数据结构来组成。数据结构 tag 和 tag_header
定义在 Linux 内核源码的include/asm/setup.h 头文件中:
/* The list ends with an ATAG_NONE node. */
#define ATAG_NONE 0x00000000
struct tag_header {
u32 size; /* 注意,这里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;
};
在嵌入式 Linux 系统中,通常需要由 Boot Loader 设置的常见启动参数有:ATAG_CORE、
ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等。比如,设置 ATAG_CORE 的代
码如下:
params = (struct tag *)BOOT_PARAMS;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size(tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next(params);
其中,BOOT_PARAMS 表示内核启动参数在内存中的起始基地址,指针 params 是一个 str
uct tag 类型的指针。宏 tag_next() 将以指向当前标记的指针为参数,计算紧临当前标
记的下一个标记的起始地址。注意,内核的根文件系统所在的设备ID就是在这里设置的。
下面是设置内存映射情况的示例代码:
for(i = 0; i < NUM_MEM_AREAS; i++) {
if(memory_map[i].used) {
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size(tag_mem32);
params->u.mem.start = memory_map[i].start;
params->u.mem.size = memory_map[i].size;
params = tag_next(params);
}
}
可以看出,在 memory_map[]数组中,每一个有效的内存段都对应一个 ATAG_MEM 参数标
记。
Linux 内核在启动时可以以命令行参数的形式来接收信息,利用这一点我们可以向内核提
供那些内核不能自己检测的硬件参数信息,或者重载(override)内核自己检测到的信息。
比如,我们用这样一个命令行参数字符串"console=ttyS0,115200n8"来通知内核以 ttyS0
作为控制台,且串口采用 "115200bps、无奇偶校验、8位数据位"这样的设置。下面是一
段设置调用内核命令行参数字符串的示例代码:
char *p;
/* eat leading white space */
for(p = commandline; *p == ' '; p++)
;
/* skip non-existent command lines so the kernel will still
* use its default command line.
*/
if(*p == '/0')
return;
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);
请注意在上述代码中,设置 tag_header 的大小时,必须包括字符串的终止符'/0',此外
还要将字节数向上圆整4个字节,因为 tag_header 结构中的size 成员表示的是字数。
下面是设置 ATAG_INITRD 的示例代码,它告诉内核在 RAM 中的什么地方可以找到 initr
d 映象(压缩格式)以及它的大小:
params->hdr.tag = ATAG_INITRD2;
params->hdr.size = tag_size(tag_initrd);
params->u.initrd.start = RAMDISK_RAM_BASE;
params->u.initrd.size = INITRD_LEN;
params = tag_next(params);
下面是设置 ATAG_RAMDISK 的示例代码,它告诉内核解压后的 Ramdisk 有多大(单位是K
B):
params->hdr.tag = ATAG_RAMDISK;
params->hdr.size = tag_size(tag_ramdisk);
params->u.ramdisk.start = 0;
params->u.ramdisk.size = RAMDISK_SIZE; /* 请注意,单位是KB */
params->u.ramdisk.flags = 1; /* automatically load ramdisk */
params = tag_next(params);
最后,设置 ATAG_NONE 标记,结束整个启动参数列表:
static void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
设置内核的启动参数
最新推荐文章于 2021-05-05 01:03:50 发布