ARM Linux 的启动过程
pe函数就是返回该对象指针。
这里涉及很多函数指针,它们都是在start_kernel函数里在各种阶段进行初始化的回函数。如map_io指向的tq2440_map_io就是在建立好内核页表后,再调用它来针对开发板的各种IO端口来建立相关的映射和页表。
至于__loopup_machine_type的代码就不作详细分析,请对比__lookup_processor_type来自行分析。代码如下:
[cpp]view plaincopy
- /*
- *Lookupmachinearchitectureinthelinker-buildlistofarchitectures.
- *Notethatwecantusetheabsoluteaddressesforthe__arch_info
- *listssincewearentrunningwiththeMMUon(andtherefore,weare
- *notinthecorrectaddressspace).Wehavetocalculatetheoffset.
- *
- *r1=machinearchitecturenumber
- *Returns:
- *r3,r4,r6corrupted
- *r5=mach_infopointerinphysicaladdressspace
- */
- __lookup_machine_type:
- adrr3,3b
- ldmiar3,{r4,r5,r6}
- subr3,r3,r4@getoffsetbetweenvirt&phys
- addr5,r5,r3@convertvirtaddressesto
- addr6,r6,r3@physicaladdressspace
- 1:ldrr3,[r5,#MACHINFO_TYPE]@getmachinetype
- teqr3,r1@matchesloadernumber?
- beq2f@found
- addr5,r5,#SIZEOF_MACHINE_DESC@nextmachine_desc
- cmpr5,r6
- blo1b
- movr5,#0@unknownmachine
- 2:movpc,lr
- ENDPROC(__lookup_machine_type)
[cpp]view plaincopy
- /*
- *Lookupmachinearchitectureinthelinker-buildlistofarchitectures.
- *Notethatwecantusetheabsoluteaddressesforthe__arch_info
- *listssincewearentrunningwiththeMMUon(andtherefore,weare
- *notinthecorrectaddressspace).Wehavetocalculatetheoffset.
- *
- *r1=machinearchitecturenumber
- *Returns:
- *r3,r4,r6corrupted
- *r5=mach_infopointerinphysicaladdressspace
- */
- __lookup_machine_type:
- adrr3,3b
- ldmiar3,{r4,r5,r6}
- subr3,r3,r4@getoffsetbetweenvirt&phys
- addr5,r5,r3@convertvirtaddressesto
- addr6,r6,r3@physicaladdressspace
- 1:ldrr3,[r5,#MACHINFO_TYPE]@getmachinetype
- teqr3,r1@matchesloadernumber?
- beq2f@found
- addr5,r5,#SIZEOF_MACHINE_DESC@nextmachine_desc
- cmpr5,r6
- blo1b
- movr5,#0@unknownmachine
- 2:movpc,lr
- ENDPROC(__lookup_machine_type)
5. 为kernel建立临时页表
前面提及到,kernel里面的所有符号在链接时,都使用了虚拟地址值。在完成基本的初始化后,kernel代码将跳到第一个C语言函数start_kernl来执行,在哪个时候,这些虚拟地址必须能够对它所存放在真正内存位置,否则运行将为出错。为此,CPU必须开启MMU,但在开启MMU前,必须为虚拟地址到物理地址的映射建立相应的面表。在开启MMU后,kernel指并不马上将PC值指向start_kernl,而是要做一些C语言运行期的设置,如堆栈,重定义等工作后才跳到start_kernel去执行。在此过程中,PC值还是物理地址,因此还需要为这段内存空间建立va = pa的内存映射关系。当然,本函数建立的所有页表都会在将来paging_init销毁再重建,这是临时过度性的映射关系和页表。
在介绍__create_table_pages前,先认识一个macro pgtbl,它将KERNL_RAM_PADDR – 0x4000的值赋给rd寄存器,从下面的使用中可以看它,该值是页表在物理内存的基础,也即页表放在kernel开始地址下的16K的地方。
[cpp]view plaincopy
- .macropgtbl,rd
- ldr\rd,=(KERNEL_RAM_PADDR-0x4000)
- .endm
[cpp]view plaincopy
- .macropgtbl,rd
- ldr\rd,=(KERNEL_RAM_PADDR-0x4000)
- .endm
[cpp]view plaincopy
- /*
- *Setuptheinitialpagetables.Weonlysetupthebarest
- *amountwhicharerequiredtogetthekernelrunning,which
- *generallymeansmappinginthekernelcode.
- *
- *r8=machinfo
- *r9=cpuid
- *r10=procinfo
- *
- *Returns:
- *r0,r3,r6,r7corrupted
- *r4=physicalpagetableaddress
- */
- __create_page_tables:
- /*r4=KERNEL_RAM_PADDR–0x4000=0x30004000
- *后面的C代码中的swapper_pg_dir变量,它的值也指向0x30004000
- *内存地址,不过它的值是虚拟内存地址,即0xc0004000
- */
- pgtblr4@pagetableaddress
- /*将从r4到KERNEL_RAP_PADDR的16K页表空间清空。*/
- movr0,r4
- movr3,#0
- addr6,r0,#0x4000
- 1:strr3,[r0],#4
- strr3,[r0],#4
- strr3,[r0],#4
- strr3,[r0],#4
- teqr0,r6
- bne1b
- /*还记得r10指向开发板相应的proc_info元素吗?这里它将的mm_mmuflags值读到r7中。
- *PROCINFO_MM_MMUFLAGS值为8,可对应上面列出来的__arm920_proc_info结构或你相应开发板结构的值来查看该mmu_flags值。
- *这里的flags就是用于设置目录项的flags。查看该mmu_flags的定义,发现它是要求一级页表是section。
- */
- ldrr7,[r10,#PROCINFO_MM_MMUFLAGS]
ARMLinux启动过 相关文章:
- arm linux 启动过程(11-09)
- ARM Linux启动过程学习(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)