微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm linux 启动过程

arm linux 启动过程

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

[cpp]view plaincopyprint?

  1. /*
  2. *Lookupmachinearchitectureinthelinker-buildlistofarchitectures.
  3. *Notethatwecantusetheabsoluteaddressesforthe__arch_info
  4. *listssincewearentrunningwiththeMMUon(andtherefore,weare
  5. *notinthecorrectaddressspace).Wehavetocalculatetheoffset.
  6. *
  7. *r1=machinearchitecturenumber
  8. *Returns:
  9. *r3,r4,r6corrupted
  10. *r5=mach_infopointerinphysicaladdressspace
  11. */
  12. __lookup_machine_type:
  13. adrr3,3b
  14. ldmiar3,{r4,r5,r6}
  15. subr3,r3,r4@getoffsetbetweenvirt&phys
  16. addr5,r5,r3@convertvirtaddressesto
  17. addr6,r6,r3@physicaladdressspace
  18. 1:ldrr3,[r5,#MACHINFO_TYPE]@getmachinetype
  19. teqr3,r1@matchesloadernumber?
  20. beq2f@found
  21. addr5,r5,#SIZEOF_MACHINE_DESC@nextmachine_desc
  22. cmpr5,r6
  23. blo1b
  24. movr5,#0@unknownmachine
  25. 2:movpc,lr
  26. 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?

  1. .macropgtbl,rd
  2. ldr\rd,=(KERNEL_RAM_PADDR-0x4000)
  3. .endm

[cpp]view plaincopyprint?

  1. /*
  2. *Setuptheinitialpagetables.Weonlysetupthebarest
  3. *amountwhicharerequiredtogetthekernelrunning,which
  4. *generallymeansmappinginthekernelcode.
  5. *
  6. *r8=machinfo
  7. *r9=cpuid
  8. *r10=procinfo
  9. *
  10. *Returns:
  11. *r0,r3,r6,r7corrupted
  12. *r4=physicalpagetableaddress
  13. */
  14. __create_page_tables:
  15. /*r4=KERNEL_RAM_PADDR–0x4000=0x30004000
  16. *后面的C代码中的swapper_pg_dir变量,它的值也指向0x30004000
  17. *内存地址,不过它的值是虚拟内存地址,即0xc0004000
  18. */
  19. pgtblr4@pagetableaddress
  20. /*将从r4到KERNEL_RAP_PADDR的16K页表空间清空。*/
  21. movr0,r4
  22. movr3,#0
  23. addr6,r0,#0x4000
  24. 1:strr3,[r0],#4
  25. strr3,[r0],#4
  26. strr3,[r0],#4
  27. strr3,[r0],#4
  28. teqr0,r6
  29. bne1b
  30. /*还记得r10指向开发板相应的proc_info元素吗?这里它将的mm_mmuflags值读到r7中。
  31. *PROCINFO_MM_MMUFLAGS值为8,可对应上面列出来的__arm920_proc_info结构或你相应开发板结构的值来查看该mmu_flags值。
  32. *这里的flags就是用于设置目录项的flags。查看该mmu_flags的定义,发现它是要求一级页表是section。
  33. */
  34. ldrr7,[r10,#PROCINFO_MM_MMUFLAGS]@mm_mmuflags
  35. /*
  36. *CreateidentitymappingforfirstMBofkernelto
  37. *caterfortheMMUenable.Thisidentitymapping
  38. *willberemovedbypaging_init().Weuseourcurrentprogram
  39. *countertodeterminecorrespondingsectionbaseaddress.
  40. */
  41. /*r3=((pc>>20)<20)|r7,即取PC以1M向下对齐的地址。R6=pc>>20也即r6=0x300(pgd_idx),
  42. *即PC对所有1M内存空间,在页表中的下标。
  43. *R7值表明该目录项是section,即它映射的大小是1M。故刚好一个目录项就可以映射kernel上的1M空间。
  44. *这个暂时的va=pa映射只建立1M大小内存的,而不需要建立整个kernel镜像范围的映射。
  45. *因为这个va=pa的映射只有当前汇编语言才使用,一量跳进start_kernl后,这将不会用到了。而汇编代码在链接时,
  46. *已将它安排到代码段的最前面了。
  47. movr6,pc,lsr#20@startofkernelsection
  48. orrr3,r7,r6,lsl#20@flags+kernelbase
  49. /*将目录内空写到页表相应位置,即((uint32_t*)r4)[pgd_idx]=r3*/
  50. strr3,[r4,r6,lsl#2]@identitymapping
  51. /*上面代码段为[pc&(~0xfffff),(pc+0xfffff)&(~0xfffff)]的物理内存空间建立了va=pa的映射关系。*/
  52. /*下面为kernel镜像所占有空间,即KERNL_START到KERNEL_END建立内存映射,
  53. *映射关系为:va=pa–PHYS+PAGR_OFFSET。注意,这里的KENEL_START是kernel空间开始的虚拟地址。
  54. *这里的目录表项同样是section,即一个项映射1M的内存。
  55. */
  56. /*KERNEL_ST

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

网站地图

Top