基于ARM 的Linux 的启动分析报告——ARM+Linux的启动分析(2)

3、zImage 的启动过程
1. Linux 内核的一般启动过程:
1)对于ARM 系列处理器来说,zImage 的入口程序即为 arch/arm/boot/
compressed/head.S。它依次完成以下工作:开启 MMU 和 Cache,调用
decompress_kernel()解压内核,最后通过调用 call_kernel()进入非压缩内核
Image 的启动。
Linux 非压缩内核的入口位于文件/arch/arm/kernel/head-armv.S 中
的 stext 段。该段的基地址就是压缩内核解压后的跳转地址。如果系统中加载的
内核是非压缩的 Image,那么bootloader将内核从 Flash中拷贝到 RAM 后将
直接跳到该地址处,从而启动 Linux 内核。
2)执行镜像:解压後/非压缩镜像直接执行(linux/arch/arm/kernel/headarmv.
S:ENTRY(stext)-> __entry->__ret->__switch_data->__mmap_switched->)
3)该程序通过查找处理器内核类型和处理器类型调用相应的初始化函数,
再建立页表,最后跳转到 start_kernel()函数开始内核的初始化工作。
(linux/init/main.c:start_kernel())
2、zImage 的启动过程
1) 内核启动地址的确定
1、#/arch/arm/Makefile文件中,设置内核启动的虚拟地址
textaddr-y := 0xC0008000 这个是内核启动的虚拟地址
TEXTADDR := $(textaddr-y)
2、#/arch/arm/boot/Makefile文件中,设置内核启动的物理地址
ZRELADDR := $(zreladdr-y)
PARAMS_PHYS := $(params_phys-y)
3、 #/arch/arm/boot/compressed/Makefile文件中,
SEDFLAGS =
s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$
(ZBSSADDR)/
使得TEXT_START = ZTEXTADDR(从flash 中启动时),LOAD_ADDR =
ZRELADDR
其中TEXT_START是内核ram启动的偏移地址,这个地址是物理地址
ZTEXTADDR就是解压缩代码的ram偏移地址,
LOAD_ADDR就是zImage中解压缩代码的ram偏移地址,
ZRELADDR是内核ram启动的偏移地址,
zImage的入口点由# /arch/arm/boot/compressed/vmlinux.lds.in决定:
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = TEXT_START;
_text = .;
.text : {
_start = .;
*(.start)
*(.text)
……
}
2) 内核解压缩过程
内核压缩和解压缩代码都在目录#/arch/arm/boot/compressed,编译完成后
将产生vmlinux、head.o、misc.o、head-xscale.o、piggy.o这几个文件,其中
head.o:内核的头部文件,负责初始设置;
misc.o:主要负责内核的解压工作,它在head.o之后;
head-xscale.o:主要针对Xscale的初始化,将在链接时与head.o合并;
piggy.o:一个中间文件,其实是一个压缩的内核(kernel/vmlinux),只不过没
有和
初始化文件及解压文件链接而已;
vmlinux:没有(zImage是压缩过的内核)压缩过的内核,就是由piggy.o、
head.o、misc.o、head-xscale.o组成的。
3) 在BootLoader 完成系统的引导以后并将Linux 内核调入内存之后,
调用
bootLinux(),这个函数将跳转到kernel的起始位置。如果kernel没有压缩,
就可以启动了。
如果kernel压缩过,则要进行解压,在压缩过的kernel头部有解压程序。
压缩过的kernel入口第一个文件源码位置
arch/arm/boot/compressed/head.S。
它将调用函数decompress_kernel(),这个函数在arch/arm/boot/compressed/
misc.c 中,decompress_kernel()又调用
proc_decomp_setup(),arch_decomp_ setup()进行设置,然后使用在打印出信
息“Uncompressing Linux...”后,调用gunzip()。将内核放于指定的位置。
4) 以下分析#/arch/arm/boot/compressed/head.S 文件:
(1) 对于各种Arm CPU的DEBUG输出设定,通过定义宏来统一操作。
(2) 设置kernel开始和结束地址,保存architecture ID。
(3) 如果在ARM2以上的CPU中,用的是普通用户模式,则升到超级用户模式,
然后关中断。
(4) 分析LC0结构delta offset,判断是否需要重载内核地址(r0存入偏移量,
判断
r0是否为零)。
接下来要把内核镜像的相对地址转化为内存的物理地址,即重载内核地
址:
(5) 需要重载内核地址,将r0的偏移量加到BSS region和GOT table中。
(6) 清空bss堆栈空间r2-r3。
(7) 建立C程序运行需要的缓存,并赋于64K的栈空间。
(8) 这时r2是缓存的结束地址,r4是kernel的最后执行地址,r5是kernel境
象文件的开始地址。检查是否地址有冲突。将r5等于r2,使decompress后的
kernel地址就在64K的栈之后。

你可能感兴趣的:(基于ARM 的Linux 的启动分析报告——ARM+Linux的启动分析(2))