ARM+Linux的启动分析(zImage)
- 格式:pdf
- 大小:220.78 KB
- 文档页数:24
Linux 内核启动分析1. 内核启动地址1.1. 名词解释ZTEXTADDR解压代码运行的开始地址。
没有物理地址和虚拟地址之分,因为此时MMU处于关闭状态。
这个地址不一定时RAM的地址,可以是支持读写寻址的flash等存储中介。
Start address of decompressor. here's no point in talking about virtual or physical addresses here, since the MMU will be off at the time when you call the decompressor code. Y ou normally call the kernel at this address to start it booting. This doesn't have to be located in RAM, it can be in flash or other read-only or read-write addressable medium.ZRELADDR内核启动在RAM中的地址。
压缩的内核映像被解压到这个地址,然后执行。
This is the address where the decompressed kernel will be written, and eventually executed. The following constraint must be valid:__virt_to_phys(TEXTADDR) == ZRELADDRThe initial part of the kernel is carefully coded to be position independent.TEXTADDR内核启动的虚拟地址,与ZRELADDR相对应。
一般内核启动的虚拟地址为RAM的第一个bank地址加上0x8000。
arm版本linux系统的启动流程ARM架构是一种常见的处理器架构,被广泛应用于嵌入式设备和移动设备中。
在ARM版本的Linux系统中,启动流程是非常重要的,它决定了系统如何从开机到正常运行。
本文将详细介绍ARM版本Linux系统的启动流程。
一、引导加载程序(Bootloader)引导加载程序是系统启动的第一阶段,它位于系统的固化存储器中,比如ROM或Flash。
在ARM版本的Linux系统中,常用的引导加载程序有U-Boot和GRUB等。
引导加载程序的主要功能是加载内核镜像到内存中,并将控制权转交给内核。
二、内核初始化引导加载程序将内核镜像加载到内存后,控制权被转交给内核。
内核初始化是系统启动的第二阶段,它主要完成以下几个步骤:1. 设置异常向量表:ARM架构中,异常是指硬件产生的中断或故障,比如系统调用、中断请求等。
内核需要设置异常向量表,以便正确处理异常。
2. 初始化处理器:内核对处理器进行初始化,包括设置页表、启用缓存、初始化中断控制器等。
3. 启动第一个进程:内核创建第一个用户进程(一般是init进程),并将控制权转交给它。
init进程是系统中所有其他进程的父进程,负责系统的初始化工作。
三、设备树(Device Tree)设备树是ARM版本Linux系统中的一种机制,用于描述硬件设备的相关信息。
在内核初始化过程中,内核会解析设备树,并建立设备树对象,以便后续的设备驱动程序使用。
设备树描述了硬件设备的类型、地址、中断等信息,以及设备之间的连接关系。
它使得内核能够在运行时自动识别和配置硬件设备,大大提高了系统的可移植性和灵活性。
四、启动初始化(Init)启动初始化是系统启动的第三阶段,它是用户空间的第一个进程(init进程)接管系统控制权后的操作。
启动初始化主要完成以下几个任务:1. 挂载根文件系统:启动初始化会挂载根文件系统,使得用户可以访问文件系统中的文件和目录。
2. 加载系统服务:启动初始化会加载并启动系统服务,比如网络服务、日志服务、时间同步服务等。
优选(VR虚拟现实)ARMLinux启动过程分析ARM Linux启动过程分析赵楠本章学习目标:●了解Linux结构及平台属性●了解bootloader的相关知识●熟悉并掌握启动过程摘要:从嵌入式系统到超级服务站,嵌入式Linux 的可移植性使得我们可以在各种电子产品上看到它的身影。
Linux 是一个完整通用的Unix 类分布式操作系统,它的结构紧凑、功能强、效率高、可移植性好且在Internet 上可自由取用。
对于不同体系结构的处理器来说Linux的启动过程也有所不同。
本文以S3C2410 ARM处理器为例,详细分析了系统上电后bootloader的执行流程及ARM Linux的启动过程。
关键词:ARM Linux bootloader 启动过程Abstract: from the embedded system to super service station, embedded Linux portability allows us to various electronic products in the form of seeing it. Linux is a complete general Unix class distributed operating system, it's structure compact, the function is strong, high efficiency, good portability and in the Internet can be free to take. For different system structure of the processor is the start of the Linux process is also different. Based on the ARM processor S3C2410 as an example, the paper analyses system after the execution flow of electric bootloader and ARM Linux start-up process.Keywords: ARM Linux bootloader start-up process1. 引言Linux 最初是由瑞典赫尔辛基大学的学生Linus Torvalds在1991 年开发出来的,之后在GNU的支持下,Linux 获得了巨大的发展。
ARM Linux启动过程分析(1)摘要:嵌入式 Linux 的可移植性使得我们可以在各种电子产品上看到它的身影。
对于不同体系结构的处理器来说Linux的启动过程也有所不同。
本文以S3C2410 ARM处理器为例,详细分析了系统上电后 bootloader的执行流程及 ARM Linux的启动过程。
关键词:ARM Linux bootloader 启动过程Abstract:We can see embedded Linux in kinds of electronic productsb ecause of its portability. Linux’s start-up procedure for different processors is also different. This paper provides the analysis ofbootloader execution process and Linux kernel start-up procedure - taking the S3C2410 ARM processor as example. Keywords: ARM Linux bootloader start-up procedure 1. 引言 Linux 最初是由瑞典赫尔辛基大学的学生 Linus Torvalds在1991 年开发出来的,之后在 GNU的支持下,Linux 获得了巨大的发展。
虽然 Linux 在桌面 PC 机上的普及程度远不及微软的Windows 操作系统,但它的发展速度之快、用户数量的日益增多,也是微软所不能轻视的。
而近些年来 Linux 在嵌入式领域的迅猛发展,更是给 Linux 注入了新的活力。
一个嵌入式 Linux 系统从软件角度看可以分为四个部分:引导加载程序(bootloader), Linux 内核,文件系统,应用程序。
其中bootloader是系统启动或复位以后执行的第一段代码,它主要用来初始化处理器及外设,然后调用 Linux 内核。
ARM的启动分析详解及应用ARM是一款广泛应用于嵌入式系统和移动设备的处理器架构。
在ARM的启动过程中,主要涉及到硬件初始化、加载引导程序和启动操作系统等步骤。
下面将对ARM的启动过程进行详细分析,并讨论其在实际应用中的应用。
硬件初始化:在ARM的启动过程中,首先需要对硬件进行初始化。
这包括对中央处理器(CPU)、存储器、外设等进行初始化操作。
例如,初始化CPU的控制和配置寄存器,设置存储器的访问模式和权限等。
硬件初始化的目的是确保系统处于一个稳定的状态,为后续的操作打下基础。
加载引导程序:引导程序是ARM启动的关键部分,它负责初始化系统环境和加载操作系统的镜像文件。
引导程序通常位于启动设备的引导扇区或者特定的存储器地址中。
在ARM中,引导程序可以是U-Boot、Das U-Boot或是其他自定义的引导程序。
加载引导程序的方式可以是通过串口、以太网或者其他类似的介质。
引导程序的主要功能是初始化设备和外设,配置内存和中断控制器等。
它会加载操作系统的镜像文件到内存中,并跳转到操作系统的起始地址,从而将控制权交给操作系统。
启动操作系统:在引导程序加载并跳转到操作系统的起始地址后,操作系统开始运行。
操作系统负责管理硬件资源、提供系统服务和支持应用程序的运行。
常见的ARM操作系统有Linux、Android等。
ARM的启动分析步骤在实际应用中具有重要的意义。
首先,通过硬件初始化可以确保系统处于一个稳定的状态,避免因为硬件问题导致系统崩溃或运行不正常。
其次,加载引导程序可以实现自定义的系统启动流程和初始化操作,满足特定应用需求。
最后,启动操作系统可以为用户提供高效、稳定的系统环境,并支持各种应用程序的运行。
在实际的应用中,ARM的启动分析步骤具有广泛的应用。
例如,嵌入式系统可以通过自定义的引导程序来实现特定的启动流程和初始化操作,以满足设备的需求。
移动设备则可以通过加载引导程序和启动操作系统来提供稳定的系统环境和良好的用户体验。
ARM Linux启动过程分析(转载)摘要:嵌入式Linux 的可移植性使得我们可以在各种电子产品上看到它的身影。
对于不同体系结构的处理器来说Linux的启动过程也有所不同。
本文以S3C2410 ARM处理器为例,详细分析了系统上电后bootloader的执行流程及ARM Linux的启动过程。
关键词:ARM Linux bootloader 启动过程Abstract:We can see embedded Linux in kinds of electronic products because of its portability. Linux’s start-up procedure for different processors is also different. This paper provides the analysis ofbootloader execution process and Linux kernel start-up procedure - taking the S3C2410 ARM processor as example.Keywords: ARM Linux bootloader start-up procedure1. 引言Linux 最初是由瑞典赫尔辛基大学的学生Linus Torvalds在1991 年开发出来的,之后在GNU的支持下,Linux 获得了巨大的发展。
虽然Linux 在桌面PC 机上的普及程度远不及微软的Windows 操作系统,但它的发展速度之快、用户数量的日益增多,也是微软所不能轻视的。
而近些年来Linux 在嵌入式领域的迅猛发展,更是给Linux 注入了新的活力。
一个嵌入式Linux 系统从软件角度看可以分为四个部分[1]:引导加载程序(bootloader),Linux 内核,文件系统,应用程序。
其中bootloader是系统启动或复位以后执行的第一段代码,它主要用来初始化处理器及外设,然后调用Linux 内核。
[原创]Linux arm 启动c语言部分详解第一讲(from Start kernel)written by leeming作为我们实验室的一个学术交流,我顺着fp的linux arm启动汇编部分继续下去。
我们可以看到其实linux汇编部分的启动大量的工作是对zimage的解压,重定位等操作,如果是image(也就是zimage解压重定位结束后)来说,其实主要就做了以下这么几件事情:1.建立启动时的一级页表,2.打开mmu,3.保存机器号等参数。
因此对于整个处理器系统来说还需要做大量的工作,对于移植内核来说,只有真正了解了这部分你才会明白在arch/arm/mach-sep4020这个目录中的文件为什么需要这样写。
进入正题:1.进入start_kernel,详解setup_arch(处理器的移植,页表建立都在这里实现的)asmlinkage void __init start_kernel(void){ char * command_line; extern struct kernel_param __start___param[], __stop___param[];/** Interrupts are still disabled. Do necessary setups, then* enable them*/ lock_kernel(); //这里是和高端内存相关的操作,arm中不涉及 page_address_init(); //这个只是printk的等级,但是为什么在控制台不显示,待看 //这时候控制台还没有初始化,因此所有的信息都是在log_buf里 printk(KERN_NOTICE); printk(linux_banner); setup_arch(&command_line); …… ……到这里就碰到了我们详解start kernel的第一道坎,setup_arch(&command_line);别看就一句话,其实这个函数本身是非常庞大的,下面我们来具体看完整的setup_arch函数。
Linux内核的启动过程在 bootloader将 Linux 内核映像拷贝到 RAM 以后,可以通过下例代码启动 Linux 内核:call_linux(0, machine_type,kernel_params_base)。
其中,machine_tpye 是 bootloader检测出来的处理器类型,kernel_params_base 是启动参数在 RAM 的地址。
通过这种方式将Linux 启动需要的参数从 bootloader传递到内核。
Linux 内核有两种映像:一种是非压缩内核,叫 Image,另一种是它的压缩版本,叫zImage。
根据内核映像的不同,Linux 内核的启动在开始阶段也有所不同。
zImage 是 Image经过压缩形成的,所以它的大小比 Image 小。
但为了能使用 zImage,必须在它的开头加上解压缩的代码,将zImage 解压缩之后才能执行,因此它的执行速度比 Image 要慢。
但考虑到嵌入式系统的存储空容量一般比较小,采用 zImage 可以占用较少的存储空间,因此牺牲一点性能上的代价也是值得的。
所以一般的嵌入式系统均采用压缩内核的方式。
对于 ARM 系列处理器来说,zImage 的入口程序即为arch/arm/boot/compressed/head.S。
它依次完成以下工作:开启 MMU 和 Cache,调用 decompress_kernel()解压内核,最后通过调用call_kernel()进入非压缩内核 Image 的启动。
下面将具体分析在此之后 Linux 内核的启动过程。
(1)Linux内核入口Linux 非压缩内核的入口位于文件/arch/arm/kernel/head-armv.S 中的 stext 段。
该段的基地址就是压缩内核解压后的跳转地址。
如果系统中加载的内核是非压缩的Image,那么bootloader将内核从 Flash中拷贝到 RAM 后将直接跳到该地址处,从而启动 Linux 内核。
uImage与zImage的区别内核编译(make)之后会生成两个文件,一个Image,一个zImage,其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为4M,而zImage不到2M。
那么uImage又是什么的?它是uboot专用的映像文件,它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别。
如何生成uImage文件?首先在uboot的/tools目录下寻找mkimage文件,把其copy 到系统/usr/local/bin目录下,这样就完成制作工具。
然后在内核目录下运行make uImage,如果成功,便可以在arch/arm/boot/目录下发现uImage文件,其大小比zImage多64个字节。
其实就是一个自动跟手动的区别,有了uImage头部的描述,u-boot就知道对应Image的信息,如果没有头部则需要自己手动去搞那些参数。
U-boot的U是“通用”的意思。
zImage是ARM Linux常用的一种压缩映像文件,uImage是U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的“头”,说明这个映像文件的类型、加载位置、生成时间、大小等信息。
换句话说,如果直接从uImage的0x40位置开始执行,zImage和uImage没有任何区别。
另外,Linux2.4内核不支持uImage,Linux2.6内核加入了很多对嵌入式系统的支持,但是uImage的生成也需要设置,这个以后我会介绍。
几种linux内核文件的区别:1、vmlinux 编译出来的最原始的内核文件,未压缩。
2、zImage 是vmlinux经过gzip压缩后的文件。
3、bzImage bz表示“big zImage”,不是用bzip2压缩的。
两者的不同之处在于,zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。
基于ARM的Linux的启动分析报告摘要:本文主要分析基于ARM的Linux-2.2.26内核启动过程。
将首先从/arch/arm/Makefile着手,介绍三种不同的启动方案,再剖析典型的压缩内核zImage启动方案的代码结构,最后将详细分析这种方案的启动过程,直到调用start_kernel()为止。
1、Linux内核的启动方案:由/arch/arm/Makefile的代码可以看出,主要有三种启动方案,分别是: echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'echo ' bootpImage - Combined zImage and initial RAM disk'echo ' (supply initrd image via make variable INITRD=<path>)'Linux内核有两种映像:一种是非压缩内核,叫 Image,另一种是它的压缩版本,叫zImage。
根据内核映像的不同,Linux内核的启动在开始阶段也有所不同。
zImage是Image经过压缩形成的,所以它的大小比 Image小。
但为了能使用 zImage,必须在它的开头加上解压缩的代码,将 zImage解压缩之后才能执行,因此它的执行速度比Image要慢。
但考虑到嵌入式系统的存储空容量一般比较小,采用zImage可以占用较少的存储空间,因此牺牲一点性能上的代价也是值得的。
所以一般的嵌入式系统均采用压缩内核的方式(另外bootpImage是编译包含zImage和initrd的映像,可以通过make变量INITRD=<path>提供initrd映像)。
2、基于zImage的启动方案。
1、zImage的生成过程1、编译链接vmlinux2、生成vmlinux.lds链接脚本3、链接生成zImage2、zImage的代码结构在内核编译完成后会在arch/arm/boot/下生成zImage。
#arch/arm/boot/Makefile:$(obj)/zImage:$(obj)/compressed/vmlinux FORCE$(call if_changed,objcopy)@echo ' Kernel: $@ is ready'由此可见,zImage的是elf格式的,由内核顶层目录下的arch/arm/boot /compressed/vmlinux二进制化得到的:#arch/armboot/compressed/Makefile:$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \ $(addprefix $(obj)/, $(OBJS)) FORCE$(call if_changed,ld)@:$(obj)/piggy.gz: $(obj)/../Image FORCE$(call if_changed,gzip)$(obj)/piggy.o: $(obj)/piggy.gz FORCE总结一下zImage的组成,它是由一个压缩后的内核piggy.o,连接上一段初始化及解压功能的代码(head.o misc.o)组成的。
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/head-armv.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组成的。
压缩过的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的栈之后。
(9) 调用文件misc.c的函数decompress_kernel(),解压内核于缓存结束的地方(r2地址之后)。
此时各寄存器值有如下变化:r0为解压后kernel的大小r4为kernel执行时的地址r5为解压后kernel的起始地址r6为CPU类型值(processor ID)r7为系统类型值(architecture ID)(10) 将reloc_start代码拷贝之kernel之后(r5+r0之后),首先清除缓存,而后执行reloc_start。
(11) reloc_start将r5开始的kernel重载于r4地址处。
(12) 清除cache内容,关闭cache,将r7中architecture ID赋于r1,执行r4开始的kernel代码。
5) 我们在内核启动的开始都会看到这样的输出Uncompressing Linux...done, booting the kernel.这也是由decompress_kernel函数内部输出的,它调用了putc()输出字符串,putc是在#/include/asm-arm/arch-pxa/uncompress.h中实现的。
执行完解压过程,再返回到#/arch/arm/boot/compressed/head.S中,启动内核:call_kernel: bl cache_clean_flushbl cache_offmov r0, #0mov r1, r7 @ restore architecture numbermov pc, r4 @ call kernel6) 执行zImage镜像,到start_kernel( )整个arm linux内核的启动可分为三个阶段:第一阶段主要是进行cpu和体系结构的检查、cpu本身的初始化以及页表的建立等;第一阶段的初始化是从内核入口(ENTRY(stext))开始到start_kernel前结束。