arm linux 启动过程
时间:11-09
来源:互联网
点击:
[cpp]view plaincopyprint?
- /*
- *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 plaincopyprint?
- .macropgtbl,rd
- ldr\rd,=(KERNEL_RAM_PADDR-0x4000)
- .endm
[cpp]view plaincopyprint?
- /*
- *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]@mm_mmuflags
- /*
- *CreateidentitymappingforfirstMBofkernelto
- *caterfortheMMUenable.Thisidentitymapping
- *willberemovedbypaging_init().Weuseourcurrentprogram
- *countertodeterminecorrespondingsectionbaseaddress.
- */
- /*r3=((pc>>20)<20)|r7,即取PC以1M向下对齐的地址。R6=pc>>20也即r6=0x300(pgd_idx),
- *即PC对所有1M内存空间,在页表中的下标。
- *R7值表明该目录项是section,即它映射的大小是1M。故刚好一个目录项就可以映射kernel上的1M空间。
- *这个暂时的va=pa映射只建立1M大小内存的,而不需要建立整个kernel镜像范围的映射。
- *因为这个va=pa的映射只有当前汇编语言才使用,一量跳进start_kernl后,这将不会用到了。而汇编代码在链接时,
- *已将它安排到代码段的最前面了。
- movr6,pc,lsr#20@startofkernelsection
- orrr3,r7,r6,lsl#20@flags+kernelbase
- /*将目录内空写到页表相应位置,即((uint32_t*)r4)[pgd_idx]=r3*/
- strr3,[r4,r6,lsl#2]@identitymapping
- /*上面代码段为[pc&(~0xfffff),(pc+0xfffff)&(~0xfffff)]的物理内存空间建立了va=pa的映射关系。*/
- /*下面为kernel镜像所占有空间,即KERNL_START到KERNEL_END建立内存映射,
- *映射关系为:va=pa–PHYS+PAGR_OFFSET。注意,这里的KENEL_START是kernel空间开始的虚拟地址。
- *这里的目录表项同样是section,即一个项映射1M的内存。
- */
- /*KERNEL_ST
armlinux启动过 相关文章:
- ARM Linux 的启动过程(11-09)
- ARM Linux启动过程学习(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)