嵌入式 arm平台kernel启动第二阶段分析
即物理地址,0x30008000)。因此,下面有些代码,需要使用地址无关技术。
__HEAD/*该宏定义了下面的代码位于".head.text"段内*/
.typestext,%function/*声明stext为函数*/
ENTRY(stext)/*第二阶段的入口地址*/
setmodePSR_F_BIT|PSR_I_BIT|SVC_MODE,r9@ensuresvcmodeandirqsdisabled进入超级权限模式,关中断
/*从协处理器CP15,C0读取CPUID,然后在__proc_info_begin开始的段中进行查找,如果找到,则返回对应处理器相关结构体在物理地址空间的首地址到r5,最后保存在r10中*/
mrcp15,0,r9,c0,c0@getprocessorid取出cpuid
bl__lookup_processor_type@r5=procinfor9=cpuid
//
__lookup_processor_type函数的具体解析开始(\arch\arm\kernel\head-common.S)
//
在讲解该程序段之前先来看一些相关知识,内核所支持的每一种CPU类型都由结构体proc_info_list来描述。
该结构体在文件arch/arm/include/asm/procinfo.h中定义:
structproc_info_list{
unsignedintcpu_val;
unsignedintcpu_mask;
unsignedlong__cpu_mm_mmu_flags;/*usedbyhead.S*/
unsignedlong__cpu_io_mmu_flags;/*usedbyhead.S*/
unsignedlong__cpu_flush;/*usedbyhead.S*/
constchar*arch_name;
constchar*elf_name;
unsignedintelf_hwcap;
constchar*cpu_name;
structprocessor*proc;
structcpu_tlb_fns*tlb;
structcpu_user_fns*user;
structcpu_cache_fns*cache;
};
对于arm920来说,其对应结构体在文件linux/arch/arm/mm/proc-arm920.S中初始化。
.section".proc.info.init",#alloc,#execinstr/*定义了一个段,下面的结构体存放在该段中*/
.type__arm920_proc_info,#object/*声明一个结构体对象*/
__arm920_proc_info:/*为该结构体赋值*/
.long0x41009200
.long0xff00fff0
.longPMD_TYPE_SECT|\
PMD_SECT_BUFFERABLE|\
PMD_SECT_CACHEABLE|\
PMD_BIT4|\
PMD_SECT_AP_WRITE|\
PMD_SECT_AP_READ
.longPMD_TYPE_SECT|\
PMD_BIT4|\
PMD_SECT_AP_WRITE|\
PMD_SECT_AP_READ
b__arm920_setup
…………………………………
.section".proc.info.init"表明了该结构在编译后存放的位置。在链接文件arch/arm/kernel/vmlinux.lds中:
SECTIONS
{
#ifdefCONFIG_XIP_KERNEL
.=XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
.=PAGE_OFFSET+TEXT_OFFSET;
#endif
.text.head:{
_stext=.;
_sinittext=.;
*(.text.head)
}
.init:{/*Initcodeanddata*/
INIT_TEXT
_einittext=.;
__proc_info_begin=.;
*(.proc.info.init)
__proc_info_end=.;
__arch_info_begin=.;
*(.arch.info.init)
__arch_info_end=.;
__tagtable_begin=.;
*(.taglist.init)
__tagtable_end=.;
………………………………
}
所有CPU类型对应的被初始化的proc_info_list结构体都放在__proc_info_begin和__proc_info_end之间。
/*
*r9=cpuid
*Returns:
*r5=proc_infopointerinphysicaladdressspace
*r9=cpuid(preserved)
*/
__lookup_processor_type:
adrr3,3f@r3存储的是标号3的物理地址(由于没有启用mmu,所以当前肯定是物理地址)
ldmiar3,{r5-r7}@R5=__proc_info_begin,r6=__proc_info_end,r7=标号4处的虚拟地址,即4:.long.处的地址
addr3,r3,#8@得到4处的物理地址,刚好是跳过两条指令
subr3,r3,r7@getoffsetbetweenvirt&phys得到虚拟地址和物理地址之间的offset
/*利用offset,将r5和r6中保存的虚拟地址转变为物理地址*/
addr5,r5,r3@convertvirtaddressesto
addr6,r6,r3@physicaladdressspace
1:ldmiar5,{r3,r4}@value,maskr3=cpu_val,r4=cpu_mask
andr4,r4,r9@maskwantedbits;r9中存放的是先前读出的processorID,此处屏蔽不需要的位
teqr3,r4@查看代码和CPU硬件是否匹配(比如想在arm920t上运行为cortex-a8编译的内核?不让)
beq2f@如果相等则跳转到标号2处,执行返回指令
addr5,r5,#PROC_INFO_SZ@sizeof(proc_info_list结构的长度,在这等于48)如果没找到,跳到下一个proc_info_list处
cmpr5,r6@判断是不是到了该段的结尾
blo1b@如果没有,继续跳到标号1处,查找下一个
movr5,#0@unknownprocessor,如果到了结尾,没找到匹配的,就把0赋值给r5,然后返回
2:movpc,lr@找到后返回,r5指向找到的结构体
ENDPROC(__lookup_processor_type)
.align2
3:.long__proc_info_begin
.long__proc_info_end
4:.long.@“.”表示当前这行代码编译连接后的虚拟地址
.long__arch_info_begin
.long__ar
嵌入式arm平台kernel启 相关文章:
- 嵌入式 arm平台kernel启动第一阶段汇编head.s分析(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)