arch/arm/kernel/head-armv.S学习
时间:2006-09-27 来源:augustusqing
Arch/arm/kernel/head-armv.S:
这个是真正内核,也就是vmlinux的首文件,也就是上面文件call r4后转到这里。先看链接脚本vmlinux-armv.lds.in
入口点stext,VMA是TEXTADDR,节的顺序是.init,.text,kstrtab,.data,.bss,先注意关注.init节,由很多的带init后缀的节构成,.text.init,.proc.info,.arch.info,.taglist,.data.init,.setup.init,initcall.init,最开始是.text.init节,每个初始节前后都定义了变量;
先根据具体体系条件编译设置进入内核前的环境。
1, 进入SVC,屏蔽中断
2, 查看处理器类型,为了得到处理器ID和页表的flags
3, 查看体系结构信息
4, 建立页表
5, __xscale_setup:跳到处理器的初始化函数,其函数地址从第2步中得到的。初始完后,跳到__ret
6, __ret:打开MMU,跳到__mmap_switched
7, __mmap_switched:在寄存器中保存必要信息,跳到init/main.c中的start_kernle,进入C语言境地。
详解:
2,找出用那种类型的处理器,比如是arm7,arm9,xscale,通过结构proc_info_list实现,结构定义在include/asm-arm/procinfo.h中,我用的是xscale的pxa255,在arch/arm/mm/proc-xscale.S中1072行,其中有__xscale_setup就是xscale的初始化函数,这些信息都被链接进.proc.info节,并且在链接脚本中由__proc_info_begin和__proc_info_end表明地址,就可以把它理解为一个数组了。返回后,如果找到了,寄存器:
r8 = page table flags 页表的flags
r9 = processor ID
r10 = pointer to processor structure(成功时),r10 = 0 (失败时) 就是上面结构指针,或者首址
3,查看体系结构信息,跟2差不多,这里的体系意思是开发板,每块板子的物理内存,io内存布局等信息不一样的。由machie_desc结构定义,结构的定义,以及设置结构变量的一些宏都在include/asm-arm/mach/arch.h中,由MACHINE_START宏的定义可以知道,每定义一个desc结构,都会被链接进 .arch.info节里面。这里我板子的定义在arch/arm/mach-pxa/cerf.c中,通过那些宏定义。细节:先在r1中保存了体系id,从结构中对比查询,查到后,就可以获得内存分布信息了,返回状态是:
* r5 = physical start address of RAM
* r6 = physical address of IO
* r7 = byte offset into page tables for IO
4, 建立页表,我们的内核起始物理地址是0xA000,8000,虚拟地址是0xC000,8000。要建立内核起始处4MB空间的映射,采用了一级映射方式,即段式(section)映射(非x386的段)方式,每段映射范围为1MB空间。于是我们需要建立4个表项,实现:
虚拟地址0xC000,0000~0xC030,0000映射到物理地址0xA000,0000~0xA030,0000
注意此时寄存器中已经储存的信息,r5-r10,函数执行完后r4中是页表的基址
清空原来页表项,比如head.S中建立的
再这样理解:设置ram开始处1MB的1:1映射,这样打开MMU就能平稳过渡。
再设置TEXTADDR内核内核虚拟地址开始的映射,共4MB映射。
再round down到ram首址映射,这里就不明白了,可能是为了健壮考虑。
5,r10中保存着 处理器结构信息首址,加上12就得到处理器初始函数地址,可以运行,属于.text.init节
此函数好理解,最后把要放入控制寄存器中去的控制相关信息设置好在r0中,比如打开MMU等
6就把r0置入控制寄存器,打开MMU等,再转入__switch_data中的__mmap_switched,此时寄存器信息为,__switch_data中保留着一些变量信息,这些变量都是全局的,进入c境地后还要使用
r0 = processor control register
r1 = machine ID
r9 = processor ID
8, 代码好理解,清空BSS等,保存处理器id(r9),机器类型(r1),控制寄存器值(r0,r2),调用全局符号start_kernle,进入C境地,整个内核第一启动阶段结束。
最后:感谢南开大学嵌入式系统与信息安全实验室学术论坛。
由于由以上论坛上的一篇很好的帖子,这个文件不到一天就能勉强了解,今天总算没那么郁闷了