新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 关于嵌入式设备上的Linux 系统开发

关于嵌入式设备上的Linux 系统开发

作者: 时间:2012-08-28 来源:网络 收藏

根据可用的资源和引导装载程序的功能,内核可以编译成 vmlinux、Image 或 zImage。vmlinux 和 zImage 之间的主要区别在于 vmlinux是实际的(未压缩的)可执行文件,而 zImage是或多或少包含相同信息的自解压压缩文件 D 只是压缩它以处理(通常是 Intel 强制的)640 KB 引导时间的限制。有关所有这些的权威性解释,请参阅 Magazine的文章“Kernel Configuration: dealing with the unexpected”(请参阅 参考资料)。

内核链接和装入

一旦为目标编译了内核后,通过使用引导装载程序(它已经被装入到目标的闪存中),内核就被装入到目标的内存(在 DRAM 中或者在闪存中)。通过使用串行、USB 或以太网端口,引导装载程序与主机通信以将内核传送到目标的闪存或 DRAM 中。在将内核完全装入目标后,引导装载程序将控制传递给装入内核的地址。

内核可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init 数据、bass 等等。这些对象文件都是由一个称为 链接器脚本的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将该可执行文件的各节装入到指定地址处。 vmlinux.lds是存在于 arch// 目录中的内核链接器脚本,它负责链接内核的各个节并将它们装入内存中特定偏移量处。典型的 vmlinux.lds 看起来象这样:

清单 2. 典型的 vmlinux.lds 文件

output_ARCH() /* includes architecture type */

ENTRY(stext) /* stext is the kernel entry point */

SECTIONS /* SECTIONS command describes the layout

of the output file */

{

. = TEXTADDR; /* TEXTADDR is LMA for the kernel */

.init : { /* Init code and data*/

_stext = .; /* First section is stext followed

by __init data section */

__init_begin = .;

*(.text.init)

__init_end = .;

}

.text : { /* Real text segment follows __init_data section */

_text = .;

*(.text)

_etext = .; /* End of text section*/

}

.data :{

_data=.; /* Data section comes after text section */

*(.data)

_edata=.;

} /* Data section ends here */

.bss : { /* BSS section follows symbol table section */

__bss_start = .;

*(.bss)

_end = . ; /* BSS section ends here */

}

}

LMA 是装入模块地址;它表示将要装入内核的目标虚拟内存中的地址。 TEXTADDR 是内核的虚拟起始地址,并且在 arch// 下的 Makefile 中指定它的值。这个地址必须与引导装载程序使用的地址相匹配。

一旦引导装载程序将内核复制到闪存或 DRAM 中,内核就被重新定位到 TEXTADDR — 它通常在 DRAM 中。然后,引导装载程序将控制转给这个地址,以便内核能开始执行。

参数传递和内核引导

stext 是内核入口点,这意味着在内核引导时将首先执行这一节下的代码。它通常用汇编语言编写,并且通常它在 arch// 内核目录下。这个代码设置内核页面目录、创建身份内核映射、标识体系结构和处理器以及执行分支 start_kernel (初始化系统的主例程)。

start_kernel 调用 setup_arch 作为执行的第一步,在其中完成特定于体系结构的设置。这包括初始化硬件寄存器、标识根和系统中可用的 DRAM 和闪存的数量、指定系统中可用页面的数目、文件系统大小等等。所有这些信息都以参数形式从引导装载程序传递到内核。

将参数从引导装载程序传递到内核有两种方法:parameter_structure 和标记列表。在这两种方法中,不赞成使用参数结构,因为它强加了限制:指定在内存中,每个参数必须位于 param_struct 中的特定偏移量处。最新的内核期望参数作为标记列表的格式来传递,并将参数转化为已标记格式。 param_struct 定义在 include/asm/setup.h 中。它的一些重要字段是:

清单 3. 样本参数结构

struct param_struct {

unsigned long page_size; /* 0: Size of the page */

unsigned long nr_pages; /* 4: Number of pages in the System */

unsigned long ramdisk /* 8: ramdisk size */

unsigned long rootdev; /* 16: number representing the root device */

unsigned long initrd_start; /* 64: starting address of initial ramdisk */

/* This can be either in flash/dram */

unsigned long initrd_size; /* 68: size of initial ramdisk */

}

请注意:这些数表示定义字段的参数结构中的偏移量。这意味着如果引导装载程序将参数结构放置在地址 0xc0000100,那么 rootdev 参数将放置在 0xc0000100 + 16,initrd_start 将放置在 0xc0000100 + 64 等等 D 否则,内核将在解释正确的参数时遇到困难。

正如上面提到的,因为从引导装载程序到内核的参数传递会有一些约束条件,所以大多数 2.4.x 系列内核期望参数以已标记的列表格式传递。在已标记的列表中,每个标记由标识被传递参数的 tag_header 以及其后的参数值组成。标记列表中标记的常规格式可以如下所示:

清单 4. 样本标记格式。内核通过 头来标识每个标记。

#define

struct {

u32 ;

u32 ;

};

/* Example tag for passing memory information */

#define ATAG_MEM 0x54410002 /* Magic number */

struct tag_mem32 {

u32 size; /* size of memory */

u32 start; /* physical start address of memory*/

linux操作系统文章专题:linux操作系统详解(linux不再难懂)


评论


相关推荐

技术专区

关闭