微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 嵌入式 arm平台kernel启动第二阶段分析

嵌入式 arm平台kernel启动第二阶段分析

时间:11-09 来源:互联网 点击:

即物理地址,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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top