一 zImage 生成流程
第六步
第五步
第四步
第三步
第二步
第一步
1 vmlinux文件
vmlinux文件根据arch/arm/kernel/vmlinux.ld生成,vmlinux属于未压缩,带调试信息、符号表的最初的内核,该文件大小约为4.3M。
2 Image文件
将vmlinux中的调试信息、注释、符号表等内容去除后生成该文件,这是未经压缩的linux内核,该文件大小为3.2M。
文件
arch/arm/boot/Image 用gzip -9 压缩生成arch/arm/boot/,该文件大小为1.55M。
4 piggy.o
编译arch/arm/boot/compressed/piggy.S 生成arch/arm/boot/compressed/piggy.o, piggy.S将作为数据段包含进piggy.o。
5 /compressed/vmlinux
依据arch/arm/boot/compressed/vmlinux.lds 将arch/arm/boot/compressed/目录下的文件head.o 、piggy.o 、misc.o链接生成 arch/arm/boot/compressed/vmlinux,这个vmlinux是经过压缩且含有自解压代码的内核,文件大小约1.5M。
6 /compressed/zImgae
将arch/arm/boot/compressed/vmlinux去除调试信息、注释、符号表等内容,生成arch/arm/boot/zImage,文件大小约1.5M。
二 zImage文件生成过程中涉及到的几个地址
主要有以下几个地址:
1 ZTEXTADDR
解压代码运行的开始地址。属于物理地址,但这个地址不一定时RAM的地址,可以是支持读写寻址的flash。
2 ZRELADDR
内核启动在RAM中的地址。压缩的内核映像被解压到这个地址,然后执行。这个地址为物理地址。
3 TEXTADDR
内核启动的虚拟地址,与ZRELADDR相对应。一般内核启动的虚拟地址为RAM的第一个bank的虚拟地址加上0x8000。
这几个地址在lpc3141中是这样定义的
1 ZTEXTADDR
ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
ZBSSADDR := ALIGN(4)
endif
从编译之后所生成的arch/arm/compressed/vmlinux.lds中可以看到:
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0;
_text = .;
///////
///
即解压缩代码的入口点被定义为“. = 0”。
注:在arch/arm/boot/compressed/Makefile中有这样的描述
# We now have a PIC decompressor implementation. Decompressors running
# from RAM should not define ZTEXTADDR. Decompressors running directly
# from ROM or Flash must define ZTEXTADDR (preferably via the config)
# FIXME: Previous assignment to ztextaddr-y is lost here. See SHARK
ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
ZBSSADDR := ALIGN(4)
endif
意思是讲如果解压缩代码是在RAM中运行的话,那么就不需要设置ZTEXTADDR,如果是在ROM或Flash中运行的话,那么需要设置ZTEXTADDR。 这里为什么说要在flash启动时设定这个值,不是很清楚
2 ZRELADDR
在arch/arm/boot/Makefile中
ZRELADDR := $(zreladdr-y)
zreladdr-y 在arch/arm/mach-lpc313x/Makefile.boot中被定义为
zreladdr-y := 0x30008000
3 TEXTADDR
在arch/arm/kernel/vmlinux.lds.S中定义
. = PAGE_OFFSET + TEXT_OFFSET 即定义TEXTADDR=PAGE_OFFSET + TEXT_OFFSET,
LPC313x有如下定义
PAGE_OFFSET在arch/arm/include/asm/memory.h中定义为
#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)
CONFIG_PAGE_OFFSET在inculde/linux/autoconf.h中定义为
#define CONFIG_PAGE_OFFSET 0xC0000000
TEXT_OFFSET在arch/arm/makefile中定义为
TEXT_OFFSET := $(textofs-y)
textofs-y在
三 解压缩代码的执行流程
解压缩代码的运行流程,即当bootloader跳转到第一条内核指令后所代码的执行过程
假定zImage在内存中的初始地址为0x30008000(这个地址由bootloader决定,位置不固定)
1、初始状态
.text | 0x30008000开始,包含piggydata段(即压缩的内核段) |
. got | ? |
. data | ? |
.bss | ? |
.stack | 4K大小 |
2、head.S调用misc.c中的decompress_kernel刚解压完内核后
text | 0x30008000开始,包含piggydata段(即压缩的内核段) |
. got | ? |
. data | ? |
.bss | ? |
.stack | 4K大小 |
解压函数所需缓冲区 | 64K大小 |
解压后的内核代码 | 小于4M |
3、此时会将head.S中的部分代码重定位
.text | 0x30008000开始,包含piggydata段(即压缩的内核段) |
. got | ? |
. data | ? |
.bss | ? |
.stack | 4K大小 |
解压函数所需缓冲区 | 64K大小 |
解压后的内核代码 | linux内核文件放在哪 小于4M |
head.S中的部分重定位代码代码 | reloc_start至reloc_end |
4、跳转到重定位后的reloc_start处,由reloc_start至reloc_end的代码复制解压后的内核代码到0x30008000处,并调用call_kernel跳转到0x30008000处执行。
解压后的内核 | 0x30008000开始 |
四 几个其他的比较重要的地址
1 PARAMS_PHYS := $(params_phys-y)
内核参数地址,其中params_phys-y在arch/arm/mach-lpc313x/Makefile.boot定义为
params_phys-y := 0x30000100
在head.S中被赋值给r0
ldr r0, =params_phys
2 PHYS_OFFSET
RAM第一个bank的物理起始地址。
Physical start address of the first bank of RAM.
3 PAGE_OFFSET
RAM第一个bank的虚拟起始地址。
Virtual start address of the first bank of RAM. During the kernel boot phase, virtual address PAGE_OFFSET will be mapped to physical address PHYS_OFFSET, along with any other mappings you supply.This should be the same value as TASK_SIZE。
4 页表存放地址
在kernel/Document/arm/Booting中有这样的描述
The zImage may also be placed in system RAM (at any location) and called there. Note that the kernel uses 16K of RAM below the image to store page tables. The recommended placement is 32KiB into RAM.
即zImage下面用16K的空间来存放内核页表,但是推荐要把zImage放在32K的位置,这里
我认为是由于在0x100位置的地方还存放了内核启动参数。所以推荐预留足够的空间来存放内核页表。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论