arm linux的启动部分源代码简略分析

上传人:第*** 文档编号:32682455 上传时间:2018-02-12 格式:DOC 页数:21 大小:166KB
返回 下载 相关 举报
arm linux的启动部分源代码简略分析_第1页
第1页 / 共21页
arm linux的启动部分源代码简略分析_第2页
第2页 / 共21页
arm linux的启动部分源代码简略分析_第3页
第3页 / 共21页
arm linux的启动部分源代码简略分析_第4页
第4页 / 共21页
arm linux的启动部分源代码简略分析_第5页
第5页 / 共21页
点击查看更多>>
资源描述

《arm linux的启动部分源代码简略分析》由会员分享,可在线阅读,更多相关《arm linux的启动部分源代码简略分析(21页珍藏版)》请在金锄头文库上搜索。

1、ARM linux 的启动部分源代码简略分析 ARM linux 的启动部分源代码简略分析 以友善之臂的 mini2440 开发板为平台,以较新的内核 linux-2.6.32.7 版本为例,仅作说明之用。当内核映像被加载到 RAM 之后,Bootloader 的控制权被释放。内核映像并不是可直接运行的目标代码,而是一个压缩过的 zImage(小内核) 。但是,也并非是 zImage 映像中的一切均被压缩了,映像中包含未被压缩的部分,这部分中包含解压缩程序,解压缩程序会解压缩映像中被压缩的部分。zImage 使用 gzip 压缩的,它不仅仅是一个压缩文件,而且在这个文件的开头部分内嵌有 gzi

2、p 解压缩代码。当 zImage 被调用时它从arch/arm/boot/compressed/head.S 的 start 汇编例程开始执行。这个例程进行一些基本的硬件设置,并调用 arch/arm/boot/compressed/misc.c 中的 decompress_kernel()解压缩内核。arch/arm/kernel/head.S 文件是内核真正的启动入口点,一般是由解压缩内核的程序来调用的。首先先看下对于运行这个文件的要求:MMU = off; D-cache = off; I-cache = 无所谓,开也可以,关也可以; r0 = 0;r1 = 机器号;r2 = atags

3、 指针。这段代码是位置无关的,所以,如果以地址 0xC0008000 来链接内核,那么就可以直接用_pa(0xc0008000)地址来调用这里的代码。其实,在这个(Linux 内核中总共有多达几十个的以 head.S 命名的文件)head.S 文件中的一项重要工作就是设置内核的临时页表,不然 mmu 开起来也玩不转,但是内核怎么知道如何映射内存呢?linux 的内核将映射到虚地址 0xCxxx xxxx 处,但他怎么知道在 4GB 的地址空间中有哪一片 ram 是可用的,从而可以映射过去呢? 因为不同的系统有不通的内存映像,所以,LINUX 约定,要调用内核代码,一定要满足上面的调用要求,以为

4、最初的内核代码提供一些最重要的关于机器的信息。内核代码开始的时候,R1 存放的是系统目标平台的代号,对于一些常见的,标准的平台,内核已经提供了支持,只要在编译的时候选中就行了,例如对 X86 平台,内核是从物理地址 1M 开始映射的。好了好了,看下面的代码。arch/arm/kernel/head.SENTRY(stext)是这个文件的入口点。最初的几行是这样的:setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 ensure svc mode and irqs disabled/ 设置为 SVC 模式,关闭中断和快速中断 / 此处设定系统的工作状态为 S

5、VC,arm 有 7 种状态每种状态/ 都有自己的堆栈,SVC 为管理模式,具有完全的权限,可以执行任意指令/ 访问任意地址的内存/ setmode 是一个宏,其定义为:/ .macro setmode, mode, reg/ msr cpsr_c, #mode/ .endm mrc p15, 0, r9, c0, c0 get processor idbl _lookup_processor_type r5=procinfo r9=cpuidmovs r10, r5 invalid processor (r5=0)?beq _error_p yes, error p这几行是查询处理器的类型的

6、,我们知道 arm 系列有很多型号,arm7、 arm9、 arm11、Cortex 核等等类型,这么多型号要如何区分呢?其实,在 arm 的 15号协处理器(其实 ARM 暂时也就这么一个协处理器)中有一个只读寄存器,存放与处理器相关信息。_lookup_processor_type 是 arch/arm/kernel/head-common.S 文件中定义的一个例程,这个head-common.S 用 include 命令被包含在 head.S 文件中。其定义为:_lookup_processor_type:adr r3, 3fldmia r3, r5 - r7add r3, r3, #8

7、sub r3, r3, r7 get offset between virt&physadd r5, r5, r3 convert virt addresses toadd r6, r6, r3 physical address space1: ldmia r5, r3, r4 value, maskand r4, r4, r9 mask wanted bitsteq r3, r4beq 2fadd r5, r5, #PROC_INFO_SZ sizeof(proc_info_list)cmp r5, r6blo 1bmov r5, #0 unknown processor2: mov pc,

8、 lrENDPROC(_lookup_processor_type)这个例程接受处理器 ID(保存在寄存器 r9 中)为参数,查找链接器建立的支持的处理器表。此时此刻还不能使用_proc_info 表的绝对地址,因为这时候 MMU 还没有开启,所以此时运行的程序没有在正确的地址空间中。所以不得不计算偏移量。若没有找到 processor ID 对应的处理器,则在 r5 寄存器中返回返回 0,否则返回一个 proc_info_list 结构体的指针(在物理地址空间) 。proc_info_list 结构体在文件中定义:struct proc_info_list unsigned int cpu_

9、val;unsigned int cpu_mask;unsigned long _cpu_mm_mmu_flags; /* used by head.S */unsigned long _cpu_io_mmu_flags; /* used by head.S */unsigned long _cpu_flush; /* used by head.S */const char *arch_name;const char *elf_name;unsigned int elf_hwcap; const char *cpu_name;struct processor *proc;struct cpu_

10、tlb_fns *tlb;struct cpu_user_fns *user;struct cpu_cache_fns *cache;第一项是 CPU id,将与协处理器中读出的 id 作比较,其余的字段也都是与处理器相关的信息,到下面初始化的过程中自然会用到。另外,这个例程加载符地址的代码也是挺值得我辈学习的:adr r3, 3f加载一个符号的地址,这个符号在加载语句前面(下面)定义,forward 嘛,这个符号为3,离这条语句最近的那个。在那个符号为 3 的位置我们看到这样的代码:.align 23: .long _proc_info_begin.long _proc_info_end4:

11、 .long .long _arch_info_begin.long _arch_info_end搜索这两个符号的值,在文件 arch/arm/kernel/vmlinux.lds.S 中:_proc_info_begin = .;*(.proc.info.init)_proc_info_end = .;这两个符号分别是一种初始化的段的结束开始地址和结束地址。为了了解由 struct proc_info_list 结构体组成的段的实际构成,我们还是得要了解一下在系统中到底都有哪些变量是声明了要被放到这个段的。用关键字.proc.info.init 来搜,全部都是arch/arm/mm/proc

12、-*.S 文件,这些都是特定于处理器的汇编语言文件,对于我们的 mini2440, 自然是要看 proc-arm920.S 文件的,在其中可以看到这些内容:.section .proc.info.init, #alloc, #execinstr.type _arm920_proc_info,#object_arm920_proc_info:.long 0x41009200.long 0xff00fff0.long PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE | P

13、MD_SECT_AP_READ.long PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE | PMD_SECT_AP_READb _arm920_setup .long cpu_arch_name.long cpu_elf_name.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB.long cpu_arm920_name.long arm920_processor_functions.long v4wbi_tlb_fns.long v4wb_user_fns#ifndef CONFIG_CPU_DCACHE_WRIT

14、ETHROUGH.long arm920_cache_fns#else.long v4wt_cache_fns#endif.size _arm920_proc_info, . - _arm920_proc_info看到这儿我们再回国头去看_lookup_processor_type 的代码:ldmia r3, r5 - r7 add r3, r3, #8sub r3, r3, r7尽管符号 3 处只有两个有效值,但它加载了三个数,而第三个数,我们看到是这样定义的:.long ._lookup_processor_type 中,给 r3 加上 8,也就是让 r3 指向“.” 的地址,然后用 r3

15、 减 r7 来获取虚拟地址与物理地址的差,这样看来, “.”就应该是虚拟空间(编译地址)里那个数据的地址。之后的代码获得_proc_info_begin 和_arch_info_end 这两个符号在物理空间中的地址:add r5, r5, r3 convert virt addresses toadd r6, r6, r3然后便是在那个段中逐个的检查 struct proc_info_list 结构体,以找到与我们的 CPU 相匹配的:1: ldmia r5, r3, r4 value, maskand r4, r4, r9 mask wanted bitsteq r3, r4beq 2fadd r5, r5, #PROC_INFO_SZ sizeof(proc_info_list)cmp r5, r6blo 1bmov r5, #0 unknown processor2: mov pc, lr_lookup_processor_type 例程会返回在文件 arch/arm/mm/proc-arm9

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 中学教育 > 职业教育

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号