嵌入式 arm平台kernel启动第二阶段分析
链表必须以ATAG_CORE开始,以ATAG_NONE结束。这里的ATAG_CORE,ATAG_NONE是各个参数的标记,本身是一个32位值,例如:ATAG_CORE=0x54410001。其它的参数标记还包括:ATAG_MEM32,ATAG_INITRD,ATAG_RAMDISK,ATAG_COMDLINE等。每个参数标记就代表一个参数结构体,由各个参数结构体构成了参数链表。参数结构体的定义如下:
structtag{
structtag_headerhdr;
union{
structtag_corecore;
structtag_mem32mem;
structtag_videotextvideotext;
structtag_ramdiskramdisk;
structtag_initrdinitrd;
structtag_serialnrserialnr;
structtag_revisionrevision;
structtag_videolfbvideolfb;
structtag_cmdlinecmdline;
structtag_acornacorn;
structtag_memclkmemclk;
}u;
};
参数结构体包括两个部分,一个是tag_header结构体,一个是u联合体。
tag_header结构体的定义如下:
structtag_header{
u32size;
u32tag;
};
其中size:表示整个tag结构体的大小(用字的个数来表示,而不是字节的个数),等于tag_header的大小加上u联合体的大小,例如,参数结构体ATAG_CORE的size=(sizeof(tag->tag_header)+sizeof(tag->u.core))>>2,一般通过函数tag_size(struct*tag_xxx)来获得每个参数结构体的size。其中tag:表示整个tag结构体的标记,如:ATAG_CORE等。
/*r8=machinfo
*Returns:
*r2eithervalidatagspointer,orzero
*/
__vet_atags:
tstr2,#0x3@aligned?r2指向该参数链表的起始位置,此处判断它是否字对齐
bne1f@如果没有对齐,跳到标号1处直接返回,并且把r2的值赋值为0,作为返回值
ldrr5,[r2,#0]@isfirsttagATAG_CORE?获取第一个tag结构的size
cmpr5,#ATAG_CORE_SIZE@判断该tag的长度是否合法
cmpner5,#ATAG_CORE_SIZE_EMPTY
bne1f@如果不合法,异常返回
ldrr5,[r2,#4]@获取第一个tag结构体的标记
ldrr6,=ATAG_CORE@取出标记ATAG_CORE的内容
cmpr5,r6@判断该标记是否等于ATAG_CORE
bne1f@如果不等,异常返回
movpc,lr@atagpointerisok,如果都相等,则正常返回
1:movr2,#0@异常返回值
movpc,lr@异常返回
ENDPROC(__vet_atags)
//
__vet_atags函数的具体解析结束(\arch\arm\kernel\head-common.S)
//
/*创建内核初始化页表*/
bl__create_page_tables
//
__create_page_tables函数的具体解析开始(\arch\arm\kernel\head.S)
//
/*
*r8=machinfo
*r9=cpuid
*r10=procinfo
*Returns:
*r4=physicalpagetableaddress
*/
/*在该文件的开头有如下宏定义*/
#defineKERNEL_RAM_PADDR(PHYS_OFFSET+TEXT_OFFSET)
.macropgtbl,rd
ldr\rd,=(KERNEL_RAM_PADDR-0x4000)
.endm
其中:PHYS_OFFSET在arch/arm/mach-s3c2410/include/mach/memory.h定义,为UL(0x30000000),而TEXT_OFFSET在arch/arm/Makefile中定义,为内核镜像在内存中到内存开始位置的偏移(字节),为$(textofs-y)textofs-y也在文件arch/arm/Makefile中定义,为textofs-y:=0x00008000,r4=30004000为临时页表的起始地址,首先即是初始化16K的页表,高12位虚拟地址为页表索引,每个页表索引占4个字节,所以为4K*4=16K,大页表,每一个页表项,映射1MB虚拟地址.
__create_page_tables:
/*为内核代码存储区域创建页表,首先将内核起始地址-0x4000到内核起始地址之间的16K存储器清0,将创建的页表存于此处*/
pgtblr4@r4中存放的为页表的基地址,最终该地址会写入cp15的寄存器c2,这个值必须是16K对齐的
movr0,r4@把页表的基地址存放到r0中
movr3,#0@把r3清0
addr6,r0,#0x4000@r6指向16K的末尾
1:strr3,[r0],#4@把16K的页表空间清0
strr3,[r0],#4
strr3,[r0],#4
strr3,[r0],#4
teqr0,r6
bne1b
/*从proc_info_list结构中获取字段__cpu_mm_mmu_flags,该字段包含了存储空间访问权限等,此处指令执行之后r7=0x00000c1e*/
ldrr7,[r10,#PROCINFO_MM_MMUFLAGS]@mm_mmuflags
/*为内核的第一MB创建一致的映射,以为打开MMU做准备,这个映射将会被paging_init()移除,这里使用程序计数器来获得相应的段的基地址*/
movr6,pc
movr6,r6,lsr#20@startofkernelsection
orrr3,r7,r6,lsl#20@flags+kernelbase
strr3,[r4,r6,lsl#2]@identitymapping
/*MMU是通过C2中基地址(高18位)与虚拟地址的高12位组合成物理地址,在转换表中查找地址条目。R4中存放的就是这个基地址0x30004000*/
addr0,r4,#(KERNEL_START&0xff000000)>>18@r0=0x30007000r0存放的是转换表的起始位置
strr3,[r0,#(KERNEL_START&0x00f00000)>>18]!@r3存放的是内核镜像代码段的起始地址
ldrr6,=(KERNEL_END-1)@获取内核的尾部虚拟地址存于r6中
addr0,r0,#4@第一个地址条目存放在0x3
嵌入式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)