ImageVerifierCode 换一换
格式:DOCX , 页数:22 ,大小:114.62KB ,
资源ID:10349058      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/10349058.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(基于ARM的Linux的启动分析.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

基于ARM的Linux的启动分析.docx

1、基于ARM的Linux的启动分析 基于ARM 的Linux 的启动分析 说明: 本文主要的分析基于ARM的linux2.6.17内核启动过程分析。 1、Linux 内核的启动方案: 由arch/arm/Makefile的代码: define archhelp echo * zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage) echo Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image) echo * xipImage - XIP kernel image, if

2、 configured (arch/$(ARCH)/boot/xipImage) echo bootpImage - Combined zImage and initial RAM disk echo (supply initrd image via make variable INITRD=) echo install - Install uncompressed kernel echo zinstall - Install compressed kernel echo Install using (your) /bin/installkernel or echo (distribution

3、) /sbin/installkernel or echo install to $(INSTALL_PATH) and run lilo endef 可以看出,主要有三种启动方案,分别是: 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 in

4、itrd image via make variable INITRD=)。Linux内核有两种映像:一种是非压缩内核,叫 Image,另一种是它的压缩版本,叫zImage。根据内核映像的不同,Linux内核的启动在开始阶段也有所不同。zImage是Image经过压缩形成的,所以它的大小比 Image小。但为了能使用zImage,必须在它的开头加上解压缩的代码,将 zImage解压缩之后才能执行,因此它的执行速度比Image要慢。但考虑到嵌入式系统的存储空容量一般比较小,采用zImage可以占用较少的存储空间,因此牺牲一点性能上的代价也是值得的。所以一般的嵌入式系统均采用压缩内核的方式(另外b

5、ootpImage 是编译包含zImage和initrd的映像,可以通过make变量INITRD=提供initrd映像)2.典型启动方案的代码结构:(1).Image启动方案的代码结构: #arch/arm/boot/Makefile: $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) echo Kernel: $ is ready 由此可见,Image由vmlinux 二进制化得到的。 Image的是由kernel/vmlinux构成的。(2).zImage启动方案的代码结构:在内核编译完成后会在arch/arm/boot/下生成z

6、Image。#arch/arm/boot/Makefile:$(obj)/zImage: $(obj)/compressed/vmlinux FORCE$(call if_changed,objcopy)echo Kernel: $ is ready由此可见,zImage由内核顶层目录下的arch/arm/boot /compressed/vmlinux二进制化得到的:#arch/armboot/compressed/Makefile:$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o $(addprefix $(o

7、bj)/, $(OBJS) FORCE$(call if_changed,ld):$(obj)/piggy.gz: $(obj)/./Image FORCE$(call if_changed,gzip)$(obj)/piggy.o: $(obj)/piggy.gz FORCEzImage 的组成,它是由一个压缩后的内核piggy.o,连接上一段初始化及解压功能的代码(head.o misc.o)组成的。 (3)BootpImage启动方案的代码结构: #arch/arm/boot/Makefile: $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE

8、$(Q)$(MAKE) $(build)=$(obj)/bootp $ $(obj)/bootpImage: $(obj)/bootp/bootp FORCE $(call if_changed,objcopy) echo Kernel: $ is ready 由此可知bootpImage是由 zImage 与initrd经过二进制化得到的,所以他包含了zImage initrd。 压缩内核zImage启动方案的分析 通常从系统加电到执行到linux kenel这部分的任务是由boot loader来完成。关于这部分内容在这里不不多分析了这里主要分析zImage部分的启动过程。 1. Linu

9、x 内核的一般启动过程: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 后将直接跳

10、到该地址处,从而启动 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文件中,设置内核启动的虚拟地址tex

11、taddr-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 = Z

12、TEXTADDR(从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

13、)*(.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是压缩过的

14、内核)压缩过的内核,就是由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

15、 中,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结

16、构delta offset,判断是否需要重载内核地址(r0存入偏移量,判断r0是否为零)。接下来要把内核镜像的相对地址转化为内存的物理地址,即重载内核地址:(5) 需要重载内核地址,将r0的偏移量加到BSS region和GOT table中。(6) 清空bss堆栈空间r2r3。(7) 建立C程序运行需要的缓存,并赋于64K的栈空间。(8) 这时r2是缓存的结束地址,r4是kernel的最后执行地址,r5是kernel境象文件的开始地址。检查是否地址有冲突。将r5等于r2,使decompress后的kernel地址就在64K的栈之后。(9) 调用文件misc.c的函数decompress_ke

17、rnel(),解压内核于缓存结束的地方(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

18、) 我们在内核启动的开始都会看到这样的输出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

19、numbermov pc, r4 call kernel6) 执行zImage 镜像,到start_kernel( )整个arm linux内核的启动可分为三个阶段:第一阶段主要是进行cpu和体系结构的检查、cpu本身的初始化以及页表的建立等;第一阶段的初始化是从内核入口(ENTRY(stext))开始到start_kernel前结束。这一阶段的代码在/arch/arm/kernel/head.S中。/arch/arm/kernel/head.S用汇编代码完成,是内核最先执行的一个文件。这一段汇编代码的主要作用,是检查cpuid,architecture number,初始化页表、cpu、bb

20、s等操作,并跳到start_kernel函数。它在执行前,处理器的状态应满足: r 0 - should be 0 r1 - unique architecture number MMU - off I-cache - on or off D-cache off流程图 代码详细注释#/arch/arm/kernel/head.S/* swapper_pg_dir is the virtual address of the initial page table.* We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we

21、* must make sure that KERNEL_RAM_VADDR is correctly set. Currently,we *expect the least significant 16 bits to be 0x8000, but we couldprobably relax this *restriction to KERNEL_RAM_VADDR = PAGE_OFFSET +0x4000.*/#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000#error KERNEL_RAM_VADDR must start at 0xXXXX8000

22、#endif.globl swapper_pg_dir.equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000.macro pgtbl, rdldr rd, =(KERNEL_RAM_PADDR - 0x4000).endm/* Since the page table is closely related to the kernel startaddress, we* can convert the page table base address to the base address of thesection* containing both.*/.m

23、acro krnladr, rd, pgtable, rambasebic rd, pgtable, #0x000ff000.endm/*/* Kernel startup entry point.* -* This is normally called from the decompressor code. Therequirements* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,* r1 = machine nr, r2 = atags pointer.* See linux/arch/arm/tools/mac

24、h-types for the complete list ofmachine* numbers for r1.*/.section .text.head, ax.type stext, %functionENTRY(stext) /内核入口点msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE/程序状态,禁止FIQ、IRQ,设定Supervisor模式。0b11010011mrc p15, 0, r9, c0, c0 get processor idbl _lookup_processor_type r5=procinfo r9=cupid /跳转到判断

25、/cpu类型,查找运行的cpu的id值和此linux编译支持的id值是否有相等movs r10, r5 invalid processor (r5=0)?beq _error_p yes, error pbl _lookup_machine_type r5=machinfo/跳转到判断体系类型,看r1寄存器的architecture number值是否支持。movs r8, r5 invalid machine (r5=0)?beq _error_a yes, error abl _vet_atagsbl _create_page_tables /创建核心页表/* The following

26、calls CPU specific code in a position independent* manner. See arch/arm/mm/proc-*.S for details. r10 = base of* xxx_proc_info structure selected by _lookup_machine_type* above. On return, the CPU will be ready for the MMU to be* turned on, and r0 will hold the CPU control register value.*/ldr r13, _

27、switch_data address to jump to after mmu has been enabledadr lr, _enable_mmu return (PIC) address /lr=0xc0028054add pc, r10, #PROCINFO_INITFUNC initialise processor /r10:pointer to processorstructure#/arch/arm/kernel/head-common.S*/#define ATAG_CORE 0x54410001#define ATAG_CORE_SIZE (2*4 + 3*4) 2).ty

28、pe _switch_data, %object_switch_data:.long _mmap_switched.long _data_loc r4.long _data_start r5.long _bss_start r6.long _end r7.long processor_id r4.long _machine_arch_type r5.long _atags_pointer r6.long cr_alignment r7.long init_thread_union + THREAD_START_SP sp/* The following fragment of code is

29、executed with the MMU on in MMUmode,* and uses absolute addresses; this is not position independent.* r0 = cp#15 control register* r1 = machine ID* r2 = atags pointer* r9 = processor ID*/.type _mmap_switched, %function_mmap_switched:/把sp指针指向init_task_union+8192(include/linux/sched.h)处,即第/一个进程的task_s

30、truct和系统堆栈的地址;清空BSS段;保存processorID/和machine type到全局变量processor_id和_machine_arch_type,这些值/以后要用到;r0为A置位的control register 值,r2为A清空的/control register 值,即对齐检查(Alignment fault checking)位,并保/存到cr_alignment,和cr_no_alignment(在文件entry-armv.S中)。最/后跳转到start_kernel(init/main.c)adr r3, _switch_data + 4ldmia r3!, r4, r5, r6, r7 r2 = compat/r20xc0000000cmp r4, r5 Copy data segment if needed /r40xc00c04e0;_bss_start1: cmpne r5,

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1